Java悲观锁Pessimistic-Lock常用实现场景
2024-09-01 00:45:25
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.
最新文章
- Trace1:Default Trace
- LLVM 笔记(二)—— PHI node
- Thinkphp 1.验证规则 2.静态定义 3.动态验证
- xxx is not in the sudoers file.This incident will be reported.的解决方法 (一般用户不能执行sudo)
- 在c#中运行js脚本(将js文件生成为.dll文件)
- Java版本-----商店购物系统
- C#获得枚举类型的长度
- MVC4.0 利用IActionFilter实现简单的后台操作日志功能
- css 文字超出变 ... 点点点
- javaIO(05)字节流和字符流的区别
- [AS/400] 基本概念
- Hadoop学习笔记(4)hadoop集群模式安装
- UVA - 11637 Garbage Remembering Exam (组合+可能性)
- C++ CRTP singleton
- arcgis_server_address_note
- 关于CSS3 object-position/object-fit属性的使用
- 记录Queue插入的时候报错
- c语言搜索子字符串
- 我的WafBypass之道(Misc篇)
- C166 -MDH
热门文章
- Docker镜像和容器管理(二)
- 一套简单的web即时通讯——第三版
- Codeforces 760C:Pavel and barbecue(DFS+思维)
- HDU 3938:Portal(并查集+离线处理)
- 成功入职ByteDance,分享我的八面面经心得!
- Linux安装httpd
- ~~Python解释器安装教程及环境变量配置~~
- ServiceFabric极简文档-5.1 编程模型选择
- Java编程思想:序列化深层部分
- [笨方法学Python]ImportError";No module named bin.app";【笔记】