事务集应该作为一个整体进行操作,而不是单个语句的执行,一个逻辑操作单元。
要么所有的事物都被提交,否则就发生事务回滚
那些操作发生数据提交:
- 增删改一旦执行,就会提交
- 关闭链接,也会自动
1 2 3 4 5 6
| 第一步:事务是自动提交的我们 手动关闭自动提交 conn.setAutoCommit(false); 第二步:如果没有异常就提交事务 conn.commit(); 第三步:如果抛出异常 我们我们就让他回滚 conn.rollback();
|
在以下这个表格中,AA与BB进行相互转账,为保证操作的可靠性,我们需要通过事务保障操作的可行性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.Properties;
public class TransferAccount { public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException { Properties properties=new Properties(); properties.load(new FileReader("src\\Information.properties")); String jdbc= properties.getProperty("jdbcJar"); String url= properties.getProperty("url"); String password= properties.getProperty("password"); String user= properties.getProperty("user"); Class.forName(jdbc); Connection connection= DriverManager.getConnection(url,user,password); String sql1="update user_table set balance=balance-100 where user=(?) "; String sql2="update user_table set balance=balance+100 where user=(?) "; PreparedStatement preparedStatement1= connection.prepareStatement(sql1); PreparedStatement preparedStatement2= connection.prepareStatement(sql2); preparedStatement1.setString(1,"AA"); preparedStatement2.setString(1,"BB"); preparedStatement1.executeUpdate(); System.out.println(10/0); preparedStatement2.executeUpdate(); preparedStatement1.close(); preparedStatement2.close(); connection.close(); } }
|
我们可以发现一笔钱无缘无故的消失了,但是当我们使用事务进行处理时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.Properties;
public class TransferAccount { public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException { Properties properties=new Properties(); properties.load(new FileReader("src\\Information.properties")); String jdbc= properties.getProperty("jdbcJar"); String url= properties.getProperty("url"); String password= properties.getProperty("password"); String user= properties.getProperty("user"); Class.forName(jdbc); Connection connection= DriverManager.getConnection(url,user,password); connection.setAutoCommit(false); String sql1="update user_table set balance=balance-100 where user=(?) "; String sql2="update user_table set balance=balance+100 where user=(?) "; PreparedStatement preparedStatement1= connection.prepareStatement(sql1); PreparedStatement preparedStatement2= connection.prepareStatement(sql2); preparedStatement1.setString(1,"AA"); preparedStatement2.setString(1,"BB"); try {
preparedStatement1.executeUpdate(); preparedStatement2.executeUpdate();}catch (ArithmeticException arithmeticException){ System.out.println("交易发生异常,事务进行回滚"); connection.rollback(); } connection.commit(); preparedStatement1.close(); preparedStatement2.close(); connection.close(); } }
|
我们可以看出数据交易正常进行
事务的属性
ACID:
- 原子性:事务不可分割,要么都发生,要么都不发生。
- 一致性:必须使数据库从一个一致性状态变换到另外一个一致性状态,比如金钱的总数
- 隔离性:事务不可以被其他事务干扰,内部操作必须是不被其他事务影响
- 持久性:数据一旦提交,数据中的改变是永久性的,其他操作均无法对其产生影响
数据库的并发问题
- 脏读:1与2两个事务,1读取了2已经更改但是还没有提交的字段,但是随后2发生了回滚,1读取的内容就变的无根据
- 不可重复读:1读取一个字段,2对其进行了更改,后来1再次重新读取时,值不相同
- 幻读:1对表中的全部行进行了同一操作,2又插入了一行,但是新插入的行并没有更改,和幻觉一样,也包含两次读取表格的数据不一致