场景:

  用户消耗积分兑换商品。

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();
}
}
} }

观察以上代码思考:

  1. lock是什么时候释放的?

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

  2. 事务是什么时候提交的?

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

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

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

由于先释放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层,保证在事务提交成功后才释放锁!

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

【redisson】分布式锁与数据库事务的更多相关文章

  1. Redisson分布式锁实现

    转: Redisson分布式锁实现 2018年09月07日 15:30:32 校长我错了 阅读数:3303   转:分布式锁和Redisson实现 概述 分布式系统有一个著名的理论CAP,指在一个分布 ...

  2. Redisson分布式锁的简单使用

    一:前言 我在实际环境中遇到了这样一种问题,分布式生成id的问题!因为业务逻辑的问题,我有个生成id的方法,是根据业务标识+id当做唯一的值! 而uuid是递增生成的,从1开始一直递增,那么在同一台机 ...

  3. Redisson 分布式锁实战与 watch dog 机制解读

    Redisson 分布式锁实战与 watch dog 机制解读 目录 Redisson 分布式锁实战与 watch dog 机制解读 背景 普通的 Redis 分布式锁的缺陷 Redisson 提供的 ...

  4. Redisson 分布式锁源码 02:看门狗

    前言 说起 Redisson,比较耳熟能详的就是这个看门狗(Watchdog)机制. 本文就一起看看加锁成功之后的看门狗(Watchdog)是如何实现的? 加锁成功 在前一篇文章中介绍了可重入锁加锁的 ...

  5. Java分布式:分布式锁之数据库实现

    Java分布式:分布式锁之数据库实现 分布式锁系列教程重点分享锁实现原理 锁实现原理 创建一张名为methodLock的数据库表,为方法名字段(method_name)添加唯一性约束. CREATE ...

  6. [转帖]SpringBoot集成redisson分布式锁

    SpringBoot集成redisson分布式锁 https://www.cnblogs.com/yangzhilong/p/7605807.html 前几天同事刚让增加上这一块东西. 百度查一下 啥 ...

  7. 又长又细,万字长文带你解读Redisson分布式锁的源码

    前言 上一篇文章写了Redis分布式锁的原理和缺陷,觉得有些不过瘾,只是简单的介绍了下Redisson这个框架,具体的原理什么的还没说过呢.趁年前项目忙的差不多了,反正闲着也是闲着,不如把Rediss ...

  8. Redisson 分布式锁实现之前置篇 → Redis 的发布/订阅 与 Lua

    开心一刻 我找了个女朋友,挺丑的那一种,她也知道自己丑,平常都不好意思和我一块出门 昨晚,我带她逛超市,听到有两个人在我们背后小声嘀咕:"看咱前面,想不到这么丑都有人要." 女朋友 ...

  9. Redisson 分布式锁实现之源码篇 → 为什么推荐用 Redisson 客户端

    开心一刻 一男人站在楼顶准备跳楼,楼下有个劝解员拿个喇叭准备劝解 劝解员:兄弟,别跳 跳楼人:我不想活了 劝解员:你想想你媳妇 跳楼人:媳妇跟人跑了 劝解员:你还有兄弟 跳楼人:就是跟我兄弟跑的 劝解 ...

随机推荐

  1. 机器学习李航——Adaboost课本例题实现

    例8.1Adaboost的例子 注意求D3或者D4的时候只需要把w替换一下就行,记得还得改阈值.这个代码算个半自动的,因为还需要手动改一下. import numpy as np def getA(e ...

  2. 性能优于JDK代理,CGLib如何实现动态代理

    按照代理的创建时期,代理类可以分为两种. 静态代理:由程序员创建或特定工具自动生成源代码,再对其编译.在程序运行前,代理类的.class文件就已经存在了. 动态代理:在程序运行时,运用反射机制动态创建 ...

  3. MCI使用

    MCI(Media Control Interface)媒体控制接口是MircroSoft提供的一组多媒体设备和文件的标准接口,它的好处是可以方便地控制绝大多数多媒体设备包括音频.视频.影碟.录像等多 ...

  4. 从免费的物联网防火墙hihttps谈机器学习之生成对抗规则

    hihttps是一款基于MQTT的免费的物联网防火墙,同时也是web应用防火墙,既支持传统的检测功能如SQL注入.XSS.恶意漏洞扫描.密码暴力破解.CC.DDOS等),又支持无监督机器学习,自主对抗 ...

  5. 使用ClouderaManager管理的HBase的RegionServer无法启动(启动失败)的问题

    问题概述 "新冠期间"远程办公,需要重新搭建一套ClouderaManager(CM)开发环境,一位测试同事发现HBase的RegionServer无法启动,在CM界面上启动总是失 ...

  6. CCF_ 201403-2_窗口

    用deque模拟. #include<iostream> #include<cstdio> #include<deque> using namespace std; ...

  7. 51Nod 1021 石子归并(区间dp经典入门)

    题意: N堆石子摆成一条线.现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价.计算将N堆石子合并成一堆的最小代价. n<=100 思 ...

  8. 都闪开,不用任何游戏引擎,html也能开发格斗游戏

    html格斗游戏,对打游戏 不用引擎,不用画布canvas,不用任何库(包括jquery), 原生div+img组件,开发格斗游戏游戏教程视频已经上传 b站:https://www.bilibili. ...

  9. apache工具

    组件 功能介绍HttpClient 提供HTTP客户端与服务器的各种通讯操作. 现在已改成HttpComponentsIO io工具的封装.Lang3 Java基本对象方法的工具类包 如:String ...

  10. expect 运行脚本文件 执行postgres数据库操作

    #!/bin/bash /usr/bin/expect << EOF spawn /usr/local/pgsql/bin/.sh expect "*postgres:" ...