zoukankan      html  css  js  c++  java
  • 数据库事务并发产生的问题以及事务的隔离级别

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

    大家都知道事务只有提交后,才会真正的持久化到硬盘,倘若出现出现了回滚的操作,则事务所有操作的影响都会被回退掉。那么假若事务在执行过程中,其他事务读取到了当前的操作结果,但是当前事务后边回滚了,那么其他事务相当于读取到了错误的数据。
    举个例子
    老板告诉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
    最高级别,强制事务进行串行操作
    解决了所有数据库并发问题

  • 相关阅读:
    P1144 最短路计数 题解 最短路应用题
    C++高精度加减乘除模板
    HDU3746 Teacher YYF 题解 KMP算法
    POJ3080 Blue Jeans 题解 KMP算法
    POJ2185 Milking Grid 题解 KMP算法
    POJ2752 Seek the Name, Seek the Fame 题解 KMP算法
    POJ2406 Power Strings 题解 KMP算法
    HDU2087 剪花布条 题解 KMP算法
    eclipse创建maven项目(详细)
    maven的作用及优势
  • 原文地址:https://www.cnblogs.com/jilodream/p/14231911.html
Copyright © 2011-2022 走看看