事务

并发访问问题

如果不考虑隔离性,事务存在3中并发访问问题。

  1. 脏读:一个事务读到了另一个事务未提交的数据.

    假设现在有两个事务A、B:

    • 假设现在A的余额是100,事务A正在准备查询Jay的余额
    • 这时候,事务B先扣减Jay的余额,扣了10
    • 最后A 读到的是扣减后的余额

1713824c77723cd4.jpg

由上图可以发现,事务A、B交替执行,事务A被事务B干扰到了,因为事务A读取到事务B未提交的数据,这就是脏读

  1. 不可重复读:一个事务读到了另一个事务已经提交(update)的数据。引发另一个事务,在事务中的多次查询结
    果不一致。

    假设现在有两个事务A和B:

    • 事务A先查询Jay的余额,查到结果是100
    • 这时候事务B 对Jay的账户余额进行扣减,扣去10后,提交事务
    • 事务A再去查询Jay的账户余额发现变成了90

1713829b86401900.jpg

事务A又被事务B干扰到了!在事务A范围内,两个相同的查询,读取同一条记录,却返回了不同的数据,这就是不可重复读

  1. 虚读 /幻读:一个事务读到了另一个事务已经提交(insert)的数据。导致另一个事务,在事务中多次查询的结果不一致。

    假设现在有两个事务A、B:

    • 事务A先查询id大于2的账户记录,得到记录id=2和id=3的两条记录
    • 这时候,事务B开启,插入一条id=4的记录,并且提交了
    • 事务A再去执行相同的查询,却得到了id=2,3,4的3条记录了。

171382b2bdd28029.jpg

事务A查询一个范围的结果集,另一个并发事务B往这个范围中插入/删除了数据,并静悄悄地提交,然后事务A再次查询相同的范围,两次读取得到的结果集不一样了,这就是幻读

四大隔离级别

数据库规范规定了4种隔离级别,分别用于描述两个事务并发的所有情况。

  1. read uncommitted 读未提交,一个事务读到另一个事务没有提交的数据。
    a)存在:3个问题(脏读、不可重复读、虚读)。
    b)解决:0个问题
  2. read committed 读已提交,一个事务读到另一个事务已经提交的数据。
    a)存在:2个问题(不可重复读、虚读)。
    b)解决:1个问题(脏读)
  3. repeatable read:可重复读,在一个事务中读到的数据始终保持一致,无论另一个事务是否提交。
    a)存在:1个问题(虚读)。
    b)解决:2个问题(脏读、不可重复读)
  4. 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

参考资料

https://juejin.im/post/5e800a1d6fb9a03c6568d06f