当前位置:首页 > java知识学习_java技术文章 > 正文

mysql和java中的悲观锁与乐观锁原理实现图解

浏览405+

一、悲观锁与乐观锁的定义介绍

悲观锁按字面意来看就是很悲观的意思,当别人获取数据的时候总是认为别人会篡改数据,因此不管查询还是修改都会上锁,别人想要操作只能等待,一个用户拿到悲观锁后,其他任何事务都不能对该数据进行修改,直到释放锁才能拿到锁进行操作。

悲观锁示意图

悲观锁是一种并发控制的方法,以牺牲效率保证并发的安全做法,mysql数据库层面悲观锁的实现依赖其数据库底层的锁机制确保排它的数据访问。

乐观锁跟悲观锁刚好相反,遇事比较乐观,习惯性的认为别人拿数据时不会对数据做修改操作,故不会上锁,它允许多个事务同时对数据进行变动,但是别人一旦想要对数据进行修改,乐观锁就会判断一下最初的数据是不是被别人修改了,若没有修改则执行操作,若数据改动则直接返回不做任何操作。

乐观锁示意图

乐观锁的实现思路多基于版本号或者时间戳字段来实现,类似于java并发编程中的cas,悲观锁可以由mysql数据库自己控制,而乐观锁则是由程序员代码控制。

二、悲观锁与乐观锁的优缺点与区别

悲观锁和乐观锁都有着它各自的优点和缺点,不能单纯地直接说哪一种更好,它们都是有各自的应用场景的。

乐观锁的优点与应用场景

乐观锁更加适合没有冲突或冲突很少发生并且读多写少的情况,乐观锁不是对数据库直接加锁,而是修改数据时做检验比对工作,此种场景下,乐观锁可以减少锁的系统开销节省时间成本,对系统的吞吐量有很大的提升作用。

乐观锁的缺点

乐观锁的缺点就是会增加业务系统的复杂性,乐观锁需要程序员手动编写代码实现,既会增加工作量又会对外来事务的操作产生不确定性的影响,它只适合本系统的事务操作。

如果将A变量首先读取为A,则其值将更改为B,然后再更改为A,则CAS操作将假定它从未更改过,这就是乐观锁常见的aba问题,J.U.C软件包提供了一个引用类AtomicStampedReference,它携带标记并且执行原子操作,它通过版本的变化来解决此问题。

悲观锁的优点与应用场景

如果在冲突频发的情况下,乐观锁就会不断地尝试做自旋操作,不断地开启重试机制,这将大大的直线降低程序的性能,因此在这种情况下,悲观锁是合适的。

悲观锁的缺点

悲观锁属于重量级锁,在java中像乐观锁这种轻量级的锁要比重量级锁优越,悲观锁直接带来线程间的阻塞问题,直接加锁对数据库的开销严重,这直接导致高并发下只能串行操作,不能并行操作,性能偏低。

三、mysql数据库中的悲观锁原理图解与代码实现

为了便于大家对乐观锁和悲观锁有一个清晰的透彻的原理的理解,我们现在来假设一个场景,假设是小a和小b两个人最近都想买零食肉干儿吃,假设他们两个找的是同一家商店,而此时他们两个又在同一时间进行下单。

肉干商品表

上图商品表中显示此时这家商店的肉干数量只剩下一包,我们看一下应用悲观锁的具体解决方案。

悲观锁的实现思路:

用户小A他查了一下该商品数量,肉干的的数量为1,他快速的对该表加上了行锁,然后再来进行购买,此时小B发现该行数据加了锁然后就只能等待中,小A购买完成数量扣减为0,然后释放锁,小B开始购买,发现肉干的数量已经变为0了,结果购买失败,具体加锁原理见下图:

悲观锁加锁原理示意图

mysql悲观锁加锁代码实现:

小A操作mysql命令,执行begin操作开启事务,然后加上悲观锁,代码如下:

mysql悲观锁加锁命令

与此同时,小B也进行加锁,发现晚了一步,只能进行等待中,等待对方释放锁后进行操作,见下图:

mysql等待释放锁命令

然后小A执行商品扣减命令,购买成功,提交事务操作,查询商品数量以变为0,代码如下图:

mysql执行扣减命令

此时小A操作完成,已经释放了锁,小B结束了等待,执行查询加锁的任务,发现为时已晚,数量已经变为了0,只能放弃购买。

事务小B尝试加锁图

四、java中的乐观锁原理图解与代码实现

java乐观锁实现思路详解:

前面提到过,乐观锁主要采用版本号或时间戳完成,还是采用上面购买肉干的案例,我们给商品表添加一个version版本字段,如下图:

添加了版本字段的商品表结构

改变数据表之后,假设还是小A和小B同时购买肉干,同时查询该商品表,此时小A将查到的数据版本为0和id为1作为乐观锁判断的条件, 购买成功后扣减数量1并增加版本号,版本号变为1,A现在已完成商品的购买。

然后,B开始购买,小B将查到的数据版本为0和id为1作为乐观锁判断的条件,然后购买更新数据,结果更新失败,发现版本已经变为了1,表明数据被别人修改了,操作失败,具体参见以下乐观锁原理详解图示:

乐观锁原理图

java乐观锁代码实现:

mysql命令行执行查询商品表命令代码如下:

商品查询代码图示

小A执行购买商品命令,扣减商品数量修改版本号成功,命令代码如下:

小A更新商品和版本号命令

小A执行成功,小B执行更新商品数据和更新版本,代码如下:

小B执行商品扣减命令

以上图示可以看出,小B的执行命令失败,原版本0已经变为了1,说明数据已经被小A修改过了。

 

相关文章推荐

乐观锁和悲观锁的定义

悲观锁和乐观锁的区别,怎么实现

并发控制中的乐观锁与悲观锁

Mysql系列进步一: MySQL 实现乐观锁和悲观锁

悲观锁实现

Redis锁机制处理高并发

什么是悲观锁和乐观锁?

MySql悲观锁和乐观锁的使用

mysql数据库悲观锁 -帮助文档

 

责任声明:文章信息由IT教程屋小编精心整理总结编排而成,倾注了心血和汗水,转载时请遵循行业规范务必注明文章作者、来源及本页链接,谢谢合作!
本篇文章标题:mysql和java中的悲观锁与乐观锁原理实现图解
本篇文章url地址:http://www.itjcw123.cn/2459.html