spring项目对某条单据进行加锁处理

最近工作中有个对工单单据进行加锁/解锁处理,目的是为了防止多用户对同一条单据处理。以下是完整的前后端代码。

前端JS billLock.js

javascript 复制代码
let orderLock = {
    orderLock:(viewmodel, id, billType)=>{
        var url = '/orderLock/lock?domainKey='+viewmodel.getDomainKey();
        var proxy = cb.rest.DynamicProxy.create({
            ensure: {url: url, method: 'POST'}
        });
        let data = {"id":id, "billType": billType, "ttl": 60*60*12}
        proxy.ensure(data, function (err, result) {
            if (err) {
                cb.utils.alert(err.message, 'error');
            } else {
                cb.utils.alert(result, 'info');
                if(viewmodel.originalViewMeta.cBillNo && viewmodel.originalViewMeta.cBillNo=="02924ed1"){
                    //维修领料页面进入
                    if(result.indexOf('成功') <= 0){
                          viewmodel.biz.action().common.browse(viewmodel)
                          viewmodel.biz.action().common.setMode(viewmodel,"browse");  
                          
                    }
                }else{
                    if(result.indexOf('成功') <= 0){
                        viewmodel.biz.action().common.browse(viewmodel)
                    }
                }
                
            }
        })
    },

    unOrderLock:(viewmodel, id, billType)=>{
        var url = '/orderLock/unLock?domainKey='+viewmodel.getDomainKey();
        var proxy = cb.rest.DynamicProxy.create({
            ensure: {url: url, method: 'POST'}
        });
        var data = {"id":id, "billType": billType}
        proxy.ensure(data, function (err, result) {
            if (err) {
                cb.utils.alert(err.message, 'error');
            } else {
                cb.utils.alert(result, 'info');
            }
        })
    }
}
export default orderLock
  

后端Java 代码

java 复制代码
@RestController
@RequestMapping("/orderLock")
@Slf4j
public class OrderLockController extends BaseController {
    @Autowired
    private GmsRedisUtil gmsRRedisUtil;
    @Autowired
    private UserInfoService userInfoService;

    private String ENGINE_NO = "afterservice";

    /**
     * 加锁
     */
    @PostMapping(value = "/lock")
    public void orderLock(@RequestBody OrderLockDTO orderLockDTO, HttpServletResponse response) {
        try{
            String result;
            UserExtendDto userExtendDto = userInfoService.getUserExtend();
            String nowDate = DateUtil.dateFormat(PartCommonConstants.dateTimeFormatter, LocalDateTime.now());
            String key = ENGINE_NO + "_" + orderLockDTO.getBillType() + "_" + orderLockDTO.getId();
            String message = "锁定人["+userExtendDto.getStaffName()+"]锁定时间["+nowDate+"]";
            Boolean flag = gmsRRedisUtil.tryGetLock(key, message, orderLockDTO.getTtl(), 2);
            if(flag){
                result = "加锁成功!";
            }else{
                String lockValue = gmsRRedisUtil.getObject(key);
                if(lockValue.contains(userExtendDto.getStaffName())){
                    result = "加锁成功!原锁定用户["+userExtendDto.getStaffName()+"]进入单据!";
                }else{
                    result = "加锁失败!单据已被锁定,"+lockValue;
                }
            }
            renderJson(response, ResultMessage.data(result,false));
        }catch(Exception e){
            renderJson(response, ResultMessage.error(e.getMessage()));
            log.error("加锁失败:{}",e);
        }
    }

代码解析(以上代码大致步骤如下:)

1. 前端代码 参数是data,带有id,billtype,字符串ttl,时间变量 4个参数穿入后端。

2.后端接收参数,调用gmsRRedisUtil.tryGetLock,这个方法是项目框架自己封装,原理是实现了redisTemplate.opsForValue().setIfAbsent方法

3.setIfAbsent方法简单介绍如下:

java 复制代码
1.setIfAbsent(K var1, V var2);
如果key不存在则新增,key存在不做任何操作
redisTemplate.opsForValue().setIfAbsent("BBB", "好的");

2.setIfAbsent(K var1, V var2, long var3, TimeUnit var5)
如果key不存在则新增,同时设置过期时间,key存在不做任何操作。
redisTemplate.opsForValue().setIfAbsent("AAA", "好的", 1, TimeUnit.MINUTES);

3.setIfAbsent(K key, V value, Duration timeout)
如果key不存在则新增,同时设置过期时间,key存在不做任何操作。
redisTemplate.opsForValue().setIfAbsent("BBB", "好的", Duration.ofMinutes(1));

4.如果单据第一次进入,key不存在,flag为true,直接返回给前端"加锁成功",前端解析字符串中含有"成功,不设置页面为浏览态,仍为编辑态

复制代码
本次加锁我调用的是第2个方法,这里的第一个参数key可见是单据id加一些特定字符。所以单据id就会被加锁,并设置加锁时间\

5 如果单据在已经加锁的情况下,仍有其他用户编辑此单据,则key重复,gmsRRedisUtil.tryGetLock不做操作。

复制代码
	gmsRRedisUtil.getObject(key)实际是调用redisTemplate.opsForValue().get(key) 方法,
	其中 get(Object var1)  是获取指定的key对应的值。
	第一次加锁的message是用户信息,这里如果是不同用户登录的话,
    if(lockValue.contains(userExtendDto.getStaffName())) 就为false,返回给前端的信息是"加锁失败...",
    前端获取字符串信息中没有加锁成功,会设置页面为浏览态,不能编辑。 到此,加锁完成!
相关推荐
陈随易10 小时前
编程语言级别的Skill市场,AI Agent 的未来形态
前端·后端·程序员
IT_陈寒12 小时前
Vite的热更新突然不香了,排查三小时差点砸键盘
前端·人工智能·后端
子兮曰13 小时前
Agency-Agents 深度解析:400+ AI 专家的"梦之队"如何重塑开发工作流
前端·后端·vibecoding
用户83562907805114 小时前
Python 实现 PDF 文件加密与解密方法
后端·python
小满zs14 小时前
Go语言第二章(小无相功)
后端·go
用户83562907805114 小时前
使用 Python 冻结与拆分 Excel 窗格教程
后端·python
karry_k14 小时前
MyBatis批量insert-select踩坑:useGeneratedKeys=true 可能让PostgreSQL返回大量插入结果
java·后端
妙码生花14 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十九):点选验证码代码逐行目检
前端·后端·go
贰先生14 小时前
Xiuno BBS X版 用户封禁系统
后端
karry_k14 小时前
PostgreSQL 在 MyBatis 中执行正常 SQL 失效:一次 DELETE USING 踩坑记录
java·后端