悲观锁

悲观锁(Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。

悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。

Java synchronized 就属于悲观锁的一种实现,每次线程要修改数据时都先获得锁,保证同一时刻只有一个线程能操作数据,其他线程则会被block。

悲观锁

乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。乐观锁适用于读多写少的应用场景,这样可以提高吞吐量

乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性

乐观锁一般来说有以下2种方式:

使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据。

使用时间戳(timestamp)。乐观锁定的第二种实现方式和第一种差不多,同样是在需要乐观锁控制的table中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp), 和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。

Java JUC中的atomic包就是乐观锁的一种实现,AtomicInteger 通过CAS(Compare And Set)操作实现线程安全的自增。

MySQL InnoDB采用的是两阶段锁定协议(two-phase locking protocol)。在事务执行过程中,随时都可以执行锁定,锁只有在执行 COMMIT或者ROLLBACK的时候才会释放,并且所有的锁是在同一时刻被释放。前面描述的锁定都是隐式锁定,InnoDB会根据事务隔离级别在需要的时候自动加锁。

另外,InnoDB也支持通过特定的语句进行显示锁定,这些语句不属于SQL规范:

SELECT ... LOCK IN SHARE MODE

SELECT ... FOR UPDATE

案例

通过一个小案例展示乐观锁和悲观锁的使用

考虑电商秒杀系统中,如果保证商品不超买,要保证数据的一致性

假设一张商品表

create table tb_product(

id int not null auto_increment primary key,

stock int not null

)ENGINE=InnoDB DEFAULT CHARSET=utf8

在不考虑并发的情况下,修改商品库存的伪代码如下:

/**

* 更新库存(不考虑并发)

* @param productId

* @return

*/

public boolean updateStockRaw(Long productId){

ProductStock product = query("SELECT * FROM tb_product WHERE id=#{productId}", productId);

if (product.getNumber() > 0) {

int updateCnt = update("UPDATE tb_product SET stock=stock-1 WHERE id=#{productId}", productId);

if(updateCnt > 0){ //更新库存成功

return true;

}

}

return false;

}

但是这种方式在多线程并发的情况下可能会出现超卖问题。

下面演示使用悲观锁和乐观锁来解决这个问题。

使用悲观锁

/**

* 更新库存(使用悲观锁)

* @param productId

* @return

*/

public boolean updateStock(Long productId){

//先锁定商品库存记录

ProductStock product = query("SELECT * FROM tb_product WHERE id=#{productId} FOR UPDATE", productId);

if (product.getNumber() > 0) {

int updateCnt = update("UPDATE tb_product SET stock=stock-1 WHERE id=#{productId}", productId);

if(updateCnt > 0){ //更新库存成功

return true;

}

}

return false;

}

使用乐观锁

/**

* 下单减库存

* @param productId

* @return

*/

public boolean updateStock(Long productId){

int updateCnt = 0;

while (updateCnt == 0) {

ProductStock product = query("SELECT * FROM tb_product WHERE product_id=#{productId}", productId);

if (product.getNumber() > 0) {

updateCnt = update("UPDATE tb_product SET stock=stock-1 WHERE product_id=#{productId} AND number=#{number}", productId, product.getNumber());

if(updateCnt > 0){ //更新库存成功

return true;

}

} else { //卖完啦

return false;

}

}

return false;

}

mysql悲观锁和乐观使用实例_MySQL 悲观锁和乐观锁相关推荐

  1. mysql proxy 悲观锁_mysql悲观锁总结和实践

    使用场景举例:以MySQL InnoDB为例 商品t_goods表中有一个字段status,status为1代表商品未被下单,status为2代表商品已经被下单,那么我们对某个商品下单时必须确保该商品 ...

  2. mysql实现悲观锁_mysql 悲观锁详解

    悲观锁指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态.悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层 ...

  3. mysql悲观锁的应用_mysql悲观锁

    悲观锁与乐观锁是两种常见的资源并发锁设计思路,也是并发编程中一个很是基础的概念.mysql 悲观锁(Pessimistic Lock) 悲观锁的特色是先获取锁,再进行业务操做,即"悲观&qu ...

  4. mysql悲观锁会有脏数据吗_mysql悲观锁原理详解

    mysql中的锁概念 mysql已经成为大家日常数据存储的最常用平台,但随着业务量和访问量的上涨,会出现并发访问等场景,如果处理不好并发问题的话会带来严重困扰.下面介绍一下如何通过mysql的悲观锁来 ...

  5. mysql实现悲观锁语句_mysql悲观锁总结和实践

    使用场景举例:以MySQL InnoDB为例 商品t_goods表中有一个字段status,status为1代表商品未被下单,status为2代表商品已经被下单,那么我们对某个商品下单时必须确保该商品 ...

  6. mysql事务处理是悲观锁还是_数据库事务的悲观锁和乐观锁

    转载出处:http://www.hollischuang.com/archives/934 在数据库的锁机制中介绍过,数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数 ...

  7. mysql读写分离主从原理、事务隔离级别及使用、锁表和锁行场景、乐观锁和悲观锁、lock锁和sychronized区别及使用自己学习之后总结和参考一些博客感觉系统了解了

    synchronized与Lock的区别 两者区别: 1.首先synchronized是java内置关键字,在jvm层面,Lock是个java类: 2.synchronized无法判断是否获取锁的状态 ...

  8. mysql如何加悲观锁_MySQL悲观锁

    悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态.悲观锁的实现,往往依靠数据库提供的锁机制( ...

  9. mysql实现悲观锁_mysql悲观锁怎么实现?

    mysql悲观锁的方法:1.首先利用[select ... for update]加锁,操作完成后使用commit来释放锁:然后innodb引擎来默认行级锁:最后查不到数据时,则不锁表即可. mysq ...

  10. mysql版本号锁_MySQL使用版本号实现乐观锁

    乐观锁适用于读多写少的应用场景 乐观锁Version图示 Project Directory Maven Dependency 1 <?xml version="1.0" e ...

最新文章

  1. 阿里副总裁、达摩院自动驾驶负责人王刚离职,将开启创业之路
  2. Oracle RAC删除节点
  3. java方法重载编程_学java教程之普通方法重载
  4. 设置修改CentOS系统时区
  5. 002_推箱子-关卡数据
  6. pycharm 运行程序时提示错误信息:ModuleNotFoundError: No module named 'pytest' 解决方法
  7. Java怎么学?在学Java的过程中要注意些什么呢?
  8. Spark入门(三)Idea构建spark项目
  9. linux用vfork创建进程,[Linux进程]使用vfork创建子进程并且执行命令
  10. (转) 学习淘淘商城第一课
  11. 我儿子竟跟男孩子抱在一起
  12. 如何给CSDN博客添加个人微信二维码或自定义栏目
  13. 新颖性搜索(Novelty Search,NS)算法详解与实现
  14. 数据结构与算法c语言版胡明课后答案,算法设计与分析(第2版) 王红梅 胡明 习题答案...
  15. Fxfactory插件:光雾滤镜插件PHYX Stylist
  16. java验证身份证号码的合格性
  17. BootstrapTable 表格 checkbox 和 显示行号
  18. tp5 php 使用array_column函数方法 记录集数组取值(取得某个元素的值)
  19. 高通平台DDR3初始化
  20. CnOpenData中国上市公司公告数据简介

热门文章

  1. 不确定性原理的前世今生 · 数学篇(三)
  2. 【MTSP】基于matlab灰狼算法求解多旅行商问题(同始终点)【含Matlab源码 1564期】
  3. 【TWVRP】基于matalb蚁群算法求解带时间窗的车辆路径规划问题【含Matlab源码 1406期】
  4. 【DCVRP】基于matlab蚁群算法求解带容量+距离的车辆路径规划问题【含Matlab源码 1038期】
  5. 【优化充电】基于matlab多种遗传算法求解电动汽车有序充电优化问题【含Matlab源码 792期】
  6. 【路径规划】基于matlab粒子群融合遗传算法栅格地图路径规划【含Matlab源码 526期】
  7. list add java_list.add()和list.addAll()的区别
  8. python3自动化软件发布系统_PythonPC客户端自动化实现原理(pywinauto)
  9. 从头实现linux操作系统_从头开始实现您的第一个人工神经元
  10. linux ssh x11,ssh服务器的x11 forwarding报错的解决