MySQL事务中的安全问题(脏读、不可重复读、幻读 及 悲观锁和乐观锁)

事务指的是一组操作 里面包含许多个单一的逻辑
指的是逻辑上的一组操作 组成这组操作的各个逻辑单元要么全部成功 要么全部失败
只要有一个逻辑没有执行成功 那么都算失败 所有的数据都回滚到最初的状态

目的是为了确保逻辑的成功 不成功即失败

然而 事务有可能会发生读和写的安全问题:

【读 问题】

  • 1、脏读
    一个事务读到了另一个事务还未提交的数据
    当事务A正在访问数据并且对数据进行了修改 而这种修改还没有提交到数据库中
    这时 另外一个事务B也访问这个数据 然后使用了这个数据
    此时 若事务A回滚 则事务B第二次读取时读到了脏数据
    因为该数据再重新读取一下就又变成原先的数据了

  • 2、不可重复读
    一个事务读到了另一个事务提交的数据 导致多次查询结果不一致
    事务B在事务A的读取的时候提交了数据 然后导致了事务A前后两次读取的数据不一致
    因为此时B若再读取一下该数据 就会发现数据又变化了 变成新的(A改过的数据)了
    该问题的解决方法就是限制只有在修改事务完全提交之后才可以读取数据

  • 3、幻读
    一个事务读到了另一个事务已提交的插入的数据 导致多次查询结果不一致
    第一个事务对一个表中的数据进行了修改 这种修改涉及到表中的全部数据行
    与此同时 第二个事务也修改这个表中的数据 这种修改向表中插入新数据
    那么 操作第一个事务的用户就会发现表中还有没有修改的数据行 就好象发生了幻觉 因而得名幻读

【写 问题】

  • 丢失更新✧
    指一个事务去修改数据库 另一个事务也修改数据库
    那么最后的那个事务 不管是提交还是回滚都会造成前面一个事务的数据更新丢失
    后面的事务会把前面的事务执行后的数据覆盖掉

对于丢失更新 有两种解决方法 分别是悲观锁和乐观锁:

悲观锁:(

事务在一开始就认为丢失更新一定会发生 这是一件很悲观的事情 因而得名

具体操作步骤:

  • 1、所有事务在执行操作前先查询一次数据 查询语句如下:
    select * from student for update:后面的for update其实是数据库锁机制 是一种排他锁
    当一个事务的操作未完成时候 其他事务可以读取但是不能写入或更新
  • 2、哪个事务先执行这个语句 哪个事务就持有了这把锁 可以查询出数据
    后面的事务再执行这条语句 不会有任何数据显示 就只能等着
  • 3、一直等到前面的事务提交数据后 后面的事务数据才会出来 然后才可往下接着操作

类似于上卫生间 谁先来 谁就可以进去蹲着 后面来的人只能得等着
只有里面的人出来了然后才能进去
该思路也是Java中同步的概念

乐观锁:)

从来不会觉得丢失更新会发生 这很乐观 因而得名

该做法要求程序员在数据库中添加字段 然后在后续更新的时候 对该字段进行判定比对 若一致才允许更新

例:

  • 1、数据库表中额外添加了一个version字段 用于记录版本
    默认从0开始 只要有针对表中数据进行修改的 那么version就+1
  • 2、开启A事务 然后开启B事务
  • 3、A先执行数据库表操作
    因为之前没有人修改过 因此允许A事务修改数据库的
    但在修改完毕后 就把version的值变成1了
  • 4、B事务这时候若想执行修改 则不允许修改的 因为B事务以前没有查询过数据库的内容的 因此它认为数据库的版本还是0
    但数据库的版本经过A修改已经是1了 因此这时候不允许修改 要求其重新查询
  • 5、B事务重新查询后将会得到version为1的数据 这份数据就是之前A事务修改的数据
    然后B再进行修改 也是在A的基础上修改 所以就不会有丢失更新的情况出现了

乐观锁的机制其实是通过比对版本或者比对字段的方式来实现的
该机制与版本控制软件SVN和GIT的机制是一样的


发布了174 篇原创文章 · 获赞 5 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/Piconjo/article/details/104913676