社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
Transaction
通常情况下在某些业务:如银行转账等,这样的业务他不是由一个SQL语句构成而是多个或多组的SQL构成,那么这样的一个过程,我们称之为一组事务。
事务的特征(ACID)
A 原子性(Atomicity):事务是最小的单位,不可再分
C 一致性(Consistency):事务在DML语句操作时,要保证同时成功同时失败
I 隔离性(Isolation):事务和事物之间互不干扰
D 持久性(Durability):完成事务后,最终要把数据库表的更改内容持久化到磁盘上
开启事务 start Transaction
关闭事务 End Transaction
提交事务 commit
回滚事务 rollback
设置保存点 savepoint
事务的简单实现
public static void main(String[] args){
Connection conn = null;
PreparedStatement ps1 = null;
PreparedStatement ps2 = null;
Savepoint sp = null;
try{
conn = JDBCUtil.getConnection();
//将自动提交事务禁用
conn.setAutoCommit(false);
//设置保存点
sp = conn.setSavepoint("A");
ps1 = conn.prepareStatement("update tb1 set salary = salary + 1000 where username = ?");
ps1.setString(1,"lucy");
ps2 = conn.prepareStatement("update tb1 set salary = salary - 1000 where username = ?");
ps2.setString(1,"lisi");
ps1.executeUpdate();
ps2.executeUpdate();
} catch (Exception e){
try{
conn.rollback(sp);
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally{
try {
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
SQL事务隔离级别
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read-uncommitted) | 是 | 是 | 是 |
不可重复读(read-committed) | 否 | 是 | 是 |
不可重复读(repeatable-read) | 否 | 否 | 是 |
串行化(Serializable) | 否 | 否 | 否 |
事务的并发问题:
脏读: 事务A读取了事务B的更新,然后B回滚操作,此时A读到的数据就是脏数据。
不可重复读: 事务A多次读取同一数据,事务B在事物A多次读取的过程中,对数据作了更新并提交,导致事物A多次读取同一数据,结果不一致。
幻读: 系统管理员A将数据库中学生的成绩分数改为ABCD四个等级,但是系统管理员B此时插入了一条具体分数的记录,当管理员A修改结束后发现还有一条记录没有修改过来,好像出现了幻觉一样。
MySQL默认的事物隔离级别为repeatable-read
1)设置客户端A当前事物模式为read uncommitted
可看出当前 lisi 的 age 是19,我们进行修改,但不提交
2)新建一个客户端B并设置事务模式,进行查询tb1,虽然客户端A并未提交,但是此时 lisi 的 age 已经为20
一旦此时客户端A的事物由于某些原因进行回滚,则此时客户端B查到的数据就是脏数据。
3)当客户端B执行更新语句时,lisi 的年龄并没有变成21而是变成了20。但是客户端B本身并不知道客户端A已经回滚操作,引发问题。
1)打开客户端A,设置事务模式read committed,查询tb1的所有记录:
2)在客户端A的事物提交之前,打开另一个客户端B,更新表tb1:
3)客户端B没有commit,此时客户端A再次进行查询时,数据没有显示变化,解决了脏读问题:
4)客户端B将修改过的事务进行提交:
5)客户端A再次进行查询,此时查询数据已经不同,但是产生了不可重复读的问题:
1)打开客户端A,将其事物设置为可重复读(repeatable read),并查询现在tb1表中的数据:
2) 新建一个客户端B,更改tb1中的数据,并进行提交:
3)此时客户端A再次进行查询查询到的数据与原来相同,没有发生不可重复读现象:
4)在客户端A中,执行update tb1 set age = age - 1 where username = ‘lisi’; 此时 age 没有变为19而是变为21,是由于此时的值是由客户端B中的值age = 22,来计算的,所以是21。
那么此时数据的一致性被破坏了吗??
答案是:并没有。
可重复的隔离级别下使用了MVCC机制,select操作下不会更新版本号,是快照读(历史版本);insert,update 和 delete 会更新版本号,是当前读(当前版本)。
接下来我们来验证一下:
5)用start transaction; 重新打开客户端B,插入一条数据后再次进行提交:
6)客户端A进行查询,没有出现增加的信息,可知并没有出现幻读现象
注意:
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!