热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

数据库中的事务与死锁

文章目录前言一、乐观锁与悲观锁1.1乐观锁1.2悲观锁1.3如何实现乐观锁悲观锁1.4乐观锁和悲观锁选择标准二、共享锁和排它锁2.1共享锁(读锁)2.2


文章目录

    • 前言
    • 一、乐观锁与悲观锁
      • 1.1 乐观锁
      • 1.2 悲观锁
      • 1.3 如何实现乐观锁/悲观锁
      • 1.4 乐观锁和悲观锁选择标准
    • 二、共享锁和排它锁
      • 2.1 共享锁(读锁)
      • 2.2 排它锁(写锁)
    • 三、加锁的粒度
      • 3.1 表锁
      • 3.2 页锁
      • 3.3 行锁
    • 四、事务
      • 4.1 事务
        • 4.1.1 用于保证数据库的一致性
        • 4.1.2 用于保证数据库的完整性
      • 4.2 事务的ACID特性
      • 4.3 隔离级别
        • 4.3.1 READ UNCOMMITED(未提交读)
        • 4.3.2 READ COMMITED(提交读)
        • 4.3.3 REPEATABLE READ (可重复读)
        • 4.3.4 SERIALIZABLE (可串行化读)
      • 4.4 不同隔离级别带来的并发问题
        • 4.4.1 脏读:
        • 4.4.2 不可重复读
        • 4.4.3 幻读
    • 五、加锁协议
      • 5.1 一次封锁协议
      • 5.2 两段锁协议
    • 六、死锁
      • 6.1 出现死锁的原因:
      • 6.2 如何避免死锁?
      • 6.3 如何预防死锁?
    • 七、InnoDB 中事务隔离性的实现:
      • 7.1 MVCC的实现
      • 7.2 InnoDB中的MVCC
      • 7.3 “快照读”与“当前读”区别
      • 7.4 InnoDB 中 Serializable 的隔离性实现


前言

并发控制: 事务和锁的存在都是为了更好的解决并发访问造成的数据不一致性的的问题


一、乐观锁与悲观锁

乐观锁和悲观锁都是为了解决并发控制问题;
乐观锁可以认为是一种在最后提交的时候检测冲突的手段;
而悲观锁则是一种避免冲突的手段。


1.1 乐观锁


  1. 什么是乐观锁
    是应用系统层面和数据的业务逻辑层次上的,利用程序处理并发,它假定当某一个用户去读取某一个数据时,其他的用户不会来访问修改这个数据,但在最后进行事务的提交的时候会进行版本的检查,以判断在该用户的操作过程中,没有其他用户修改了这个数据。开销比较小

  2. 实现方式
    乐观锁的实现大部分都是基于版本控制实现, 此外,还可通过时间戳方式,通过提前读取,事后对比方式实现 。如mysql里添加版本version字段来控制

    UPDATE price_versionSET front = #{front,jdbcType=DECIMAL},version= version + 1WHERE id = #{id,jdbcType=INTEGER}

  3. 乐观锁的优势和劣势

    1. 优势:如果数据库记录始终处于悲观锁加锁状态,面对几百上千个并发,要不断的加锁减锁,且用户等待的时间会非常的长, 乐观锁机制避免了长事务中的数据库加锁解锁开销,大大提升了大并发量下的系统整体性能表现,所以如果系统的并发非常大=,悲观锁定会带来非常大的性能问题,建议就要选择乐观锁定的方法, 而如果并发量不大,完全可用悲观锁定的方法。乐观锁也适合于读较多的场景。
    2. 劣势: 乐观锁也存在问题,只能在提交数据时才发现业务事务将要失败,如果系统冲突非常多,且一旦冲突就要因为重新计算提交而造成较大的代价,乐观锁也会带来很大的问题,在某些情况下,发现失败太迟的代价会非常的大。且乐观锁也无法解决脏读的问题

1.2 悲观锁


  1. 什么是悲观锁?
    完全依赖数据库锁的机制实现,在数据库中可用Repeatable Read的隔离级别(可重复读)实现悲观锁它认为当某一用户读取某一数据时,其他用户也会对该数据进行访问,所以在读取时就对数据加锁, 在该用户读取数据的期间,其他任何用户都不能来修改该数据,但其他用户可读取该数据, 只有当自己读取完毕才释放锁。

  2. 悲观锁的优势和劣势
    劣势:开销较大,且加锁时间较长,对于并发的访问性支持不好。
    优势 : 能避免冲突的发生,


1.3 如何实现乐观锁/悲观锁

以hibernate为例,可通过为记录添加版本或时间戳字段来实现乐观锁,一旦发现出现冲突了,修改失败就要通过事务进行回滚。可用session.Lock()锁定对象来实现悲观锁(本质是执行SELECT * FROM t FOR UPDATE语句)


1.4 乐观锁和悲观锁选择标准

乐观锁和悲观所各有优缺点,在乐观锁和悲观锁之间进行选择的标准是:


  • 发生冲突的频率与严重性。
  • 如果冲突很少,或者冲突的后果不会很严重,那么通常情况下应该选择乐观锁,因为它能得到更好的并发性,而且更容易实现。
  • 如果冲突太多或者冲突的结果对于用户来说痛苦的,那么就需要使用悲观策略,它能避免冲突的发生。 如果要求能够支持高并发,那么乐观锁。
    其实使用乐观锁 高并发==高冲突, 看看你怎么衡量了。

但现在大多数源代码开发者更倾向于使用乐观锁策略


二、共享锁和排它锁

共享锁和排它锁是具体的锁,是数据库机制上的锁。


2.1 共享锁(读锁)

共享锁(读锁) 在同一个时间段内,多个用户可读取同一个资源,读取过程中数据不发生任何变化。读锁间是相互不阻塞的, 多个用户可同时读,但不允许有人修改, 任何事务都不允许获得数据上的排它锁,直到数据上释放掉所有的共享锁


2.2 排它锁(写锁)

排它锁(写锁) 在任何时候只能有一个用户写入资源,当进行写锁时会阻塞其他读锁或写锁操作,只能由这一个用户来写,其他用户既不能读也不能写。


三、加锁的粒度

加锁会有粒度问题,从粒度上从大到小可以划分为


3.1 表锁

开销较小,一旦有用户访问这个表就会加锁,其他用户就不能对这个表操作了,应用程序的访问请求遇到锁等待的可能性比较高。


3.2 页锁

MySQL中较独特的一种锁定级别,锁定颗粒度介于行级锁定与表级锁间,所以获取锁定所需要的资源开销,及所能提供的并发处理能力也同样是介于上面二者间。另外,页级锁定和行级锁定一样,会发生死锁。


3.3 行锁

开销较大,能具体锁定到表中的某行数据,能更好的支持并发处理, 会发生死锁


四、事务


4.1 事务


4.1.1 用于保证数据库的一致性

所谓数据一致性,就是当多个用户试图同时访问一个数据库,它们的事务同时使用相同的数据时,可能会发生以下四种情况:


  • 丢失更新、
  • 脏读、
  • 不可重复读
  • 幻读


4.1.2 用于保证数据库的完整性

所谓数据完整性,数据库中的数据是从外界输入的,而数据的输入由于种种原因,会发生输入无效或错误信息。保证输入的数据符合规定,
数据完整性分为四类:


  • 实体完整性(Entity Integrity)、
  • 域完整性(Domain Integrity)、
  • 参照完整性(Referential Integrity)、
  • 用户定义的完整性(User-definedIntegrity)。

数据库采用多种方法来保证数据完整性,包括外键、约束、规则和触发器。


4.2 事务的ACID特性


  • 原子性Automicity,一个事务内的所有操作,要么全做,要么全不做
  • 一致性Consistency,数据库从一个一致性状态转到另一个一致性状态
  • 独立性(隔离性)isolation, 一个事务在执行期间,对于其他事务来说是不可见的
  • 持久性(Durability): 事务一旦成功提交,则就会永久性的对数据库进行了修改


4.3 隔离级别

在SQL 中定义了四种隔离级别


4.3.1 READ UNCOMMITED(未提交读)

READ UNCOMMITED(未提交读) 事务间的数据是相互可见的


4.3.2 READ COMMITED(提交读)

READ COMMITED(提交读) 大多数数据库的默认隔离级别, 保证了不可能脏读,但不能保证可重复读, 在这个级别里,数据的加锁实现是读取都是不加锁的,但数据的写入、修改和删除是要加锁的。


4.3.3 REPEATABLE READ (可重复读)

REPEATABLE READ (可重复读) 解决了不可重复读问题,保证在同一个事务之中,多次读取相同的记录的值的结果是一致的。 但无法解决幻读。这个阶段的事务隔离性,在mysql中是通过基于乐观锁原理的多版本控制实现的。


4.3.4 SERIALIZABLE (可串行化读)

SERIALIZABLE (可串行化读) 最高的隔离级别,解决了幻读 ,它在读取的每行数据上都加锁, 有能导致超时和锁争用的问题。
它的加锁实现是读取时加共享锁,修改删除更新时加排他锁,读写互斥,但并发能力差。


隔离级别脏读不可重复读幻读
未提交读(Read uncommitted)可能可能可能
已提交读(Read committed)不可能可能可能
可重复读(Repeatable read)不可能不可能可能
可串行化(Serializable)不可能不可能不可能

Mysql 默认的隔离级别是可重复读 。

丢失更新: 当两个或多个事务同时对某一数据进行更新时,事务B的更新可能覆盖掉事务A的更新,导致更新丢失

解决方案:


  • 悲观锁方式: 加锁,建议最后一步更新数据时加上排它锁,不要在一开始就加锁。执行到了最后一步更新,首先做加锁的查询确认数据有无改变,如没有被改变,则进行数据更新,否则失败。 一定要是做加锁的查询确认,因为如果不加锁,有可能在做确认时数据又发生了改变。
  • 乐观锁的方式:使用版本控制实现

级别高低是&#xff1a;脏读 <不可重复读 <幻读。所以&#xff0c;设了最高级别的SERIALIZABLE_READ就不用在设置REPEATABLE_READ和READ_COMMITTED了


4.4 不同隔离级别带来的并发问题


4.4.1 脏读&#xff1a;

事务可读取未提交的数据&#xff0c;如&#xff1a; 事务A对某一个数据data&#61;1000 进行了修改: data &#61; 2000, 但是还没有提交&#xff1b; 事务B读取data 得到了结果data &#61; 2000, 由于某种原因事务A撤销了刚才的操作&#xff0c;数据data &#61; 1000 然后提交 这时事务B读取到的2000就是脏数据。正确的数据应该还是 1000

解决方法 &#xff1a; 把数据库的事务隔离级别调整到READ_COMMITTED &#xff0c; 但存在事务A与B都读取了data&#xff0c;A还未完成事务&#xff0c;B此时修改了数据data&#xff0c;并提交&#xff0c; A又读取了data&#xff0c;发现data不一致了&#xff0c;出现了不可重复读。


4.4.2 不可重复读

在同一个事务之中&#xff0c;多次读取相同的记录的值的结果是不一样的&#xff0c;针对的是数据的修改和删除。
事务A 读取data &#61; 1000, 事务还未完成&#xff1b; 事务B 修改了data &#61; 2000&#xff0c; 修改完毕事务提交&#xff1b; 事务A 再次读取data, 发现data &#61; 2000 了&#xff0c;与之前的读取不一致的

解决办法; 把数据库的事务隔离级别调整到 REPEATABLE READ &#xff0c; 读取时候不允许其他事务修改该数据&#xff0c;不管数据在事务过程中读取多少次&#xff0c;数据都是一致的&#xff0c;避免了不可重复读问题


4.4.3 幻读

幻读&#xff1a; 当某个事务在读取某个范围内的记录的时候&#xff0c;另外一个事务在这个范围内增加了一行&#xff0c;当前一个事务再次读取该范围的数据的时候就会发生幻行&#xff0c;. 针对的是数据的插入insert

解决方案 &#xff1a; 采用的是范围锁 RangeS RangeS_S模式&#xff0c;锁定检索范围为只读 或者 把数据库的事务隔离级别调整到SERIALIZABLE_READ&#xff0c; MySQL中InnoDB 和 XtraDB 利用&#xff08;多版本并发控制&#xff09;解决了幻读问题&#xff0c;


五、加锁协议


5.1 一次封锁协议

因为有大量的并发访问&#xff0c;为了预防死锁&#xff0c;一般应用中推荐使用一次封锁法&#xff0c;就是在方法的开始阶段&#xff0c;已经预先知道会用到哪些数据&#xff0c;然后全部锁住&#xff0c;在方法运行之后&#xff0c;再全部解锁。这种方式可以有效的避免循环死锁&#xff0c;但在数据库中却不适用&#xff0c;因为在事务开始阶段&#xff0c;数据库并不知道会用到哪些数据。


5.2 两段锁协议

将事务分成两个阶段&#xff0c;加锁阶段和解锁阶段&#xff08;所以叫两段锁&#xff09;


  1. 加锁阶段&#xff1a;在该阶段可以进行加锁操作。在对任何数据进行读操作之前要申请并获得S锁&#xff08;共享锁&#xff0c;其它事务可以继续加共享锁&#xff0c;但不能加排它锁&#xff09;&#xff0c;在进行写操作之前要申请并获得X锁&#xff08;排它锁&#xff08;只有当前数据无共享锁&#xff0c;无排它锁之后才能获得&#xff09;&#xff0c;其它事务不能再获得任何锁&#xff09;。加锁不成功&#xff0c;则事务进入等待状态&#xff0c;直到加锁成功才继续执行。
  2. 解锁阶段&#xff1a;当事务释放了一个封锁以后&#xff0c;事务进入解锁阶段&#xff0c;在该阶段只能进行解锁操作不能再进行加锁操作。
    事务提交时&#xff08;commit&#xff09; 和事务回滚时&#xff08;rollback&#xff09;会自动的同时释放该事务所加的insert、update、delete对应的锁。

这种方式虽然无法避免死锁&#xff0c;但是两段锁协议可以保证事务的并发调度是串行化&#xff08;串行化很重要&#xff0c;尤其是在数据恢复和备份的时候&#xff09;的。


六、死锁

**指两个事务或者多个事务在同一资源上相互占用&#xff0c;并请求对方所占用的资源&#xff0c;从而造成恶性循环的现象。 **


6.1 出现死锁的原因&#xff1a;


  1. 系统资源不足
  2. 进程运行推进的顺序不当
  3. 资源分配不当
    产生死锁的四个必要条件
  4. 互斥条件&#xff1a; 一个资源只能被一个进程使用
  5. 请求和保持条件&#xff1a;进行获得一定资源&#xff0c;又对其他资源发起了请求&#xff0c;但是其他资源被其他线程占用&#xff0c;请求阻塞&#xff0c;但是也不会释放自己占用的资源。
  6. 不可剥夺条件&#xff1a; 指进程所获得的资源&#xff0c;不可能被其他进程剥夺&#xff0c;只能自己释放
  7. 环路等待条件&#xff1a; 进程发生死锁&#xff0c;必然存在着进程-资源之间的环形链
    处理死锁的方法&#xff1a; 预防&#xff0c;避免&#xff0c;检查&#xff0c;解除死锁

数据库也会发生死锁的现象&#xff0c;数据库系统实现了各种死锁检测和死锁超时机制来解除死锁&#xff0c;锁监视器进行死锁检测&#xff0c;MySQL的InnoDB处理死锁的方式是 将持有最少行级排它锁的事务进行回滚&#xff0c;相对比较简单的死锁回滚办法


6.2 如何避免死锁&#xff1f;

避免死锁的核心思想是&#xff1a;

系统对进程发出每一个资源申请进行动态检查,并根据检查结果决定是否分配资源,如果分配后系统可能发生死锁,则不予分配,否则予以分配.这是一种保证系统不进入不安全或者死锁状态的动态策略。 什么是不安全的状态&#xff1f;系统能按某种进程推进顺序( P1, P2, …, Pn)&#xff0c;为每个进程Pi分配其所需资源&#xff0c;直至满足每个进程对资源的最大需求&#xff0c;使每个进程都可顺序地完成。此时称 P1, P2, …, Pn 为安全序列。如果系统无法找到一个安全序列&#xff0c;则称系统处于不安全状态。

其实第一和第二是预防死锁的方式&#xff0c;分别对应着的是破坏循环等待条件&#xff0c;和破坏不可剥夺条件。


  • 第一&#xff1a; 加锁顺序&#xff1a; 对所有的资源加上序号&#xff0c;确保所有的线程都是按照相同的顺序获得锁&#xff0c;那么死锁就不会发生&#xff0c;比如有资源 A&#xff0c; B&#xff0c;规定所有的线程只能按照A–B的方式获取资源&#xff0c; 这样就不会发生 线程1持有A&#xff0c;请求B&#xff0c;线程2持有B请求A的死锁情况发生了
  • 第二&#xff1a; 获取锁的时候加一个超时时间&#xff0c;这也就意味着在尝试获取锁的过程中若超过了这个时限该线程则放弃对该锁请求&#xff0c;同时放弃掉自己已经成功获得的所有资源的锁&#xff0c;然后等待一段随机的时间再重试。这段随机的等待时间让其它线程有机会尝试获取相同的这些锁&#xff0c;并且让该应用在没有获得锁的时候可以继续运行。
  • 第三&#xff1a;死锁的提前检测&#xff0c; 很出名的就是银行家算法。 每当一个线程获得了锁&#xff0c;会存储在线程和锁相关的数据结构中&#xff08;map、graph等等&#xff09;将其记下。除此之外&#xff0c;每当有线程请求锁&#xff0c;也需要记录在这个数据结构中&#xff0c;当一个线程请求锁失败时&#xff0c;这个线程可以遍历锁的关系图看看是否有死锁发生。

银行家算法&#xff1a;

思想&#xff1a; 当进程首次申请资源时&#xff0c;要测试该进程对资源的最大需求量&#xff0c;如果系统现存的资源可以满足它的最大需求量则按当前的申请量分配资源&#xff0c;否则就推迟分配。当进程在执行中继续申请资源时&#xff0c;先测试该进程已占用的资源数与本次申请的资源数之和是否超过了该进程对资源的最大需求量。若超过则拒绝分配资源&#xff0c;若没有超过则再测试系统现存的资源能否满足该进程尚需的最大资源量&#xff0c;若能满足则按当前的申请量分配资源&#xff0c;否则也要推迟分配


6.3 如何预防死锁&#xff1f;

主要是通过设置某些外部条件去破坏死锁产生的四个必要条件中的一个或者几个。


  • 破坏互斥条件&#xff0c;一般不采用&#xff0c;因为资源的互斥性这个特性有时候是我们所需要的&#xff1b;
  • 破坏请求和保持条件&#xff1a;可以一次性为一个进程或者线程分配它所需要的全部资源&#xff0c;这样在后面就不会发起请求资源的情况&#xff0c;但是这样资源的效率利用率很低&#xff1b;
  • 破坏不可剥夺条件&#xff1a; 当一个已保持了某些不可剥夺资源的进程&#xff0c;请求新的资源而得不到满足时&#xff0c;它必须释放已经保持的所有资源&#xff0c;待以后需要时再重新申请&#xff0c;但是释放已获得的资源可能造成前一阶段工作的失效&#xff0c;反复地申请和释放资源会增加系统开销&#xff0c;降低系统吞吐量&#xff1b;
  • 破坏循环等待条件&#xff1a; 可釆用顺序资源分配法。首先给系统中的资源编号&#xff0c;规定每个进程&#xff0c;必须按编号递增的顺序请求资源&#xff0c;同类资源一次申请完。也就是说&#xff0c;只要进程提出申请分配资源Ri&#xff0c;则该进程在以后的资源申请中&#xff0c;只能申请编号大于Ri的资源。
    但是这样的话&#xff0c;编号必须相对稳定&#xff0c;这就限制了新类型设备的增加&#xff1b;尽管在为资源编号时已考虑到大多数作业实际使用这些资源的顺序&#xff0c;但也经常会发生作业使甩资源的顺序与系统规定顺序不同的情况&#xff0c;造成资源的浪费&#xff1b;此外&#xff0c;这种按规定次序申请资源的方法&#xff0c;也必然会给用户的编程带来麻烦

七、InnoDB 中事务隔离性的实现&#xff1a;

READ COMMITED 和 REPEATABLE READ 的隔离性实现&#xff1a;MVCC


7.1 MVCC的实现

MVCC&#xff08;多版本控制系统&#xff09;的实现&#xff08;目的&#xff1a; 实现更好的并发&#xff0c;可以使得大部分的读操作不用加锁&#xff0c; 但是insert&#xff0c;delete&#xff0c;update是需要加锁的&#xff09;&#xff1a;
MVCC 只在 READ COMMITED 和 REPEATABLE READ 这两个事务隔离性级别中使用。这是因为MVCC 和其他两个不兼容&#xff0c;READ UNCOMMITED 总是读取最新的行&#xff0c;不关事务&#xff0c; 而Seriablizable则会对每一个读都加共享锁。


7.2 InnoDB中的MVCC

在InnoDB中&#xff0c;会在每行数据后添加两个额外的隐藏的值来实现MVCC&#xff0c;这两个值一个记录这行数据何时被创建&#xff0c;另外一个记录这行数据何时过期&#xff08;即何时被删除&#xff09;。 在实际操作中&#xff0c;存储的并不是时间&#xff0c;而是系统的版本号&#xff0c;每开启一个新事务&#xff0c;系统的版本号就会递增。
通过MVCC&#xff0c;虽然每行记录都需要额外的存储空间&#xff0c;更多的行检查工作以及一些额外的维护工作&#xff0c;但可以减少锁的使用&#xff0c;大多数读操作都不用加锁&#xff0c;读数据操作很简单&#xff0c;性能很好&#xff0c;并且也能保证只会读取到符合标准的行&#xff0c;也只锁住必要行。
select &#xff08;不加锁&#xff09;&#xff1a; 满足两个条件的结果才会被返回&#xff1a;


  1. 创建版本号<&#61; 当前事务版本号&#xff0c;小于意味着在该事务之前没有其他事务对其进行修改&#xff0c;等于意味着事务自身对其进行了修改&#xff1b;
  2. 删除版本号 > 当前事务版本号 意味着删除操作是在当前事务之后进行的&#xff0c;或者删除版本未定义&#xff0c;意味着这一行只是进行了插入&#xff0c;还没有删除过。
    INSERT &#xff1b; 为新插入的每一行保存当前事务的版本号作为创建版本号
    DELETE &#xff1b; 为删除的行保存当前事务的版本号为删除版本号
    UPDATE&#xff1b; 为修改的每一行保存当前事务的版本号作为创建版本号

7.3 “快照读”与“当前读”区别

MySQL中的读&#xff0c;和事务隔离级别中的读&#xff0c;是不一样的&#xff0c; 在REPEATABLE READ 级别中&#xff0c;通过MVCC机制&#xff0c;虽然让数据变得可重复读&#xff0c;但我们读到的数据可能是历史数据&#xff0c;是不及时的数据&#xff08;存储在缓存等地方的数据&#xff09;&#xff0c;不是数据库当前的数据&#xff01;这在一些对于数据的时效特别敏感的业务中&#xff0c;就很可能出问题。


  • 快照读 (snapshot read)&#xff1a;读取历史数据&#xff08;缓存数据&#xff09;的方式。
  • 当前读 (current read)&#xff1a;读取数据库当前版本数据的方式。

在MVCC中&#xff1a;


  • 快照读就是select &#xff0c;是不加锁的&#xff0c; 在REPEATABLE READ 和READ COMMITED 级别中 select语句不加锁。
    select * from table ….;

  • 当前读&#xff1a;插入/更新/删除操作&#xff0c;属于当前读&#xff0c;处理的都是当前的数据&#xff0c;需要加锁。

    select * from table where ? lock in share mode;
    select * from table where ? for update;
    insert;
    update ;
    delete;

事务的隔离级别实际上都是定义了当前读的级别&#xff0c;MySQL为了减少锁处理&#xff08;包括等待其它锁&#xff09;的时间&#xff0c;提升并发能力&#xff0c;引入了快照读的概念&#xff0c;使得select不用加锁。而update、insert这些“当前读”&#xff0c;就需要另外的模块来解决了。&#xff08;这是因为update、insert的时候肯定要读取数据库中的值来与当前事务要写入的值进行对比&#xff0c;看看在该事务所处理的数据在这一段时间内有没有被其他事务所操作&#xff08;就是先读取数据库中数据的版本号与当前的版本号做检查&#xff09;&#xff09;

为了解决当前读中的幻读问题&#xff0c;MySQL事务使用了Next-Key锁。Next-Key锁是行锁和GAP&#xff08;间隙锁&#xff09;的合并 GAP&#xff08;间隙锁&#xff09;就是在两个数据行之间进行加锁&#xff0c;防止插入操作

行锁防止别的事务修改或删除&#xff0c;解决了数据不可重复读的问题&#xff0c;GAP锁防止别的事务新增&#xff0c;行锁和GAP锁结合形成的的Next-Key锁共同解决了RR级别在读数据时的幻读问题


7.4 InnoDB 中 Serializable 的隔离性实现

Serializable级别使用的是悲观锁的理论&#xff0c; 读加共享锁&#xff0c;写加排他锁&#xff0c;读写互斥&#xff0c; 在Serializable这个级别&#xff0c;select语句还是会加锁的。

https://blog.csdn.net/woshiluoye9/article/details/68954515


推荐阅读
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文介绍了如何在MySQL中将零值替换为先前的非零值的方法,包括使用内联查询和更新查询。同时还提供了选择正确值的方法。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 本文详细介绍了MySQL表分区的创建、增加和删除方法,包括查看分区数据量和全库数据量的方法。欢迎大家阅读并给予点评。 ... [详细]
  • mysql-cluster集群sql节点高可用keepalived的故障处理过程
    本文描述了mysql-cluster集群sql节点高可用keepalived的故障处理过程,包括故障发生时间、故障描述、故障分析等内容。根据keepalived的日志分析,发现bogus VRRP packet received on eth0 !!!等错误信息,进而导致vip地址失效,使得mysql-cluster的api无法访问。针对这个问题,本文提供了相应的解决方案。 ... [详细]
  • javascript  – 概述在Firefox上无法正常工作
    我试图提出一些自定义大纲,以达到一些Web可访问性建议.但我不能用Firefox制作.这就是它在Chrome上的外观:而那个图标实际上是一个锚点.在Firefox上,它只概述了整个 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 本文详细介绍了在ASP.NET中获取插入记录的ID的几种方法,包括使用SCOPE_IDENTITY()和IDENT_CURRENT()函数,以及通过ExecuteReader方法执行SQL语句获取ID的步骤。同时,还提供了使用这些方法的示例代码和注意事项。对于需要获取表中最后一个插入操作所产生的ID或马上使用刚插入的新记录ID的开发者来说,本文提供了一些有用的技巧和建议。 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
author-avatar
mobiledu2402851323
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有