乐观锁

乐观锁与悲观锁的简单区别

最后都变了- 提交于 2019-12-05 21:50:40
乐观锁和悲观锁都是用于解决并发场景下的数据竞争问题,但是却是两种完全不同的思想。它们的使用非常广泛,也不局限于某种编程语言或数据库。 乐观锁的概念 所谓的乐观锁,指的是在操作数据的时候非常乐观,乐观地认为别人不会同时修改数据,因此乐观锁不会上锁,只有在执行更新的时候才会去判断在此期间别人是否修改了数据,如果别人修改了数据则放弃操作,否则执行操作。 悲观锁的概念 所谓的悲观锁,指的是在操作数据的时候比较悲观,悲观地认为别人一定会同时修改数据,因此悲观锁在操作数据时是直接把数据上锁,直到操作完成之后才会释放锁,在上锁期间其他人不能操作数据。 乐观锁的实现方式 乐观锁的实现方式主要有两种,一种是CAS(Compare and Swap,比较并交换)机制,一种是版本号机制。 CAS机制 CAS操作包括了三个操作数,分别是需要读取的内存位置(V)、进行比较的预期值(A)和拟写入的新值(B),操作逻辑是,如果内存位置V的值等于预期值A,则将该位置更新为新值B,否则不进行操作。另外,许多CAS操作都是自旋的,意思就是,如果操作不成功,就会一直重试,直到操作成功为止。 版本号机制 版本号机制的基本思路,是在数据中增加一个version字段用来表示该数据的版本号,每当数据被修改版本号就会加1。当某个线程查询数据的时候,会将该数据的版本号一起读取出来,之后在该线程需要更新该数据的时候

使用乐观锁实现电商下单问题?

天大地大妈咪最大 提交于 2019-12-05 14:34:42
一. 乐观锁 乐观锁并不是真实存在的锁,而是在更新的时候判断此时的库存是否是之前查询出的库存,如果相同,表示没人修改,可以更新库存,否则表示别人抢过资源,不再执行库存更新。类似如下操作。 # sql实现语句update tb_apple set stock=2 where id=1 and stock=7;# djano中ORM实现语句 apple.objects.filter(id=1, stock=7).update(stock=2) 二.乐观锁下单逻辑 第一步 : 下单逻辑 def create(self, validated_data): """ 保存订单 """ # 获取当前下单用户 user = self.context['request'].user # 组织订单编号 20170903153611+user.id # timezone.now() -> datetime order_id = timezone.now().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id) address = validated_data['address'] pay_method = validated_data['pay_method'] # 生成订单 with transaction.atomic(): # 创建一个保存点 save_id

乐观锁的幂等性方案

允我心安 提交于 2019-12-05 13:37:35
那么为了使用乐观锁,我们首先修改t_goods表, 增加一个version字段,数据默认version值为1 。 乐观锁方案 借鉴数据库的乐观锁机制,如: update t_goods set count = count -1 , version = version + 1 where good_id=#{id} and version = 1 根据version版本,也就是在操作库存前先获取当前商品的version版本号,然后操作的时候带上此version号。我们梳理下,我们第一次操作库存时,得到version为1,调用库存服务version变成了2;但返回给订单服务出现了问题,订单服务又一次发起调用库存服务,当订单服务传如的version还是1,再执行上面的sql语句时,就不会执行;因为version已经变为2了,where条件就不成立。这样就保证了不管调用几次,只会真正的处理一次。 来源: https://www.cnblogs.com/leeego-123/p/11925852.html

redis 事务(悲观锁和乐观锁)

坚强是说给别人听的谎言 提交于 2019-12-04 21:11:54
MUTI   开启事务,后续的命令会被加入到同一个事务中   事务中的操作会发送给客服端,但是不会立即执行,而是将操作放到了该事务对应的一个队列中,服务端返回QUEQUD EXEC   执行EXEC后,事务中的命令才会执行   事务中的命令出错时,不会回滚也不会停止,而是继续执行下一步操作 DISCARD   取消事务,事务队列会被清空 原子性:不支持,不会回滚, 隔离性:支持,事务中的命令顺序,不会被打断 持久性:不支持 一致性:不支持,要求通过乐观锁watch来实现 乐观锁:watch   redis实现乐观锁机制   机制:开启事务前,设置对数据的监听,EXEXC时,如果发生数据发生过修改,事务会自动取消(DISCARD)   事务EXEC后,无论成败,监听会被移除 示例代码: 悲观锁:    来源: https://www.cnblogs.com/wjun0/p/11884240.html

乐观锁和悲观锁

倾然丶 夕夏残阳落幕 提交于 2019-12-03 09:26:16
一、乐观锁: 1. 总是假设最好的情况,进行业务操作的时候不加锁 2. 只有在更新操作时,才回去判断数据是否被别的线程更新过 3. 适合读操作比较多的场景,提高系统吞吐量;写操作比较多的场景会降低性能 4. 实现方式 a. 版本号或者时间戳:表里多加一列作为标记,先读取标记,更新的时候也更新标记,如果发现版本号不是刚才读取的数据,说明被其他线程更新过,做异常处理 b. CAS:无锁编程,但会有ABA问题 二、悲观锁: 1. 总是假设最坏的情况,每次操作数据的时候,都会假设别的线程会修改数据,就先获取锁,再进行业务操作 2. 读数据的情况也加锁,系统吞吐量比较低;适合写操作比较多的场景 3. 关系型数据库实现:行锁、表锁、读锁、写锁 4. Java实现:synchronized、Lock 参考: https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484911&idx=1&sn=1d53616437f50b353e33edad6fda2e4f&source=41#wechat_redirect 来源: https://www.cnblogs.com/june0816/p/10029425.html

悲观锁 和 乐观锁

梦想的初衷 提交于 2019-12-03 04:46:48
悲观锁(Pessimistic Lock), 顾名思义,就是 对数据的一致性 很悲观,每次去拿数据 (无论是读数据还是写数据) 的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型 数据库 里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。 乐观锁(Optimistic Lock), 顾名思义,就是 对数据的一致性 很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁 适用于多读 的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。 两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于 写比较少 ,读比较多 的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适 ,即 更新数据 比较频繁的应该用悲观所. 来源: oschina 链接: https://my.oschina.net/u/2459446/blog/703995

公平锁,非公平锁,乐观锁,悲观锁

匿名 (未验证) 提交于 2019-12-03 00:32:02
公平锁/非公平锁(多线程执行顺序的维度) 概念理解 公平锁:加锁前先查看是否有排队等待的线程,有的话优先处理排在前面的线程, 先来先得 。 非公平所:线程加锁时 直接尝试获取锁 ,获取不到就自动到队尾等待。 例子 ReentrantLock 同时支持两种锁 // 创建一个非公平锁,默认是非公平锁 Lock nonFairLock = new ReentrantLock(); Lock nonFairLock = new ReentrantLock( false ); // 创建一个公平锁,构造传参true Lock fairLock = new ReentrantLock( true ); 适用场景 更多的是直接使用非公平锁:非公平锁比公平锁性能高5-10倍,因为公平锁需要在多核情况下维护一个队列,如果当前线程不是队列的第一个无法获取锁,增加了线程切换次数。 乐观锁/悲观锁(多线程操作共享数据的维度) 概念理解 悲观锁: 假设一定会发生并发冲突 ,通过阻塞其他所有线程来保证数据的完整性。 乐观锁: 假设不会发生并发冲突 ,直接不加锁去完成某项更新,如果冲突就返回失败。 例子 悲观锁: Synchronized 多线程同步,具有排他性,也会容易产生死锁。 乐观锁: CAS 机制,简单来说会有三个操作数,当前内存变量值V,变量预期值A,即将更新值B,当需要更新变量的时候

悲观乐观锁

匿名 (未验证) 提交于 2019-12-03 00:26:01
1. 悲观锁 悲观锁介绍(百科): 悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。 使用场景举例 :以MySQL InnoDB为例 商品goods表中有一个字段status,status为1代表商品未被下单,status为2代表商品已经被下单,那么我们对某个商品下单时必须确保该商品status为1。假设商品的id为1。 1如果不采用锁,那么操作方法如下: //1.查询出商品信息 select status from t_goods where id=1; //2.根据商品信息生成订单 insert into t_orders (id,goods_id) values (null,1); //3.修改商品status为2 update t_goods set status=2; 上面这种场景在高并发访问的情况下很可能会出现问题。 前面已经提到,只有当goods status为1时才能对该商品下单,上面第一步操作中,查询出来的商品status为1。但是当我们执行第三步Update操作的时候

乐观锁的实现

匿名 (未验证) 提交于 2019-12-03 00:15:02
乐观锁介绍: 乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。那么我们如何实现乐观锁呢,一般来说有以下2种方式: 1.使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据。用下面的一张图来说明: 如上图所示,如果更新操作顺序执行,则数据的版本(version)依次递增,不会产生冲突。但是如果发生有不同的业务操作对同一版本的数据进行修改,那么,先提交的操作(图中B)会把数据version更新为2,当A在B之后提交更新时发现数据的version已经被修改了,那么A的更新操作会失败。 2.乐观锁定的第二种实现方式和第一种差不多,同样是在需要乐观锁控制的table中增加一个字段,名称无所谓

synchronized和lock

匿名 (未验证) 提交于 2019-12-03 00:11:01
类别 synchronized Lock 存在层次 Java的关键字 一个类 锁的释放 1.以获取锁的线程执行代码同步代码,释放锁。 2,线程执行发生异常,jvm会让线程释放锁 在finally中必须释放锁,不然容易造成线程死锁 锁的获取 假设A线程获得锁,B线程等待,如果A线程阻塞,则B会一直等 分情况而定,Lock有多个获取锁的方式,线程不用一直等 锁状态 无法判断 可判断 锁类型 可重入,不可中断,非公平 可重入,可判断,可公平 性能 少量同步 大量同步 1.Lock Lock的几个方法 lock() 获取锁 unlock() 释放锁 trylock() 获得锁的状态,返回true和false tryLock(long time,TimeUnit unit) 比tryLock加了时间期限 lockInterruptibly() 2. synchronized 乐观锁 ( Optimistic Locking ) 相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。而乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本( Version )记录机制实现。何谓数据版本?即为数据增加一个版本标识