mysql的分布式锁和事物_【redisson】分布式锁与数据库事务

场景:

用户消耗积分兑换商品。

user_point(用户积分):

id

point

1

2000

point_item(积分商品):

id

point

num

101

200

10

传统的controller、service、dao三层架构,数据库事务控制在service层(数据库MYSQL)。

@RestController

@RequestMapping(value = {"point"})

public class UserPointController{

@Autowired

private UserPointService userPointService;

@RequestMapping("/exchange")

public boolean exchange(HttpServletRequest request, Long userId, Long itemId){

return userPointService.exchange(userId, itemId);

}

}

@Service

public class UserPointService {

@Resource

private RedissonClient redissonClient;

@Transaction

public boolean exchange(Long userId, Long itemId) throws Exception {

RLock lock = redissonClient.getLock("lock:" + itemId);

try {

boolean bool = lock.tryLock(10, 30, TimeUnit.SECONDS);

if (!bool){

throw new Exception("操作失败,请稍后重试");

}

UserPoint user = "select * from user_point where id = :userId";

PointItem item = "select * from point_item where id = :itemId";

if(user.point - item.point > 0 && item.num > 0){

// 扣减积分

>> update user_point set point = point - :item.point where id = :userId;

// 扣减库存

>> update point_item set num = num - 1 where id = :itemId;

return true;

}

return false;

} catch (Exception e) {

throw e;

} finally {

if(lock != null && lock.isHeldByCurrentThread()){

lock.unlock();

}

}

}

}

观察以上代码思考:

lock是什么时候释放的?

调用lock.unlock()就是释放redisson-lock。

事务是什么时候提交的?

事务的提交是在方法UserPointService#exchange()执行完成后。所以,示例代码中其实会先释放lock,再提交事务。

事务是什么时候提交完成的?

事务提交也需要花费一定的时间

由于先释放lock,再提交事务。并且由于mysql默认的事务隔离级别为 repetable-read,这导致的问题就是:

假设现在有2个并发请求{"userId": 1, "itemId": 101},user剩余积分201。

假设A请求先获得lock,此时B请求等待获取锁。

A请求得到的数据信息是user_point#point=201,此时允许兑换执行扣减,返回true。

在返回true前,会先释放lock,再提交事务。

释放lock后,B请求可以马上获取到锁,查询user可能得到剩余积分: 201(正确的应该是剩余积分: 1),因为A请求的事务可能未提交完成造成!

解决方案:

暂时是将lock改写到controller层,保证在事务提交成功后才释放锁!

(画图苦手,时序图有缘再见)

原文:https://www.cnblogs.com/VergiLyn/p/11506756.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值