MySQL事务的隔离级别
1、事务
MySQL
是一个客户端/服务器架构的软件,对于同一个服务器来说,可以有若干个客户端与之连接,每个客户端与服务器连接上之后,就可以称之为一个会话(Session
)。每个客户端都可以在自己的会话中向服务器发出请求语句,一个请求语句可能是某个事务的一部分,也就是对于服务器来说可能同时处理多个事务。事务有一个称之为隔离性的特性,理论上在某个事务对某个数据进行访问时,其他事务应该进行排队,当该事务提交之后,其他事务才可以继续访问这个数据。但是这样子的话对性能影响太大,我们既想保持事务的隔离性,又想让服务器在处理访问同一数据的多个事务时性能尽量高些,只能舍弃部分隔离性取性能。
2、事务并发执行的问题
- 脏写(这个太严重了,任何隔离级别都不允许发生)
sessionA:修改了一条数据,回滚掉
sessionB:修改了同一条数据,提交掉
Session A
和Session B
各开启了一个事务,Session B
中的事务先将stu_id列为1
的记录的name
列更新为’王五’,然后
中的事务接着又把这条stu_id列为1的记录的name列更新为李四。如果之后Session B
中的事务进行了回滚,那么Session A
中的更新也将不复存在,这种现象就称之为脏写。这时Session A
中的事务就很奇怪,我明明把数据更新了,最后也提交事务了,怎么到最后说自己啥也没干呢?
- 脏读:一个事务读到另一个未提交事务修改的数据
session A:查询,得到某条数据
session B:修改某条数据,但是最后回滚掉啦
session A:在sessionB修改某条数据之后,在回滚之前,读取了该条记录
对于session A来说,读到了session回滚之前的脏数据。
Session A
和Session B
各开启了一个事务,Session B
中的事务先将stu_id
列为1的记录的name
列更新为’王五’,然后Session A
中的事务再去查询这条stu_id
为1的记录,如果读到列name
的值为’王五’,而Session B
中的事务稍后进行了回滚,那么Session A
中的事务相当于读到了一个不存在的数据,这种现象就称之为脏读。
- 不可重复读:前后多次读取,同一个数据内容不一样
session A:查询某条记录
session B : 修改该条记录,并提交事务
session A : 再次查询该条记录,发现前后查询不一致
在Session B
中提交了几个隐式事务(注意是隐式事务,意味着语句结束事务就提交了),这些事务都修改了stu_id
列为1的记录的列name
的值,每次事务提交之后,如果Session A
中的事务都可以查看到最新的值,这种现象也被称之为不可重复读
。
- 幻读:前后多次读取,数据总量不一致
session A:查询表内所有记录
session B : 新增一条记录,并查询表内所有记录
session A : 再次查询该条记录,发现前后查询不一致
Session A
中的事务先根据条件stu_id > 0
这个条件查询表t_order
,得到了name
列值为'张三'
的记录;之后Session B
中提交了一个隐式事务,该事务向表t_order
中插入了一条新记录;之后Session A
中的事务再根据相同的条件stu_id > 0
查询表t_order
,得到的结果集中包含Session B
中的事务新插入的那条记录,这种现象也被称之为幻读。
3、SQL标准中的四种隔离级别
我们上边介绍了几种并发事务执行过程中可能遇到的一些问题,这些问题也有轻重缓急之分,我们给这些问题按照严重性来排一下序:
脏写 > 脏读 > 不可重复读 > 幻读
也就是说:
READ UNCOMMITTED
隔离级别下,可能发生脏读、不可重复读和幻读问题。READ COMMITTED
隔离级别下,可能发生不可重复读和幻读问题,但是不可以发生脏读问题。REPEATABLE READ
隔离级别下,可能发生幻读问题,但是不可以发生脏读和不可重复读的问题。SERIALIZABLE
隔离级别下,各种问题都不可以发生。
MySQL默认的隔离级别是REPEATABLE READ