mysql的事务隔离
1.事务:
1)概念:
构成单个逻辑工作单元的操作集合;多个操作要么全部提交,要么全部回滚。
2)事务基本要素:
原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。 事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。
隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。
3)事务的并发问题:
对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发问题:
脏读: 对于两个事物 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段. 之后, 若 T2 回滚, T1读取的内容就是临时且无效的.
不可重复读: 对于两个事物 T1, T2, T1 读取了一个字段, 然后 T2 更新了该字段. 之后, T1再次读取同一个字段, 值就不同了.
幻读: 对于两个事物 T1, T2, T1 读取一个表, 然后 T2 在该表中插入了一些新的行. 之后, 如果 T1 再次读取同一个表, 就会多出几行.
2.事务隔离
1)概念
数据库事务的隔离性: 数据库系统必须具有隔离并发运行各个事务的能力, 使它们不会相互影响, 避免各种并发问题.
一个事务与其他事务隔离的程度称为隔离级别.
数据库规定了多种事务隔离级别, 不同隔离级别对应不同的干扰程度, 隔离级别越高, 数据一致性就越好, 但并发性越弱。
2)MySQL事务隔离级别:
事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted) 是 是 是
读已提交,不可重复读(read-committed) 否 是 是
可重复读(repeatable-read) 否 否 是
串行化(serializable) 否 否 否
每次连接关闭都是一个新的session,每个session每都有自己的事务和隔离级别。但一定要在session中开启事务,否则会自动提交。
commit后事务会关闭,需要重新开启新的事务。
当A的事务隔离是read-uncommitted,A开启事务,B更新但未提交,A会读取未提交的数据。
当A的事务隔离是read-committed,A开启事务,B更新并提交,A前后读取不一致。(在A读取过程中B的更新使得A前后读取不一致)
当A的事务隔离是repeatable-read,A开启事务,B更新并提交,A前后读取一致,不会出现不可重复读。
当A的事务隔离是serializable,A开启事务,B更新或插入数据,无法执行。
总结:
read-uncommitted,repeatable-read,依赖于MVCC机制,不会对表加锁。
serializable,会对表加行锁甚至表锁。
还有一种情况,在select后面加for update,这和序列化一样,也会对数据行加锁。
3.问题
1)可重复读级别能解决幻读问题吗?
貌似在MySQL中通过MVCC就解决了幻读的问题,但实际上不能。
测试前数据:
根据上面的结果我们期望的结果是这样的:
image.png但是实际上我们的经过是:
image.png本来我们希望得到的结果只是第一条数据的部门改为财务,但是结果确实两条数据都被修改了。
这种结果告诉我们其实在MySQL可重复读的隔离级别中并不是完全解决了幻读的问题,而是通过MVCC机制解决了读数据情况下的幻读问题。而对于修改的操作依旧存在幻读问题,就是说MVCC对于幻读的解决时不彻底的。
所以,解决幻读,我们一般要通过加锁的方式,使用串行化读的隔离级别,或者select * from emp for update;