概述
在开发中,我们对数据库的多个表或对一个表的多条数据执行更新操作的时候,要保证多个更新操作要么同时成功、要么都不成功。这就涉及到多个更新操作的事务管理问题了。
例如:银行的转账问题,A用户向B用户转账100元,假设A用户和B用户的钱都存储在Account表中,那么A向B转账就涉及同时更新Account表中的A用户的钱和B用户的钱,不然的话,A的钱少了,而B却没有收到钱,这是不允许出现的事件。
update account set money = money -100 where name = 'A';
update account set money = money + 100 where name = 'B';
事务
为什么上面的sql语句不能够实现“要么都成功、要么都失败”?这是因为如果JDBC处于自动提交模式,每个SQL语句在完成后都会提交到数据库,也就是说在执行A扣钱(即第一条sql)语句之后,他就已经更新了数据库,如果这个时候程序突然崩溃,导致后面的语句没有运行,那么就出现了我们说的,a扣钱了,但是b却没收到钱。
所以我们需要考虑是否关闭自动提交并且管理自己的事务。
事务能够控制何时更改提交并应用于数据库。它将单个SQL语句或一组SQL语句视为一个逻辑单元,如果任何语句失败,整个事务将失败。
如上面所说,JDBC连接默认是处于自动提交,我们需要手动的打开这个功能。调用Connection对象的setAutoCommit()方法,将false传递给setAutoCommit(),就关闭了自动提交。也可以创第一个布尔值true来打开它。
conn.setAutoCommit(false);
现在我们知道了,想要让多条更新语句保持原子性,首先要关闭自动提交,然后手动提交,在一个事务失败的时候,要进行回滚。
提交和回滚
完成更改后,若要提交更改,需要在对象上调用commit()方法:
conn.commit();
否则要进行回滚
conn.rollback();
以下实例说明了如何使用提交和回滚。
try{
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
String SQL = "INSERT INTO Employees" + "VALUES (106,20,'Rita,'Tez')";
stmt.executeUpdate(SQL);
String SQL = "IMSERT IN Employees " + "VALUES (107,22,'SITA','SINGH')";
stmt.excuteUpdate(SQL);
conn.commit();
}catuch(SQLException se){
conn.rollback();
}
使用保存点
新的JDBC3.0新添加了Savepoint接口提供了额外的事务控制能力。
使用Connection对象两个方法来创建Savepoint对象。
setSavepoint(String savepointName);//定义新的保存点,返回`Savepoint`对象。
releaseSavepoint(Savepoint savepointName);//删除保存点。参数是由上面的方法生出的对象。
这样使用rollback(String savepointName)方法,就可以将事务回滚到指定的保存点
try{
//Assume a valid connection object conn
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
//set a Savepoint
Savepoint savepoint1 = conn.setSavepoint("Savepoint1");
String SQL = "INSERT INTO Employees " +
"VALUES (106, 24, 'Curry', 'Stephen')";
stmt.executeUpdate(SQL);
//Submit a malformed SQL statement that breaks
String SQL = "INSERTED IN Employees " +
"VALUES (107, 32, 'Kobe', 'Bryant')";
stmt.executeUpdate(SQL);
// If there is no error, commit the changes.
conn.commit();
}catch(SQLException se){
// If there is any error.
conn.rollback(savepoint1);
}
事务的隔离性
以上我们说明了,如何实现一个数据要么都成功,要么都失败,这个其实是在事务中的原子性。而另一个比较重要的就是隔离性
什么是隔离性
所谓隔离性是指事务与事务之间的隔离,即在事务提交之间,其他事务中与未完成的事务的数据中间状态访问权限,具体可以通过设置隔离级别来进行控制。
并发事务可能出现的情况
脏读
一个事务读取另一个事务尚未提交的数据。
这个解决办法,就是在事务进行操作的时候,禁止该事物进行读操作。
不可重新读
其他事务的操作导致某一个事务两次读取数据不一致。
幻读
其他事务的数据操作导致某个事务两次读取数据数量不一致。
参考资料
未完待续。。。