什么叫事务
事务就是一组sql组成的操作单元,要么操作全部成功,要么全部失败。
事务的基本要素(ACID)(四个)
-
原子性
一个事务必须被视为一个不可分割的最小工作单元,整个事务要么全部成功,要么失败全部回滚。事务中不能只执行其中的一部分操作。
-
一致性
数据库总是从一个一致的状态转换到另外一个一致的状态。比如两个update,第一个update之后系统崩溃了,也不会对数据有影响,因为事务还没有提交。
-
隔离性
一个事务所做的修改,在提交之前,对其他事务应该是不可见的。
-
持久性
一旦事务提交,那么所做的修改就会永久的保存到数据库中。
事务的并发问题(三种)
脏读
事务B读取了事务A未提交的修改数据
不可重复读
事务A一直查询,事务B在事务A查询的期间对数据做了更新,导致事务A读取的结果不一致
幻读
事务A对摸个数据范围记录时,事务B在事务A查询的范围内插入了新的记录。当事务A再次读取事务时,会发现新增的记录,就想出现幻觉似的。
事务的隔离级别(四种)
-
读未提交(read-uncommitted)
允许脏读,也就是可能读取到其他会话中未提交事务修改的数据
例子:
①事务A命令行设置事务模式为read uncommitted(未提交读),查询表member的初始状态:
set session transaction isolation level read uncommitted;
start transaction;
select * from member;
image.png
②事务A到此暂停,打开事务B,让事务B更新一条数据
set session transaction isolation level read uncommitted;
start transaction;
update member set age = age-10 where name = 'zhangsan';
select * from member;
image.png
③虽然事务B的事务还没提交,但是事务A就可以查询到事务B已经更新的数据:
image.png
④事务B如果回滚,所有的操作都将会被撤销,那事务A查询到的数据其实就是脏数据:
image.png
⑤如果事务A执行更新语句update member set age = age -3 where name='zhangsan';,zhangsan的age没有变成0,居然是10,What???3-3=10???,这样子算其实是因为事务A不知道事务B回滚了.所以会用3-3=0.其实程序是13-3=10。要想解决这个问题可以采用读已提交的隔离级别
image.png
-
不可重复读(read-committed)
只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)
①把事务A的事务模式设置成read committed(未提交读),查询表member的所有记录:
set session transaction isolation level read committed;
start transaction;
image.png
②打开事务B,更新一条数据
image.png
③事务A再查询,查不到事务B的修改,解决了脏读
image.png
④事务B提交事务,事务A再查询,结果不一致,即产生了不可重复读的问题
image.png
-
可重复读(repeatable-read)
可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读
①打开事务A并设置当前事务模式为repeatable read,查询表member的所有记录
set session transaction isolation level repeatable read;
start transaction;
select * from member;
image.png
②事务A提交之前打开事务B更新一条并且提交事务
image.png
③事务A再次查询,发现此时的信息是一致的,没有出现不可重复读的问题
image.png
④事务A更新一条数据然后查看,会发现数据跟想象的不一样,age的数据是根据事务B的结果进行计算的。数据的一致性倒是没有被破坏。可重复读的隔离级别下使用了MVCC机制,select操作不会更新版本号,是快照读(历史版本);insert、update和delete会更新版本号,是当前读(当前版本)。
image.png
⑤当事务B重新开启事务添加一条信息的话会出现事务锁,事务A还是之前数据。没有出现幻读。
image.png
image.png
-
串行化(serializable)
完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞
①打开事务A,并设置当前事务模式为serializable,查询表member的初始值:
image.png
②打开事务B,插入一条数据,会报错。mysql中事务隔离级别为serializable时会锁表,因此不会出现幻读的情况,这种隔离级别并发性极低,开发中很少会用到。
image.png
重要
①事务隔离级别为读提交时,写数据只会锁住相应的行
②事务隔离级别为可重复读时,如果检索条件有索引(包括主键索引)的时候,默认加锁方式 是next-key锁,如果检索条件没有索引,更新数据时候会锁住整张表。一个间隙被事务加了锁,其他事物是不能再这个间隙插入记录的,这样可以防止幻读。
③事务隔离级别为串行化时,读写数据都回锁住整张表
④隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也就越大。
⑤mysql的mvcc机制
⑥next-key锁
级别顺序(由低到高)
Read uncommitted (读未提交)、Read committed(读提交/不可重复读) 、Repeatable read(可重复读) 、Serializable (串行化)
网友评论