极速快3_快3信誉网_极速快3信誉网 - 极速快3,快3信誉网,极速快3信誉网是一个基于本地城市资讯管理的应用,里面汇集了所在城市最热门的民生资讯和便民服务功能,想知道你的家乡发生了什么,打开极速快3,快3信誉网,极速快3信誉网尽在掌握!

[数据库锁机制] 深入理解乐观锁、悲观锁以及CAS乐观锁的实现机制原理分析

  • 时间:
  • 浏览:0

前言:

  • 在并发访问清况 下,是因为分析会经常出现 脏读、不可重复读和幻读等读问題报告 ,为了应对有有哪些问題报告 ,主流数据库都提供了锁机制,并引入了事务隔离级别的概念。数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务一起存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。
  • 乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。无论是悲观锁还是乐观锁,总要大伙儿儿定义出来的概念,可以认为是三种思想。虽然不仅仅是关系型数据库系统所含乐观锁和悲观锁的概念,像memcache、hibernate、tair等总要同类 的概念。
  • 本文中也将深入分析一下乐观锁的实现机制,介绍有哪些是CAS、CAS的应用以及CAS发生的问題报告 等。

并发控制

在计算机科学,有点是系统进程设计、操作系统、多补救机和数据库等领域,并发控制(Concurrency control)是确保及时纠正由并发操作是因为的错误的三种机制。

数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务一起存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。下面举例说明并发操作带来的数据不一致性问題报告 :

现有两处火车票售票点,一起读取某一趟列车车票数据库中车票余额为 X。两处售票点一起卖出一张车票,一起修改余额为 X -1写回数据库,什么都 就造成了实际卖出两张火车票而数据库中的记录却只少了一张。 产生你这些 清况 的是因为是是因为分析三个白 事务读入同一数据并一起修改,其中三个白 事务提交的结果破坏了什么都 事务提交的结果,是因为其数据的修改被丢失,破坏了事务的隔离性。并发控制要补救的什么都 同类 问題报告 。

封锁、时间戳、乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。

一、数据库的锁

当并发事务一起访问三个白 资源时,有是因为分析是因为数据不一致,什么都 需用三种机制来将数据访问顺序化,以保证数据库数据的一致性。锁什么都 其中的三种机制。

在计算机科学中,锁是在执行系统进程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的满足。

锁的分类(oracle)

一、按操作划分,可分为DML锁DDL锁

二、按锁的粒度划分,可分为表级锁行级锁页级锁(mysql)

三、按锁级别划分,可分为共享锁排他锁

四、按加锁方法 划分,可分为自动锁显示锁

五、按使用方法 划分,可分为乐观锁悲观锁

DML锁(data locks,数据锁),用于保护数据的删改性,其中包括行级锁(Row Locks (TX锁))、表级锁(table lock(TM锁))。

DDL锁(dictionary locks,数据字典锁),用于保护数据库对象的形态学 ,如表、索引等的形态学 定义。其中包排他DDL锁(Exclusive DDL lock)、共享DDL锁(Share DDL lock)、可中断解析锁(Breakable parse locks)

1.1 锁机制

常用的锁机制有三种:

1、悲观锁:假定会发生并发冲突,屏蔽一切是因为分析违反数据删改性的操作。悲观锁的实现,往往依靠底层提供的锁机制;悲观锁会是因为其它所有需用锁的系统进程挂起,在等待持有锁的系统进程释放锁。

2、乐观锁:假设还会发生并发冲突,每次不加锁什么都 假设没有 冲突而去完成某项操作,只在提交操作时检查与否违反数据删改性。是因为分析是因为分析冲突失败就重试,直到成功为止。乐观锁大多是基于数据版本记录机制实现。为数据增加三个白 版本标识,比如在基于数据库表的版本补救方案中,一般是通过为数据库表增加三个白 “version” 字段来实现。读取出数据时,将此版本号一起读出,以后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,是因为分析提交的数据版本号大于数据库表当前版本号,则予以更新,什么都 认为是过期数据。 

乐观锁的缺点是不到补救要素脏读的问題报告 ,同类 ABA问題报告 (下面会讲到)。

在实际生产环境后面 ,是因为分析并发量不大且不允许脏读,可以使用悲观锁补救并发问題报告 ;但是因为分析系统的并发非常大句子,悲观锁定会带来非常大的性能问題报告 ,什么都大伙儿儿就要选用乐观锁定的方法 。

二、悲观锁与乐观锁详解

2.1 悲观锁

在关系数据库管理系统里,悲观并发控制(叫华“悲观锁”,Pessimistic Concurrency Control,缩写“PCC”)是三种并发控制的方法 。它可以阻止三个白 事务以影响一些用户的方法 来修改数据。是因为分析三个白 事务执行的操作都某行数据应用了锁,那不到当你这些 事务把锁释放,一些事务才并能执行与该锁冲突的操作。

悲观并发控制主要用于数据争用激烈的环境,以及发生并发冲突时使用锁保护数据的成本要低于回滚事务的成本的环境中。

悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的一些事务,以及来自结构系统的事务补救)修改持保守态度(悲观),什么都 ,在整个数据补救过程中,将数据发生锁定清况 。 悲观锁的实现,往往依靠数据库提供的锁机制 (也不到数据库层提供的锁机制并能真正保证数据访问的排他性,什么都 ,即使在本系统中实现了加锁机制,也无法保证结构系统还会修改数据)

在数据库中,悲观锁的流程如下:

在对任意记录进行修改前,先尝试为该记录加带排他锁(exclusive locking)。

是因为分析加锁失败,说明该记录正在被修改,没有 当前查询是因为分析要在等待是因为分析抛出异常。 具体响应方法 由开发者根据实际需用决定。

是因为分析成功加锁,没有 就可以对记录做修改,事务完成后就会解锁了。

其间是因为分析有一些对该记录做修改或加排他锁的操作,总要在等待大伙儿儿解锁或直接抛出异常。

MySQL InnoDB中使用悲观锁:

要使用悲观锁,大伙儿儿需用关闭mysql数据库的自动提交属性,是因为分析MySQL默认使用autocommit模式,也什么都 说,当你执行三个白 更新操作后,MySQL会立刻将结果进行提交。set autocommit=0;

//0.以后开始事务
begin;/begin work;/start transaction; (三者选一就可以)
//1.查询出商品信息
select status from t_goods where id=1 for update;
//2.根据商品信息生成订单
insert into t_orders (id,goods_id) values (null,1);
//3.修改商品status为2
update t_goods set status=2;
//4.提交事务
commit;/commit work;

后面 的查询句子中,大伙儿儿使用了select…for update的方法 ,什么都 就通过开启排他锁的方法 实现了悲观锁。此时在t_goods表中,id为1的 那条数据就被大伙儿儿锁定了,其它的事务需用等本次事务提交以后并能执行。什么都 大伙儿儿可以保证当前的数据还会被其它事务修改。

后面 大伙儿儿提到,使用select…for update会把数据给锁住,不过大伙儿儿需用注意一些锁的级别,MySQL InnoDB默认行级锁。行级锁总要基于索引的,是因为分析一根绳子 SQL句子用不到索引是还会使用行级锁的,会使用表级锁把整张表锁住,这点需用注意。

优点与缺陷

悲观并发控制实际上是“先取锁再访问”的保守策略,为数据补救的安全提供了保证。什么都 在速率方面,补救加锁的机制会让数据库产生额外的开销,还有增加产生死锁的是因为分析;另外,在只读型事务补救中是因为分析还会产生冲突,也没必要使用锁,什么都 做不到增加系统负载;还有会降低了并行性,三个白 事务是因为分析锁定了某行数据,一些事务就需用在等待该事务补救完才可以补救那行数

2.2 乐观锁

在关系数据库管理系统里,乐观并发控制(叫华“乐观锁”,Optimistic Concurrency Control,缩写“OCC”)是三种并发控制的方法 。它假设多用户并发的事务在补救时还会彼此互相影响,各事务并能在不产生锁的清况 下补救个人影响的那要素数据。在提交数据更新以后,每个事务会先检查在该事务读取数据后,有没有 一些事务又修改了该数据。是因为分析一些事务有更新句子,正在提交的事务会进行回滚。乐观事务控制最早是由孔祥重(H.T.Kung)教授提出。

乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般清况 下还会造成冲突,什么都在数据进行提交更新的以后,才会正式对数据的冲突与否进行检测,是因为分析发现冲突了,则让返回用户错误的信息,让用户决定怎样才能去做。

相对于悲观锁,在对数据库进行补救的以后,乐观锁还会会使用数据库提供的锁机制。一般的实现乐观锁的方法 什么都 记录数据版本。

数据版本,为数据增加的三个白 版本标识。当读取数据时,将版本标识的值一起读出,数据每更新一次,一起对版本标识进行更新。当大伙儿儿提交更新的以后,判断数据库表对应记录的当前版本信息与第一次取出来的版本标识进行比对,是因为分析数据库表当前版本号与第一次取出来的版本标识值相等,则予以更新,什么都 认为是过期数据。

实现数据版本有三种方法 ,第三种是使用版本号,第二种是使用时间戳。

使用版本号实现乐观锁

使用版本号时,可以在数据初始化时指定三个白 版本号,每次对数据的更新操作都对版本号执行+1操作。并判断当前版本号是总要该数据的最新的版本号。

1.查询出商品信息
select (status,status,version) from t_goods where id=#{id}
2.根据商品信息生成订单
3.修改商品status为2
update t_goods 
set status=2,version=version+1
where id=#{id} and version=#{version};

优点与缺陷

乐观并发控制相信事务之间的数据竞争(data race)的概率是比较小的,什么都 尽是因为分析直接做下去,直到提交的以后才去锁定,什么都还会产生任何锁和死锁。但是因为分析直接简单没有 做,还是有是因为分析会遇到不可预期的结果,同类 三个白 事务都读取了数据库的某一行,经过修改以后写回数据库,这时就遇到了问題报告 。

三、CAS详解

在说CAS以后,大伙儿儿不得不提一下Java的系统进程安全问題报告 。

系统进程安全:

众所周知,Java是系统进程的。什么都 ,Java对系统进程的支持虽然是一把双刃剑。一旦涉及到多个系统进程操作共享资源的清况 时,补救不好就是因为分析产生系统进程安全问題报告 。系统进程安全性是因为分析是非常冗杂的,在没有 富有的同步的清况 下,多个系统进程中的操作执行顺序是不可预测的。

Java后面 进行系统进程通信的主要方法 什么都 共享内存的方法 ,共享内存主要的关注点有三个白 :可见性和有序性。加带复合操作的原子性,大伙儿儿可以认为Java的系统进程安全性问題报告 主要关注点有五个:可见性、有序性和原子性。

Java内存模型(JMM)补救了可见性和有序性的问題报告 ,而锁补救了原子性的问題报告 。这里不再删改介绍JMM及锁的一些相关知识。什么都 大伙儿儿要讨论三个白 问題报告 ,那什么都 锁到底是总要有利无弊的?

3.1 锁发生的问題报告

Java在JDK1.5以后总要靠synchronized关键字保证同步的,你这些 通过使用一致的锁定协议来协调对共享清况 的访问,可以确保无论哪个系统进程持有共享变量的锁,都采用独占的方法 来访问有有哪些变量。独占锁虽然什么都 三种悲观锁,什么都可以说synchronized是悲观锁。

悲观锁机制发生以下问題报告 :

1) 在系统进程竞争下,加锁、释放锁会是因为比较多的上下文切换和调度延时,引起性能问題报告 。

2) 三个白 系统进程持有锁会是因为其它所有需用此锁的系统进程挂起。

3) 是因为分析三个白 优先级高的系统进程在等待三个白 优先级低的系统进程释放锁会是因为优先级倒置,引起性能风险。

而什么都 更加有效的锁什么都 乐观锁。所谓乐观锁什么都 ,每次不加锁什么都 假设没有 冲突而去完成某项操作,是因为分析是因为分析冲突失败就重试,直到成功为止。

与锁相比,volatile变量是三个白 更轻量级的同步机制,是因为分析在使用有有哪些变量时还会发生上下文切换和系统进程调度等操作,什么都 volatile不到补救原子性问題报告 ,什么都 当三个白 变量依赖旧值时就不到使用volatile变量。什么都 对于同步最终还是要回到锁机制上来。

乐观锁

乐观锁( Optimistic Locking)虽然是三种思想。相对悲观锁而言,乐观锁假设认为数据一般清况 下还会造成冲突,什么都在数据进行提交更新的以后,才会正式对数据的冲突与否进行检测,是因为分析发现冲突了,则让返回用户错误的信息,让用户决定怎样才能去做。

后面 提到的乐观锁的概念中虽然是因为分析阐述了他的具体实现细节:

主要什么都 三个白 步骤:冲突检测数据更新

虽然现方法 有三种比较典型的什么都 Compare and Swap(CAS)。

3.2 CAS

CAS是项乐观锁技术,当多个系统进程尝试使用CAS一起更新同三个白 变量时,不到其中三个白 系统进程能更新变量的值,而其它系统进程都失败,失败的系统进程还会会被挂起,什么都 被告知这次竞争中失败,并可以再次尝试。

CAS 操作所含三个白 操作数 —— 内存位置(V)、预期原值(A)和新值(B)。是因为分析内存位置的值与预期原值相匹配,没有 补救器会自动将该位置值更新为新值。什么都 ,补救器不做任何操作。无论哪种清况 ,它总要在 CAS 指令以后返回该位置的值。(在 CAS 的一些特殊清况 下将仅返回 CAS 与否成功,而不提取当前值。)CAS 有效地说明了“我认为位置 V 应该所含值 A;是因为分析所含该值,则将 B 倒入你这些 位置;什么都 ,还会更改该位置,只真不知道你这些 位置现在的值即可。”这虽然和乐观锁的冲突检查+数据更新的原理是一样的。

这里再强调一下,乐观锁是三种思想。CAS是你这些 思想的三种实现方法 。

3.3 Java对CAS的支持

JDK 5以后Java语言是靠synchronized关键字保证同步的,这是三种独占锁,也是是悲观锁。j在JDK1.5 中新增java.util.concurrent(J.U.C)什么都 建立在CAS之上的。相对于对于synchronized你这些 阻塞算法,CAS是非阻塞算法的三种常见实现。什么都J.U.C在性能上有了很大的提升。

现代的CPU提供了特殊的指令,允许算法执行读-修改-写操作,而还会害怕一些系统进程一起修改变量,是因为分析是因为分析一些系统进程修改变量,没有 CAS会检测它(并失败),算法可以对该操作重新计算。而 compareAndSet() 就用有有哪些代替了锁定。

大伙儿儿以java.util.concurrent中的AtomicInteger为例,看一下在没有 锁的清况 下是怎样才能保证系统进程安全的。主要理解getAndIncrement方法 ,该方法 的作用为宜 ++i 操作。

public class AtomicInteger extends Number implements java.io.Serializable {
    
    private volatile int value;
    
    public final int get() {
        return value;
    }
    
    public final int getAndIncrement() {
        for (;;) {
            int current = get();
            int next = current + 1;
            if (compareAndSet(current, next))
                return current;
        }
    }
    
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

字段value需用借助volatile原语,保证系统进程间的数据是可见的(共享的)。什么都 在获取变量的值的以后并能直接读取。什么都 来看看++i是为啥做到的。getAndIncrement采用了CAS操作,每次从内存中读取数据什么都 将此数据和+1后的结果进行CAS操作,是因为分析成功就返回结果,什么都 重试直到成功为止。而compareAndSet利用JNI来完成CPU指令的操作。

public final boolean compareAndSet(int expect, int update) {   
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
 }

整体的过程什么都 什么都 子的,利用CPU的CAS指令,一起借助JNI来完成Java的非阻塞算法。其它原子操作总要利用同类 的形态学 完成的。

而整个J.U.C总要建立在CAS之上的,什么都 对于synchronized阻塞算法,J.U.C在性能上有了很大的提升。

3.4 CAS会是因为“ABA问題报告 ”:

ABA问題报告 :

aba实际上是乐观锁无法补救脏数据读取的三种体现。CAS算法实现三个白 重要前提需用取出内存中某时刻的数据,而在下时刻比较并替换,没有 在你这些 时间差类会是因为数据的变化。

比如说三个白 系统进程one从内存位置V中取出A,这以后什么都 系统进程two也从内存中取出A,什么都 two进行了一些操作变成了B,什么都 two又将V位置的数据变成A,这以后系统进程one进行CAS操作发现内存中仍然是A,什么都 one操作成功。尽管系统进程one的CAS操作成功,什么都 不代表你这些 过程什么都 没有 问題报告 的。

要素乐观锁的实现是通过版本号(version)的方法 来补救ABA问題报告 ,乐观锁每次在执行数据的修改操作时,总要带上三个白 版本号,一旦版本号和数据的版本号一致就可以执行修改操作并对版本号执行+1操作,什么都 就执行失败。是因为分析每次操作的版本号总要随之增加,什么都还会经常出现 ABA问題报告 ,是因为分析版本号只会增加还会减少。

 是因为分析链表的头在变化了两次后恢复了原值,什么都 不代表链表就没有 变化。什么都 AtomicStampedReference/AtomicMarkableReference就很有用了。

AtomicMarkableReference 类描述的三个白 <Object,Boolean>的对,可以原子的修改Object是因为分析Boolean的值,你这些 数据形态学 在一些缓存是因为分析清况 描述中比较有用。你这些 形态学 在单个是因为分析一起修改Object/Boolean的以后并能有效的提高吞吐量。 



AtomicStampedReference 类维护所含整数“标志”的对象引用,可以用原子方法 对其进行更新。对比AtomicMarkableReference 类的<Object,Boolean>,AtomicStampedReference 维护的是三种同类 <Object,int>的数据形态学 ,虽然什么都 对对象(引用)的三个白 并发计数(标记版本戳stamp)。什么都 与AtomicInteger 不同的是,此数据形态学 可以携带三个白 对象引用(Object),什么都 并能对此对象和计数一起进行原子操作。

REFERENCE:

收集自以下博客:

1.  http://www.hollischuang.com/archives/934

2.  http://www.hollischuang.com/archives/1537

3.  http://www.cnblogs.com/Mainz/p/3546347.html

4.  http://www.digpage.com/lock.html

5.  https://chenzhou123520.iteye.com/blog/1863407

6.  https://chenzhou123520.iteye.com/blog/18150954