什么是事务
事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。
默认MysQL的事务是自动提交的,也就是说,当执行一条DML语句,MySQL会立即隐式的提交事务。
事务的四大特性
- 原子性
事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做 - 一致性
事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。 - 隔离性
一个事务的执行不能被其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。 - 持续性
也称永久性,指一个事务一旦提交,它对数据库中的数据的改变就是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。
MySQL事务隔离级别
隔离级别 | 隔离级别的值 | 导致的问题 |
---|---|---|
Read-Uncommitted | 0 | 导致脏读 |
Read-Committed | 1 | 避免脏读,允许不可重复读和幻读 |
Repeatable-Read | 2 | MySQL默认的隔离级别。避免脏读,不可重复读,允许幻读 |
Serializable | 3 | 串行化读,事务只能一个一个执行,避免了脏读、不可重复读、幻读。执行效率慢,使用时慎重 |
脏读
一个事务对数据进行了增删改查,但是未提交事务。另一个事物可以读取到未提交的数据,如果第一个事务进行了回滚,那么第二个事务就读到了脏数据。
例子:
领导给张三发工资,10000元已打到张三账户,但该事务还未提交,正好这时候张三去查询工资,发现10000元已到账。这时领导发现张三工资算多了5000元,于是回滚了事务,修改了金额后将事务提交。最后张三实际到账的只有5000元。
不可重复度
一次事务发生了两次读操作,两个读操作之间发生了另一个事务对数据修改操作,这时候第一次和第二次读到的数据不一致。
不可重复度关注点在数据更新和删除,通过行级锁可以实现可重复读的隔离级别。
例子:
张三需要转正1000元,系统读到卡余额有2000元,此时张三老婆正好需要转正2000元,并且在张三提交事务前把2000元转走了,当张三提交转账是系统提示余额不足。
幻读
幻读,指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行。
相对于不可重复读,幻读更关注其它事务的新增数据。通过行级锁可以避免不可重复读,但无法解决幻读的问题,想要解决幻读,只能通过Serializable隔离级别来实现
。
例子:
张三老婆准备打印张三这个月的信用卡消费记录,经查询发现消费了两次共1000元,而这时张三刚按摩完准备结账,消费了1000元,这时银行记录新增了一条1000元的消费记录。当张三老婆将消费记录打印出来时,发现总额变为了2000元,这让张三老婆很诧异。
串行化读
Serializable是最高的隔离级别,性能很低,一般很少用。在这级别下,事务是串行顺序执行的,不仅避免了脏读、不可重复读,还避免了幻读。
实际操作
- 查看当前事务隔离级别
SELECT @@tx_isolation;
- 设置当前mysql的事务隔离级别
set session transaction isolation level read uncommitted;
SELECT @@tx_isolation;
- read uncommitted的脏读演示
先创建一个表:
开启事务,并修改一列数据
重新打开一个命令行,注意:每启动一个 mysql 程序, 就会获得一个单独的数据库连接,所以新打开的事务隔离级别还是repeatable read
若此时用另一个mysql程序查看表时,发现对应的值修改为王五了,若此时第一个mysql程序执行回滚,则读到的数据又变为张三了,此时就出现了脏读情况即读到了脏数据。
- read committed规避脏读和read committed的不可重复读的演示
将两个mysql程序都设置为read committed隔离级别
注:之前的事务虽然回滚了,但还没有提交,要进行下一个操作的话先执行commit;提交事务
可以发现蓝色这边的mysql程序读到的是未提交的数据,就可以避免脏读
黑色这边提交之后,蓝色才能读到:
但也导致了两次连续的查询 查询到的结果不一样,就导致了不可重复读。
- repeatable read避免不可重复读与repeatable read的幻读
提交之前的事务并设置事务为可重复读
先看一下现在表有什么数据,不要到时候混乱了:
黑色这边修改数据,蓝色这边查看数据还是原来的,规避了脏读
黑色这边提交,蓝色这边读到的仍然是原来的数据
只有当蓝色这边也提交了才能看到修改的数据,这就能使蓝色这边事务进行过程中读到的数据是一致的。
再次开启事务,演示幻读:
黑色这边先查询有两个数据,此时蓝色这边插入了一条数据并提交了,此时黑色这边就会出现一个问题就是我明明是要修改两个数据的,结果却修改了3个,就导致了幻读。
- serializable解决幻读问题
首先还是老样子,提交之前的事务,然后设置事务为serializable
此时在黑色事务打开时,在蓝色这边对数据进行插入操作,发现蓝色这边的操作执行不了,这就是serializable的隔离机制,即之前有事务在进行操作,新的事务要对表进行增删改时就会阻塞改操作,知道当前事务提交才能修改
那个插入数据之所以没成功,是等待时间太长了,被系统杀死了,大家在操作的时候就不要让另一个事务等太久。