Java悲观锁Pessimistic-Lock常用实现场景
1:商品库存秒杀采用悲观锁Pessimistic-Lock主要好处是安全,充分利用了数据库的性能来做的一种锁机制。
悲观锁的实现:
(1)环境:mysql + jdbctemplate
(2)商品表goods:
DROP TABLE IF EXISTS `goods`;
CREATE TABLE `goods` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(100) DEFAULT NULL COMMENT '商品名称',
`stock` int(11) unsigned NOT NULL COMMENT '商品库存',
`version` int(2) DEFAULT NULL COMMENT '版本号',
`token_time` datetime NOT NULL COMMENT '乐观锁时间戳',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8; -- ----------------------------
-- Records of goods
-- ----------------------------
BEGIN;
INSERT INTO `goods` VALUES (1, 'product', 9999, 1, '2018-11-30 22:06:20');
COMMIT; SET FOREIGN_KEY_CHECKS = 1;
(3)DAO层代码:
package org.yugh.goodsstock.pessimistic_lock.repository; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository; import javax.annotation.Resource;
import java.util.List;
import java.util.Map; /**
* @author: YuGenHai
* @name: SeckRepository
* @creation: 2018/11/28 00:30
* @notes: 悲观锁DAO层
* @notes: 悲观锁需要注意mysql自带自动commit,用行锁需要开启事务 set transation 或者set autocommit =0
* 防止自动提交,set autocommit =1 自动提交
*/
@Repository
public class PessimisticLockRepository { /**
* 测试使用 {@link JdbcTemplate}
*/
@Resource
private JdbcTemplate jdbcTemplate; /**
* 获取现有库存量
* @param id
* @return
* @author yugenhai
*/
public int queryStock(long id) {
//开启事务
String lock = "set autocommit=0";
jdbcTemplate.update(lock);
//获得当前库存 并上锁
String sql = "select * from goods where id=1 for update";
List<Map<String,Object>> list = jdbcTemplate.queryForList(sql);
if(null != list && list.size() > 0){
Map<String,Object> map = list.get(0);
System.out.println("当前库存值: "+ map.get("stock"));
return Integer.valueOf(String.valueOf(map.get("stock")));
}
return 0;
} /**
* 还有库存量,并且要释放当前锁
* @author yugenhai
* @return
*/
public int updateStock() {
String update = "update goods set stock=stock-1 where id=1";
jdbcTemplate.update(update);
String unlock = "commit";
jdbcTemplate.update(unlock);
return 1;
} /**
* 商品被抢光后需要释放
* @author yugenhai
* @return
*/
public int unlock(){
String unlock = "commit";
jdbcTemplate.update(unlock);
return 1;
} }
(4)测试悲观锁:
package org.yugh.goodsstock.pessimistic_lock; import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.yugh.goodsstock.pessimistic_lock.repository.PessimisticLockRepository; import javax.annotation.Resource; /**
* @author: YuGenHai
* @name: PessimisticLockTest
* @creation: 2018/11/28 00:32
* @notes: 悲观锁测试秒杀商品
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class PessimisticLockTest { @Resource
PessimisticLockRepository pessimisticLockRepository; /**
* STOCK库存总数,测试可以理解为购买者
* 表里的stock对应库存
*/
private static final int STOCK = 10000; /**
* 悲观锁秒杀商品
* @author yugenhai
*/
@Test
public void pessimisticLockTest() {
long beTime = System.currentTimeMillis();
for (int i = 0; i < STOCK; i++) {
//获得当前库存
//顺带上锁,开启事务
int stock = pessimisticLockRepository.queryStock(1);
if (stock > 0) {
//库存还有
//当前用户继续秒杀一个商品 并提交事务 释放锁
pessimisticLockRepository.updateStock();
System.out.println(new Thread().getName() + " 抢到了第 " + (i + 1) + " 商品");
} else {
//没有库存后释放锁
System.err.println(new Thread().getName() + " 抱歉,商品没有库存了!");
pessimisticLockRepository.unlock();
//break;
}
}
System.out.println("秒杀 "+ STOCK + " 件商品使用悲观锁需要花费时间:" + (System.currentTimeMillis() - beTime)); } }
(5)模拟10000个用户抢购9999个商品,最后一位用户没有抢到:
当前库存值: 8
Thread-9994 抢到了第 9992 商品
当前库存值: 7
Thread-9995 抢到了第 9993 商品
当前库存值: 6
Thread-9996 抢到了第 9994 商品
当前库存值: 5
Thread-9997 抢到了第 9995 商品
当前库存值: 4
Thread-9998 抢到了第 9996 商品
当前库存值: 3
Thread-9999 抢到了第 9997 商品
当前库存值: 2
Thread-10000 抢到了第 9998 商品
当前库存值: 1
Thread-10001 抢到了第 9999 商品
当前库存值: 0
秒杀 10000 件商品使用悲观锁需要花费时间:9922
Thread-10002 抱歉,商品没有库存了!
2018-12-01 00:51:06.914 INFO 9125 --- [ Thread-2] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@f0da945: startup date [Sat Dec 01 00:50:56 CST 2018]; root of context hierarchy
2018-12-01 00:51:06.915 INFO 9125 --- [ Thread-2] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2018-12-01 00:51:06.920 INFO 9125 --- [ Thread-2] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
Java悲观锁Pessimistic-Lock常用实现场景的更多相关文章
- 乐观锁(optimistic locking)与悲观锁(pessimistic locking)
首先,乐观锁(optimistic locking)与悲观锁(pessimistic locking)基本是针对数据处理来说,也就是跟数据库有关的术语,目的是为了解决并发处理时所遇到的相关性能问题,以 ...
- Java悲观锁和乐观锁
悲观的并发策略——Synchronized互斥锁 互斥锁是最常见的同步手段,在并发过程中,当多条线程对同一个共享数据竞争时,它保证共享数据同一时刻只能被一条线程使用,其他线程只有等到锁释放后才能重新进 ...
- Java 悲观锁 synchronized (member){代码块}
Java 如果遇到会出现高并发的情况,一般建议使用悲观锁 :synchronized (member){代码块} 需要对数据库进行修改或新增的时候,建议写上事务--@Transactional @T ...
- Java中的锁-悲观锁、乐观锁,公平锁、非公平锁,互斥锁、读写锁
总览图 如果文中内容有错误,欢迎指出,谢谢. 悲观锁.乐观锁 悲观锁.乐观锁使用场景是针对数据库操作来说的,是一种锁机制. 悲观锁(Pessimistic Lock):顾名思义,就是很悲观,每次去拿数 ...
- Java多线程:乐观锁、悲观锁、自旋锁
悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁.传统的关系型数据 ...
- Java乐观锁、悲观锁
乐观锁 乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号 ...
- Hibernate、乐观锁和悲观锁
悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁.传统的关系型数据 ...
- 乐观锁&悲观锁
悲观&乐观,只是对数据加锁的时机与粒度. 悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这 ...
- Hibernate乐观锁、悲观锁和多态
乐观锁和悲观锁 悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁 ...
随机推荐
- Mac iTerm2使用lrzsz上传和下载文件
Mac iTerm2使用lrzsz对服务器上传和下载文件 安装工具 首先需要安装iTerm2和homebrew,在终端中执行(打开终端,使用搜索(command + space),输入terminal ...
- Linux 勿卸载软件,所有命令不能用了咋办
1. 一次有趣的事 有个做技术的(不说什么岗位,容易被人喷,谁都有失手的时候),在公司的业务测试环境的机器,卸载了一个软件rpm -e --nodeps filesystem* , 导致机器所有的命令 ...
- 驰骋工作流引擎ccflow-ccbpm工作流引擎sdk表单装载逻辑处理注意事项
cbpm工作流引擎sdk表单装载逻辑处理注意事项 关键字:驰骋工作流引擎 sdk表单 装载接口调用 说明:如果您要采用ccbpm的sdk表单开发,在表单 加载前您需要调用一个接口来获得当前节点的信 ...
- 大数据虚拟混算平台Moonbox配置指南
一.环境准备 已安装Apache Spark 2.2.0(此版本仅支持Apache Spark 2.2.0, 其他Spark 版本后续会兼容) 已安装MySQL并启动,且开启远程访问 各安装节点已经配 ...
- golang开发:类库篇(三)命令行工具cli的使用
为什么要使用命令行 觉得这个问题不应该列出来,又觉得如果初次进行WEB开发的话,可能会觉得所有的东西都可以使用API去做,会觉得命令行没有必要. 其实,一个生产的项目命令行是绕不过去的.比如运营需要导 ...
- mybatis的example类
1. 场景描述 idea下使用mybatis_generator自动生成mapper文件,默认生成了一大堆的example文件及方法,使用规则类似于Hibernate,给了一大堆参数,感觉没必要,只所 ...
- 剑指offer第二版-10.斐波那契数列
面试题10:斐波那契数列 题目要求: 求斐波那契数列的第n项的值.f(0)=0, f(1)=1, f(n)=f(n-1)+f(n-2) n>1 思路:使用循环从下往上计算数列. 考点:考察对递归 ...
- MFC在一个工程中启动其他工程的exe文件
说明:有的时候把两个工程合并,但是偷懒不想在工程中添加代码,所以想到了这个办法,仅限偷懒哈哈哈哈 方法:新建一个主程序,在主程序的界面中添加按钮,在按钮的程序代码中添加以下语句: void CMain ...
- 【CYH-02】NOIp考砸后虐题赛:成绩:题解
这道题挺送水了吧... 两种做法. 其实空间都不需要那么大,我来提交界面一看一堆MLE的,于是还是良心的放开了时限. 这么简单,就不做解释了. 下面放出几种代码. 代码: 两个数组: #include ...
- 个人永久性免费-Excel催化剂功能第80波-按条件查找数字,扩展原生查找功能
Excel的查找替换功能,只能对文本类数据查找较为得力,若需查找数字类型的数据,如查找大于100的数字,就无能为力,此篇Excel催化剂补足其短板. Excel数据类型知识背景介绍 用好Excel,必 ...