热门标签 | 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


推荐阅读
  • PTArchiver工作原理详解与应用分析
    PTArchiver工作原理及其应用分析本文详细解析了PTArchiver的工作机制,探讨了其在数据归档和管理中的应用。PTArchiver通过高效的压缩算法和灵活的存储策略,实现了对大规模数据的高效管理和长期保存。文章还介绍了其在企业级数据备份、历史数据迁移等场景中的实际应用案例,为用户提供了实用的操作建议和技术支持。 ... [详细]
  • 本文详细介绍了数据库并发控制的基本概念、重要性和具体实现方法。并发控制是确保多个事务在同时操作数据库时保持数据一致性的关键机制。文章涵盖了锁机制、多版本并发控制(MVCC)、乐观并发控制和悲观并发控制等内容。 ... [详细]
  • php更新数据库字段的函数是,php更新数据库字段的函数是 ... [详细]
  • 本文总结了一些开发中常见的问题及其解决方案,包括特性过滤器的使用、NuGet程序集版本冲突、线程存储、溢出检查、ThreadPool的最大线程数设置、Redis使用中的问题以及Task.Result和Task.GetAwaiter().GetResult()的区别。 ... [详细]
  • 本文详细介绍了MySQL数据库的基础语法与核心操作,涵盖从基础概念到具体应用的多个方面。首先,文章从基础知识入手,逐步深入到创建和修改数据表的操作。接着,详细讲解了如何进行数据的插入、更新与删除。在查询部分,不仅介绍了DISTINCT和LIMIT的使用方法,还探讨了排序、过滤和通配符的应用。此外,文章还涵盖了计算字段以及多种函数的使用,包括文本处理、日期和时间处理及数值处理等。通过这些内容,读者可以全面掌握MySQL数据库的核心操作技巧。 ... [详细]
  • 在什么情况下MySQL的可重复读隔离级别会导致幻读现象? ... [详细]
  • MySQL Decimal 类型的最大值解析及其在数据处理中的应用艺术
    在关系型数据库中,表的设计与SQL语句的编写对性能的影响至关重要,甚至可占到90%以上。本文将重点探讨MySQL中Decimal类型的最大值及其在数据处理中的应用技巧,通过实例分析和优化建议,帮助读者深入理解并掌握这一重要知识点。 ... [详细]
  • C# 中 SQLite 报错:在 "\\s\\" 附近出现语法错误,如何解决? ... [详细]
  • 在软件开发过程中,经常需要将多个项目或模块进行集成和调试,尤其是当项目依赖于第三方开源库(如Cordova、CocoaPods)时。本文介绍了如何在Xcode中高效地进行多项目联合调试,分享了一些实用的技巧和最佳实践,帮助开发者解决常见的调试难题,提高开发效率。 ... [详细]
  • 在使用 Cacti 进行监控时,发现已运行的转码机未产生流量,导致 Cacti 监控界面显示该转码机处于宕机状态。进一步检查 Cacti 日志,发现数据库中存在 SQL 查询失败的问题,错误代码为 145。此问题可能是由于数据库表损坏或索引失效所致,建议对相关表进行修复操作以恢复监控功能。 ... [详细]
  • 如何将TS文件转换为M3U8直播流:HLS与M3U8格式详解
    在视频传输领域,MP4虽然常见,但在直播场景中直接使用MP4格式存在诸多问题。例如,MP4文件的头部信息(如ftyp、moov)较大,导致初始加载时间较长,影响用户体验。相比之下,HLS(HTTP Live Streaming)协议及其M3U8格式更具优势。HLS通过将视频切分成多个小片段,并生成一个M3U8播放列表文件,实现低延迟和高稳定性。本文详细介绍了如何将TS文件转换为M3U8直播流,包括技术原理和具体操作步骤,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 在HTML布局中,即使将 `top: 0%` 和 `left: 0%` 设置为元素的定位属性,浏览器中仍然会出现空白填充。这个问题通常与默认的浏览器样式、盒模型或父元素的定位方式有关。为了消除这些空白,可以考虑重置浏览器的默认样式,确保父元素的定位方式正确,并检查是否有其他CSS规则影响了元素的位置。 ... [详细]
  • Python错误重试让多少开发者头疼?高效解决方案出炉
    ### 优化后的摘要在处理 Python 开发中的错误重试问题时,许多开发者常常感到困扰。为了应对这一挑战,`tenacity` 库提供了一种高效的解决方案。首先,通过 `pip install tenacity` 安装该库。使用时,可以通过简单的规则配置重试策略。例如,可以设置多个重试条件,使用 `|`(或)和 `&`(与)操作符组合不同的参数,从而实现灵活的错误重试机制。此外,`tenacity` 还支持自定义等待时间、重试次数和异常处理,为开发者提供了强大的工具来提高代码的健壮性和可靠性。 ... [详细]
  • 本文详细介绍了在MySQL中如何高效利用EXPLAIN命令进行查询优化。通过实例解析和步骤说明,文章旨在帮助读者深入理解EXPLAIN命令的工作原理及其在性能调优中的应用,内容通俗易懂且结构清晰,适合各水平的数据库管理员和技术人员参考学习。 ... [详细]
  • 在对WordPress Duplicator插件0.4.4版本的安全评估中,发现其存在跨站脚本(XSS)攻击漏洞。此漏洞可能被利用进行恶意操作,建议用户及时更新至最新版本以确保系统安全。测试方法仅限于安全研究和教学目的,使用时需自行承担风险。漏洞编号:HTB23162。 ... [详细]
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社区 版权所有