• 数据库事务并发产生的问题以及事务的隔离级别


    之前我们谈到过,数据库通过调整事务之间的隔离级别来提高事务的性能。
    那么接下来,我们来首先说说事务之间可能互相遇到的问题。

    大家都知道事务只有提交后,才会真正的持久化到硬盘,倘若出现出现了回滚的操作,则事务所有操作的影响都会被回退掉。那么假若事务在执行过程中,其他事务读取到了当前的操作结果,但是当前事务后边回滚了,那么其他事务相当于读取到了错误的数据。
    举个例子
    老板告诉HR,技术员工从下个月开始涨工资。技术小A从小道消息得知后,非常开心,准备把自己的单车换成摩托。后边老板发现公司的债务堆积严重,告知HR取消该加薪计划。得知真相的小A眼泪流下泪,只能含着泪去找摩托店老板退货。
    流程如下图:

    理论上小A等员工不应该从侧面提前获知公司的加薪计划,而应该在公司正式发文后(事务提交后)才可获知。这个问题就是我们常说的脏读。此时的隔离级别我们称之为读未提交,也就是说还没有正式公布的数据,可以被提前获知到。(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )
    如何解决这个问题呢?
    公司特别进行了申明,任何未经公司正式发文的消息,全部为不实消息,大家不可以信赖,出现任何问题后果自负,大家只能相信眼见为实的那些消息。这种隔离级别我们称之为读已提交,也就是只能读到公司正式发文的信息,对于那些未通过正式发文的消息,直接无视掉。
    问题好像已经解决了。
    年会前公司正式发文,由于今年业绩成长明显,经讨论, 全员加薪。
    小A看了看自己骑了两年的单车,决定换一辆摩托。正所谓搏一搏单车变摩托。
    于是小A兴冲冲的跑到摩托车行,预定了自己中意已久的摩托。
    然而接下来小A在参加年会的过程中,老总在会议上特别宣布,由于上一年公司业绩的特别突出,经过公司董事会的宣布,包括小A在内的所有员工,特别增发配股。
    小A看了看微信已经给摩托车老板转发的定金,又看了看最新的路虎,陷入的沉思。正所谓赌一赌摩托变路虎,年会结束后,小A火速联系摩托车老板,一哭二闹的总算把押金退了,去隔壁的4S店下单了路虎。
    流程如下图:

    对于这种每次读取到待遇都不一样,导致处理过程中出现了错误的处理的场景,我们称之为不可重复读。啥意思呢?也就是说即使公司正式发文后(提交后),也可能存在不确定性,因为公司可能反复提交数据,导致你拿到的数据仍然是脏数据,甚至你已经根据历史数据进行了错误的处理。此时的隔离级别我们称之为读已提交。
    那么怎么解决这个不可重复读的问题呢?
    也就是你操作期间,其他人不能改数据。很简单,你用什么数据锁住什么数据就好了,如果你需要根据薪酬要做出消费的判断,那么只要锁住薪酬就好了。

    这样好像问题已经解决了,但是通过一系列操作预订完路虎的你,回家发现,当初私房钱买的比特币,现在已经涨到3万美金了,折合下来资产都过亿了。(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )望着一串你的小屏手机都快显示不下的数字,你再次陷入沉思。从沉思缓过来后,你拨通了路虎店的电话,又是一顿一哭二闹三上吊,你去了旁边的玛莎拉蒂店下了订单。
    整体的流程如下:


    为啥明明已经锁定了薪酬,可是收入却仍然无情的增长。
    原因很简单,你只锁定住了既有的数据,来自单位的薪酬,没有锁住外界新增的数据,导致读到的数据仍然不够准确,无法做出正确的处理。这种异常场景我们称之为幻读,也就是因为新增数据导致的读不一致性。而当前的这种隔离级别称之为可重复读。也就是我们可以反复的读取之前已经读取到的数据,但是新增的数据,我们仍然可能会读取到,读不一致性仍然存在
    如何解决幻读的问题呢?
    答案很简单,还是加锁,之前加锁是对某些已经存在的数据加锁,现在加锁,是对全局加锁,谁要操作,谁获取到全局的锁。(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )至此也就不存在并发场景了,也就更不存在并发问题了。这种隔离级别我们称之为串行化。
    至于这几种隔离级别在innodb中是如何实现的,确实是比较复杂,一两句话难以说清,我会在后文中专门讲解
    下边我们总结一下前文所提到的概念:
    1、 脏读
    读到了其他事务未提交的数据。(也就是脏页中的数据,这个后文中我会专门讲解)
    2、 不可重复读
    在事务中每次读取到的数据是别人已经提交的数据,但是由于存在并发修改(update delele),每次读取到的数据不一致
    3、 幻读
    对于新插入的数据造成的读不一致性,我们称之为幻读
    这三个问题都属于存在并发事务时,数据的前后读不一致的问题。解决办法就是通过数据库的不同隔离机制,(防盗连接:本文首发自http://www.cnblogs.com/jilodream/ )来规避掉这些问题。
    1、 读未提交 Read Uncommitted
    事务未提交的数据修改,对其他事务也是可见的
    未解决脏读,不可重复读,幻读
    2、 读已提交 Read Committed
    一个事务开始后,只能看到已经提交的事务做出的修改
    解决脏读,未解决不可重复读,幻读
    3、 可重复读 Repeatable Read
    一个事务开始后,对于已经查询出的数据,再次反复查询获取到的数据是一样的
    解决了脏读,不可重复读,未解决幻读
    这里要特别注意下,可重复读级别尽管不要求解决幻读问题,但是innodb存储引擎却不存在该问题,这个我会再接下来的博客中专门解释该问题
    4、 串行化  Serializable
    最高级别,强制事务进行串行操作
    解决了所有数据库并发问题

  • 相关阅读:
    2011级csdnjava张侃—Spring加载配置web
    基于thinkphp实现根据用户ip判断地理位置并提供对应天气信息的应用
    ip地址库 与浏览器的关系
    根据IP定位用户所在城市信息
    Linux利用OneinStack搭建环境
    Laravel根据Ip获取国家,城市信息
    艾伟:一次挂死(hang)的处理过程及经验 狼人:
    艾伟:正则表达式30分钟入门教程 狼人:
    艾伟:C# Design Patterns (1) Factory Method 狼人:
    艾伟:打通.NET 3.5与ExtJS数据交互的任督二脉 狼人:
  • 原文地址:https://www.cnblogs.com/jilodream/p/14231911.html
Copyright © 2020-2023  润新知