欢迎访问昆山宝鼎软件有限公司网站! 设为首页 | 网站地图 | XML | RSS订阅 | 宝鼎邮箱 | 后台管理


新闻资讯

MENU

软件开发知识
原文出处: sdlyjzh

本文会按照实际事情中遇到的例子,梳理清楚数据库事务的断绝级别。内容很简朴,假如你能静下心来看完,必然会对你领略断绝级别有很大的辅佐。

想象一个场景。抽奖,假如用户中奖了,昆山软件开发,一般有如下几个流程:

  • 扣减奖品数量;
  • 记任命户中奖信息;
  • 试想假如扣减奖品数量了,功效记任命户中奖数据的时候失败了,那么数据就会呈现纷歧致的问题。
  • 这种场景,就可以利用事务。因为事务的一个特性,就是原子性:要么不做,要么全做。

    上述问题办理了。再想一下这样的场景:
    在抽奖前,先查询奖品剩余数量,假如剩余数量<1,则任务抽奖勾当已经竣事,不再举办抽奖。假如事务A扣减奖品数量但未提交,事务B查询剩余奖品数量,此时应该是几多呢?这就和事务的断绝级别有干系了。

    在接头断绝级别前,我们先做一些数据库的初始化操纵:

    建表:

    CREATE TABLE `Tran_test` (
      `id` bigint(20) NOT NULL,
      `userId` bigint(20) NOT NULL DEFAULT '0',
      `weChatId` varchar(50) NOT NULL DEFAULT '' COMMENT '微信id(openId、uninId)',
      `orderId` bigint(20) NOT NULL DEFAULT '0' COMMENT '商城订单id',
      `count` bigint(10) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8

    初始化1个奖品:

    insert into Tran_test (id,count) values(1,1)

    未提交读

    事务中的修改,纵然没有提交,也会被其他事务读取。

    下面通过mysql演示:

    配置断绝级别为为提交读:

    SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

     `count` bigi <a href=昆山软件开拓 nt(10) DEFAULT NULL" class="aligncenter size-full wp-image-29324" title="79920266-1" src="/uploads/allimg/c180731/1532b1044214P-12947.png" />

    可以看到,事务B读取到了事务A未提交的数据,它任务抽奖勾当已经竣事。但假如此时事务A回滚,count仍然为1,则勾当实际是未竣事的,这就是脏读。因此,实际中,一般不会回收这种断绝级别。

    提交读

    提交读断绝级别可以办理上述脏读问题,其只能读到其他事务已经提交的数据。

    变动数据库断绝级别:

    SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;

     `count` bigi <a href=昆山软件开拓 nt(10) DEFAULT NULL" class="aligncenter size-full wp-image-29325" title="Snipaste_2018-07-30_15-02-16" src="/uploads/allimg/c180731/1532b10442610-25142.png" />

    可以看到,在事务A提交前的窜改,事务B是读取不到的。只有A事务提交后,B才气读取到事务A的窜改。

    我们看到,在事务B中,先后两次读取,count的值是纷歧样的,这就是不行反复读。而可反复读断绝级别可以办理这个问题。

    可反复读

    变动数据库断绝级别:

    SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;

     `count` bigi <a href=昆山软件开拓 nt(10) DEFAULT NULL" class="aligncenter size-full wp-image-29326" title="Snipaste_2018-07-30_15-03-17" src="/uploads/allimg/c180731/1532b104429320-3V41.png" />

    可以看到,岂论事务A是否提交,事务B读到的count值都是稳定的。这就是可反复读。

    除了上面提到的脏读、不行反复读,尚有一种环境是幻读:在事务中,前后两次查询,记录数量是纷歧样的。

    好比事务B是事务A插入一笔记录的前后执行查询,会发明沟通的查询条件,查出来的记录数纷歧样。由于mysql的RR(可反复读)一并办理了幻读的问题,所以我们直接看上述场景,在mysql中的表示:

     `count` bigi <a href=昆山软件开拓 nt(10) DEFAULT NULL" class="aligncenter size-full wp-image-29327" title="Snipaste_2018-07-30_15-04-10" src="/uploads/allimg/c180731/1532b104432620-4cD.png" />

    可见,昆山软件开发,在事务A提交前后,事务B查询的功效数量是一直的,并没有呈现幻读的环境。

    一点思考

    下面默认都是接头的msyql RR断绝级此外环境。

    假如两个用户同时抽奖,并且同时中奖。两者都进入了中奖的事务。A事务扣减了奖品数量,B也执行了扣减数量。假设奖品数量是N,假如是可反复读,那么,假如两个事务并行举办,那么岂论A有没有提交,B读到的数量都是N,执行后为N-1,而事务A也是N-1,这样不就有问题了吗?我们期望的是N-2。

    当初这个问题让我很狐疑。这回响了其时我对数据库锁和快照读、当前读两个常识点的欠缺。

    快照读、当前读

    将设事务A已经提交,由于是可反复读,那事务B读到的奖品数量一致是N,昆山软件开发,执行-1,数据酿成N-1,而不是我们期望的N-2。

    假如领略了快照读和当前读的观念,上面的狐疑就不会存在了。

    在事务中,执行普通select查询之后,会建设快照,后头再执行沟通的select语句时,查询的其实是前面生成的快照。这也就是为什么会有可反复读。