A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

1. 案例
有甲乙两个公司,甲选择一批自己的订单(一个订单有多个货物),生成的6位数字验证码,乙通过验证码接收订单,接收后需要将订单及订单中的货物的操作权限归属乙,甲不再拥有操作权限,要保证订单和货物的权限必须同时更改成功,我选择了开启了事务。在程序中我首先校验验证码,然后去redis查询对应内容,如果验证码正确则进行更改订单及货物的权限,然后移除Redis中的验证码。
@Transactionalpublic String receiveOrder(String code){    //第一步 校验验证码    ......    //第二步 获取验证码对应的内容    ......    //第三步 执行对应的更改权限逻辑    ......    //第四步 移除验证码    ......    //返回结果信息    return .....;}
在进行测试的时候发现有问题,第一种情况,有时候可以执行成功,有时候失败,于是直接打印日志,发现失败的时候获取的内容是空的,实际是存在的;第二种,执行成功后还能继续执行成功,验证码没有被移除掉。
经过查询相关信息发现了问题的原因竟然是因为事务导致的,是因为当开启事务的时候,Redis将进行队列模式执行,Redis会按照队列顺序进行执行,会进行等待。
2. 具体原因:
Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,Redis对事物支持不会很复杂,当一个客服端连接Redis服务时,发出了MULTI命令时,这个连接会进入事物,在执行MULTI命令之后,执行所有的命令都不会执行,会先放到一个队列中,会提示正在Query,当最后执行EXEC命令之后,Redis会按照之前的进入队列的顺序,执行命令。
3. 解决方案
解决办法是利用了Spring事务代理的特性将Redis执行的部分抽离出来,导致Redis部分事务失效,这样也能保证权限的问题。

@Transactionalpublic String receiveOrder(String code){    //第一步 校验验证码    ......    //第二步 获取验证码对应的内容    String result = getCodeContent(code);    //第三步 执行对应的更改权限逻辑    ......    //第四步 移除验证码    if(!removeCode(code)){        //如果移除失败 触发事务回滚    }    //返回结果信息    return .....;}//获取验证码内容private String getCodeContent(String code){    //获取验证码对应的内容    ......    //返回结果信息    return .....;}

1 个回复

正序浏览
我要黑马币,我要学习。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马