事务(TRANSACTION)是作为单个逻辑工作单元执行的一系列操作。这些操作作为一个整体一起向系统提交,要么都执行、要么都不执行 。事务是一个不可分割的工作逻辑单元。
事务是现代数据库理论中的核心概念之一。如果一组处理步骤或者全部发生或者一步也不执行,我们称该组处理步骤为一个事务。当所有的步骤像一个操作一样被完整地执行,我们称该事务被提交。由于其中的一部分或多步执行失败,导致没有步骤被提交,则事务必须回滚到最初的系统状态。
二 事务的四大特性
1,原子性,事务的原子性指的是,事务中包含的程序作为数据库的逻辑工作单元,它所做的对数据的修改操作要么全部执行,要么完全不执行;(原子操作,也就是不可分割的操作,要么一起成功,要么一起失败)
2,一致性,事务的一致性是在一个事务执行之前和执行之后数据库都必须处于一致性状态。这种特性称为事务的一致性。假如数据库的状态满足所有的完整性约束,就说该数据库是一致的。
3,分离性,分离性指并发的事务是相互隔离的。即一个事务内部的操作及正在操作的数据必须封锁起来,不被其它企图进行修改的事务看到。
4,持久性,持久性意味着当系统或介质故障时,确保已提交的事务的更新不能丢失。即一旦一个事务提交,DBMS保证它对数据库中的数据的改变应该是永久性的,经得住任何系统故障。持久性通过数据库备份和恢复来保证。
三 JDBC事务并发产生的问题及隔离级别
JDBC 事务并发产生的问题:
1脏读(D D irty R R eads s ) 一个事务读取了另一个并行事务还未提交的数据。
2不可重复读( Un Re peatable Read ) 一个事务再次读取之前的数据时,得到的数据不一致,被另一个已提交的事务修改。
3 幻读(Phantom Read ) 一个事务重新执行一个查询,返回的记录中包含了因为其它最近提交的事务而产生的新记录。
为了避免以上三种情况的出现,则采用事务隔离级别。
事务隔离级别:
y:可能出现,n:不会出现
隔离级别 | 脏读 | 不可重复读 | 幻读 |
读未提交(Read uncommitted) | y | y | y |
读已提交(Read committed) | n | y | y |
可重复读(Repeatable read) | n | n | y |
可串行化(Serializable) | n | n | n |
四 事务处理三步曲及示例代码
a 事务处理三步曲
1 connection.setAutoCommit(false); // 把自动提交关闭
正常的 DB 操作
2 connection.commit() // 事务提交
3 connection.rollback() // 事务失败后,进行事务回滚
注:当只想撤销事务中的部分操作时,可以使用SavePoint;
connection.setAutoCommit(false)
正常的 DB 操作 1
Savepoint sp = connection.setSavepoint();
正常的 DB 操作 2
connection.commit();
connection.rollback(sp);
当事务失败后,进行事务回滚,只会回滚到事务保存点,事务保存点之前的操作还是会执行。
b 示例代码
业务需求:查询名字为Alex的记录,如果其money大于200,则将其money数减200,然后将这200加到名字为Dick的记录上;
public static void acidTest() {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JDBCUtils.getConnection();
conn.setAutoCommit(false);//step1,把自动提交关闭
String sql = "select money from test where name = 'Alex'";
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
float money = 0;
if(rs.next()){
money = rs.getFloat("money");
}
if(money < 200){
throw new RuntimeException("钱数没有超出200");
}
sql = "update test set money = money - 200 where name = 'Alex'";
ps = conn.prepareStatement(sql);
ps.executeUpdate();
sql = "update test set money = money + 200 where name = 'Dick'";
ps = conn.prepareStatement(sql);
ps.executeUpdate();
conn.commit();//step2,提交事务
} catch (Exception e) {
try {
conn.rollback();//step3,事务回滚
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally{
JDBCUtils.free(rs, ps, conn);
}
}