事务
并发访问问题
如果不考虑隔离性,事务存在3中并发访问问题。
脏读:一个事务读到了另一个事务未提交的数据.
假设现在有两个事务A、B:
- 假设现在A的余额是100,事务A正在准备查询Jay的余额
- 这时候,事务B先扣减Jay的余额,扣了10
- 最后A 读到的是扣减后的余额
由上图可以发现,事务A、B交替执行,事务A被事务B干扰到了,因为事务A读取到事务B未提交的数据,这就是脏读。
不可重复读:一个事务读到了另一个事务已经提交(update)的数据。引发另一个事务,在事务中的多次查询结
果不一致。假设现在有两个事务A和B:
- 事务A先查询Jay的余额,查到结果是100
- 这时候事务B 对Jay的账户余额进行扣减,扣去10后,提交事务
- 事务A再去查询Jay的账户余额发现变成了90
事务A又被事务B干扰到了!在事务A范围内,两个相同的查询,读取同一条记录,却返回了不同的数据,这就是不可重复读。
虚读 /幻读:一个事务读到了另一个事务已经提交(insert)的数据。导致另一个事务,在事务中多次查询的结果不一致。
假设现在有两个事务A、B:
- 事务A先查询id大于2的账户记录,得到记录id=2和id=3的两条记录
- 这时候,事务B开启,插入一条id=4的记录,并且提交了
- 事务A再去执行相同的查询,却得到了id=2,3,4的3条记录了。
事务A查询一个范围的结果集,另一个并发事务B往这个范围中插入/删除了数据,并静悄悄地提交,然后事务A再次查询相同的范围,两次读取得到的结果集不一样了,这就是幻读。
四大隔离级别
数据库规范规定了4种隔离级别,分别用于描述两个事务并发的所有情况。
- read uncommitted 读未提交,一个事务读到另一个事务没有提交的数据。
a)存在:3个问题(脏读、不可重复读、虚读)。
b)解决:0个问题 - read committed 读已提交,一个事务读到另一个事务已经提交的数据。
a)存在:2个问题(不可重复读、虚读)。
b)解决:1个问题(脏读) - repeatable read:可重复读,在一个事务中读到的数据始终保持一致,无论另一个事务是否提交。
a)存在:1个问题(虚读)。
b)解决:2个问题(脏读、不可重复读) - serializable 串行化,同时只能执行一个事务,相当于事务中的单线程。
a)存在:0个问题。
b)解决:3个问题(脏读、不可重复读、虚读)
安全和性能对比
- 安全性: serializable > repeatable read > read committed > read uncommitted
- 性能 : serializable < repeatable read < read committed < read uncommitted
常见数据库的默认隔离级别:
- MySql: repeatable read
- Oracle: read committed