|
@@ -2,6 +2,9 @@ package com.sf.service;
|
|
|
|
|
|
import com.sf.utils.RedisUtils;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.dao.DataAccessException;
|
|
|
+import org.springframework.data.redis.core.RedisOperations;
|
|
|
+import org.springframework.data.redis.core.SessionCallback;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
@Service
|
|
@@ -14,14 +17,64 @@ public class RedisServiceImpl implements RedisService {
|
|
|
public void seckill(String userId, String goodsId) {
|
|
|
// goodsId = 1
|
|
|
// 1_stock_num
|
|
|
- String key = goodsId + "_stock_num";
|
|
|
- Integer num = (Integer) redisUtils.get(key);
|
|
|
- if (num > 0) {
|
|
|
- Long decr = redisUtils.decr(key);
|
|
|
- System.out.println(decr);
|
|
|
- }
|
|
|
+// String key = goodsId + "_stock_num";
|
|
|
+// Integer num = (Integer) redisUtils.get(key);
|
|
|
+// // 出现超卖的原因
|
|
|
+// // 当10个线程同时获取num的值 此时num=5 会同时进行自减操作
|
|
|
+// if (num > 0) {
|
|
|
+// Long decr = redisUtils.decr(key);
|
|
|
+// System.out.println(decr);
|
|
|
+// }
|
|
|
+ handleByTran(userId, goodsId);
|
|
|
+
|
|
|
+ // 加锁 乐观锁和悲观锁
|
|
|
+ // 以悲观的态度看待 如果修改数据时不增加锁 一定会出现问题
|
|
|
+ // 以乐观的态度看待 如果修改数据时不增加锁 不一定会出现问题
|
|
|
+
|
|
|
+ // 乐观锁
|
|
|
+ // id=1 name=zhangsan -> 修改为lisi
|
|
|
+ // version=1
|
|
|
+ // -> 修改为wangwu
|
|
|
+ // 第一个请求 记录数据的值和数据的版本 name=zhangsan version=1 newName=lisi
|
|
|
+ // 第二个请求 记录数据的值和数据的版本 name=zhangsan version=1 newName=wangwu
|
|
|
+
|
|
|
+ // id=1 name=lisi version=2
|
|
|
+ // 第二个请求 记录数据的值和数据的版本 name=zhangsan version=1 newName=wangwu
|
|
|
+ // 如果请求传递的数据和版本与当前数据版本不匹配 不予处理 打回
|
|
|
+ // 第二个请求 记录数据的值和数据的版本 name=lisi version=2 newName=wangwu
|
|
|
+
|
|
|
+ // 第三个请求 记录数据的值和数据的版本 name=lisi version=2 newName=laoliu
|
|
|
+ // id=1 name=wangwu version=3
|
|
|
+
|
|
|
+
|
|
|
+ // 悲观锁 性能低但安全性高
|
|
|
+ // mysql中的行锁 就是悲观锁
|
|
|
+
|
|
|
}
|
|
|
|
|
|
+ // 尝试通过事务处理
|
|
|
+ public void handleByTran(String userId, String goodsId) {
|
|
|
+ // 编写事务处理的逻辑
|
|
|
+ SessionCallback sessionCallback = new SessionCallback() {
|
|
|
+ @Override
|
|
|
+ public Object execute(RedisOperations operations) throws DataAccessException {
|
|
|
+ // watch - multi - command - exec
|
|
|
+ String key = goodsId + "_stock_num";
|
|
|
+ operations.watch(key);
|
|
|
+ Integer num = (Integer) redisUtils.get(key);
|
|
|
+ if (num <= 0) {
|
|
|
+// System.out.println();
|
|
|
+ return "已经被秒杀一空";
|
|
|
+ }
|
|
|
+ operations.multi();
|
|
|
+ redisUtils.decr(key);
|
|
|
+ // 代表一笔订单生成 订单id=商品id+用户id
|
|
|
+ redisUtils.set(goodsId + "_" + userId, "1");
|
|
|
+ return operations.exec();
|
|
|
+ }
|
|
|
+ };
|
|
|
+ redisUtils.execute(sessionCallback);
|
|
|
+ }
|
|
|
|
|
|
@Override
|
|
|
public void init() {
|