事务隔离级别

数据库事务隔离级别,只是针对一个事务能不能读取其它事务的中间结果。

Read Uncommitted (读取未提交内容)

在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读( Dirty Read )。

Read Committed (读取提交内容)

这是大多数数据库系统的默认隔离级别(但不是 MySQL 默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读( Nonrepeatable Read ),因为同一事务的其他实例在该实例处理其间可能会有新的 commit ,所以同一 select 可能返回不同结果。

Repeatable Read (可重读)

这是 MySQL 的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 ( Phantom Read )。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的 " 幻影 " 行。 InnoDB和 Falcon 存储引擎通过多版本并发控制( MVCC , Multiversion Concurrency Control )机制解决了该问题。

Serializable (可串行化)

这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

这四种隔离级别采取不同的锁类型来实现,若读取的是同一个数据的话,就容易发生问题。例如:

脏读 (Drity Read) :某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个 RollBack 了操作,则后一个事务所读取的数据就会是不正确的。

不可重复读 (Non-repeatable read): 在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。

幻读 (Phantom Read): 在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列 (Row) 数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。

事务传播级别

数据库事务传播级别,指的是事务嵌套时,应该采用什么策略,即在一个事务中调用别的事务,该怎么办

假如有一下两个事务:

ServiceA  {   
         void  methodA ()   {   
         ServiceB . methodB ();   
      }   
   
}   
   
ServiceB  {   
      void  methodB ()   {   
      }     
}

1 : PROPAGATION_REQUIRED

加入当前正要执行的事务不在另外一个事务里,那么就起一个新的事务

比如说, ServiceB.methodB 的事务级别定义为 PROPAGATION_REQUIRED, 那么由于执行 ServiceA.methodA 的时候,

ServiceA.methodA 已经起了事务,这时调用 ServiceB.methodB ,ServiceB.methodB 看到自己已经运行在 ServiceA.methodA

的事务内部,就不再起新的事务。而假如 ServiceA.methodA 运行的时候发现自己没有在事务中,他就会为自己分配一个事务。

这样,在 ServiceA.methodA 或者在 ServiceB.methodB 内的任何地方出现异常,事务都会被回滚。即使 ServiceB.methodB 的事务已经被

提交,但是 ServiceA.methodA 在接下来 fail 要回滚, ServiceB.methodB 也要回滚

2 : PROPAGATION_SUPPORTS

如果当前在事务中,即以事务的形式运行,如果当前不再一个事务中,那么就以非事务的形式运行

3 : PROPAGATION_MANDATORY

必须在一个事务中运行。也就是说,他只能被一个父事务调用。否则,他就要抛出异常

4 : PROPAGATION_REQUIRES_NEW

这个就比较绕口了。 比如我们设计 ServiceA.methodA 的事务级别为PROPAGATION_REQUIRED , ServiceB.methodB 的事务级别为PROPAGATION_REQUIRES_NEW ,

那么当执行到 ServiceB.methodB 的时候, ServiceA.methodA 所在的事务就会挂起, ServiceB.methodB 会起一个新的事务,等待 ServiceB.methodB 的事务完成以后,

他才继续执行。他与 PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。因为 ServiceB.methodB 是新起一个事务,那么就是存在

两个不同的事务。如果 ServiceB.methodB 已经提交,那么 ServiceA.methodA 失败回滚, ServiceB.methodB 是不会回滚的。如果 ServiceB.methodB 失败回滚,

如果他抛出的异常被 ServiceA.methodA 捕获, ServiceA.methodA 事务仍然可能提交。

5 : PROPAGATION_NOT_SUPPORTED

当前不支持事务。比如 ServiceA.methodA 的事务级别是PROPAGATION_REQUIRED ,而 ServiceB.methodB 的事务级别是PROPAGATION_NOT_SUPPORTED ,

那么当执行到 ServiceB.methodB 时, ServiceA.methodA 的事务挂起,而他以非事务的状态运行完,再继续 ServiceA.methodA 的事务。

6 : PROPAGATION_NEVER

不能在事务中运行。假设 ServiceA.methodA 的事务级别是PROPAGATION_REQUIRED , 而 ServiceB.methodB 的事务级别是PROPAGATION_NEVER ,

那么 ServiceB.methodB 就要抛出异常了。

7 : PROPAGATION_NESTED

理解 Nested 的关键是 savepoint 。他与 PROPAGATION_REQUIRES_NEW 的区别是, PROPAGATION_REQUIRES_NEW 另起一个事务,将会与他的父事务相互独立,

而 Nested 的事务和他的父事务是相依的,他的提交是要等和他的父事务一块提交的。也就是说,如果父事务最后回滚,他也要回滚的。

而 Nested 事务的好处是他有一个 savepoint 。

行级锁

如果有两个事务 A,B 都有 read 和 write 操作,如果逻辑是如果表中没有记录则插入,那么因为 read 操作并没有加锁, A , B 进行 read 操作时,有可能表中都没有记录,那么事务 A,B 都会进行插入操作,表中将会有两条记录。

如果要保证在事务并发时,每条事务读取到的数据都是最新的,那么只能采用锁。

在 select 语句后加上 FOR UPDATE ,再测试,重复提交的问题被解决了。

但是问题又来了,如果在 select 语句后加上 LOCK IN SHARE MODE ,那么会报死锁的错误。

查看 mysql 文档:

    • SELECT ... LOCK IN SHARE MODE sets a shared mode lock on any rows that are read. Other sessions can read the rows, but cannot modify them until your transaction commits. If any of these rows were changed by another transaction that has not yet committed, your query waits until that transaction ends and then uses the latest values.
    • SELECT ... FOR UPDATE   sets an exclusive lock on the rows read. An exclusive lock prevents other sessions from accessing the rows for reading or writing.

      LOCK IN SHARE MODE 会在读取的行上加共享锁 ,其他 session 只能读不能修改或删除,如果有其他事务修改了记录,那么会等待事务提交后,再读取。

      FOR UPDATE 在读取行上设置一个排他锁 。阻止其他 session 读取或者写入行数据

      这样看起来似乎就能解释为什么使用 LOCK IN SHARE MODE 会产生死锁了,假如两个事务 A 、 B 都读取同一行记录,那么在这一行就加上了共享锁,但是 A 和B 事务中都需要修改这一行,那么都要等待对方释放共享锁才能进行,结果造成了死锁。

      只能使用 for update 来防止死锁和重复插入。

      这就是 mysql 的两种行级锁的区别。

Mysql事务及行级锁的更多相关文章

  1. Mysql事务及行级锁的理解

    在最近的开发中,碰到一个需求签到,每个用户每天只能签到一次,那么怎么去判断某个用户当天是否签到呢?因为当属表设计的时候,每个用户签到一次,即向表中插入一条记录,根据记录的数量和时间来判断用户当天是否签 ...

  2. [数据库事务与锁]详解五: MySQL中的行级锁,表级锁,页级锁

    注明: 本文转载自http://www.hollischuang.com/archives/914 在计算机科学中,锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的 ...

  3. 【数据库】数据库的锁机制,MySQL中的行级锁,表级锁,页级锁

    转载:http://www.hollischuang.com/archives/914 数据库的读现象浅析中介绍过,在并发访问情况下,可能会出现脏读.不可重复读和幻读等读现象,为了应对这些问题,主流数 ...

  4. MySQL中的行级锁,表级锁,页级锁

    在计算机科学中,锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的满足. 在数据库的锁机制中介绍过,在DBMS中,可以按照锁的粒度把数据库锁分为行级锁(INNODB引 ...

  5. 【转】MySQL中的行级锁,表级锁,页级锁

    在计算机科学中,锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的满足. 在数据库的锁机制中介绍过,在DBMS中,可以按照锁的粒度把数据库锁分为行级锁(INNODB引 ...

  6. 转 MySQL中的行级锁,表级锁,页级锁

      对mysql乐观锁.悲观锁.共享锁.排它锁.行锁.表锁概念的理解 转载. https://blog.csdn.net/puhaiyang/article/details/72284702 实验环境 ...

  7. 详述 MySQL 中的行级锁、表级锁和页级锁

    转自:https://blog.csdn.net/qq_35246620/article/details/69943011 refer:cnblogs.com/f-ck-need-u/p/899547 ...

  8. Mysql的事务及行级锁

    转自:http://www.cnblogs.com/edwinchen/p/4171866.html 以签到为例,每个用户每天只能签到一次,那么怎么去判断某个用户当天是否签到呢?因为当初表设计的时候, ...

  9. mysql 行级锁的使用以及死锁的预防

    一.前言 mysql的InnoDB,支持事务和行级锁,可以使用行锁来处理用户提现等业务.使用mysql锁的时候有时候会出现死锁,要做好死锁的预防. 二.MySQL行级锁 行级锁又分共享锁和排他锁. 共 ...

随机推荐

  1. Javascript实现简单的选项卡

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/u011043843/article/details/30723933 在线演示:http://jsf ...

  2. Unite 2018 | 《崩坏3》:在Unity中实现高品质的卡通渲染(下)

    http://forum.china.unity3d.com/thread-32273-1-1.html 今天我们继续分享米哈游技术总监贺甲在Unite Beijing 2018大会上的演讲<在 ...

  3. 异常处理--Exception(一)

    很诱人的标题,今天不是给大家介绍,而是跟大家讨论些问题. 在做开发的这几年中,大大小小的项目也经历了很多,但无论那个项目中,都没有真正的对Exception进行完整的处理.虽然我们在学C#的时候,经常 ...

  4. getpwuid()

    getpwuid函数是通过用户的uid查找用户的passwd数据.如果出错时,它们都返回一个空指针并设置errno的值,用户可以根据perror函数查看出错的信息. 外文名 getpwuid() 头文 ...

  5. angular-ui-bootstrap的弹出框定义成一个服务的实践(二)

    定义一个弹出框的服务:alert_box defiine(["app"],function(mainapp){ mainapp.controller('ModalInstanceC ...

  6. jq 合并json对象

    一,保存object1和2合并后产生新对象,若2中有与1相同的key,默认2将会覆盖1的值 1 var object = $.extend({}, object1, object2); 二,将2的值合 ...

  7. linux下echo命令详解

    linux的echo命令, 在shell编程中极为常用, 在终端下打印变量value的时候也是常常用到的, 因此有必要了解下echo的用法 例如: echo $JAVA_HOME /export/se ...

  8. 关于git rebase的相关讲解

    http://gitbook.liuhui998.com/4_2.html 一.基本 git rebase用于把一个分支的修改合并到当前分支. 假设你现在基于远程分支"origin" ...

  9. hive默认分隔符引起的日志分割问题

    Hive中的外部表 对于Hive中的外部表来说,因为表是外部的,Hive认为其并不拥有这份数据,删除该表并不会真正删除其中的数据,其中的表描述元信息会被删除掉.   对数据进行分区后,对于管理表,可以 ...

  10. 第三章:Hadoop简介及配置Hadoop-1.2.1,hbase-0.94.13集群

    前面给大家讲了怎么安装Hadoop,肯定会有人还是很迷茫,装完以后原来就是这个样子,但是怎么用,下面,先给大家讲下Hadoop简介:大致理解下就OK了 hadoop是一个平台,提供了庞大的存储和并行计 ...