即息极 发表于 2025-6-9 18:17:12

数据并发安全校验处理工具类

一、项目现存问题描述

  当前系统项目中,存在一些并发安全风险问题(虽然并发量较小)。特别是在处理审批状态修改和涉及金额数量的操作,由于缺乏有效的并发控制,可能会导致业务逻辑重复执行和数据不一致。例如 并发场景下,多个线程同时尝试更新同一笔交易状态或金额,这不仅会导致数据不一致,还可能引发更严重的相关业务逻辑错误。
二、一般处理方案概述

乐观锁:
通过在表中添加一个版本号字段来实现,当更新记录时,检查版本号是否与读取时相同,否则表示数据已被其他事务修改,需要重试。PS:需要现行表增加字段并修改代码支持,改动稍大
悲观锁:
使用数据库提供的锁机制,在查询时即锁定记录。PS:应避免表级锁,查询条件应使用到索引字段。
分布式锁:
对于跨服调用的场景,可以采用redis等缓存技术实现分布式锁,确保在同一时刻只有一个服务实例能够对共享资源进行操作。PS:我们的项目开发规则不支持服务层使用redis组件,固开发了这个工具类
事务管理:
合理配置事务隔离级别,确保事务间的可见性服务预期,避免脏读、不可重复读等问题。PS:不便于后期维护,容易造成事务的未知风险
三、基于现行项目的工具类设计方案

结合项目实际情况,设计了一个专用于解决此类并发问题的工具类。该工具类采用了悲观锁方案,使用便捷,以下是不分测试样例与工具类源码。
1、使用测试样例:

    //修改金额
    @Transactional(rollbackFor = Exception.class)
    public void addUserAccountAmount() {
      ConcurrentDataUtils.updateAmount(UserInfo::getAccountAmount, 600, this,Pair.of(UserAccount::getId, 10));
    }
  //判断是否与预期值一致 eg:判断审批状态 是否为待审批,否则应拦截
    @Transactional(rollbackFor = Exception.class)
    public void isEqual() {
      ConcurrentDataUtils.isEqual(Approve::getStatus, 0, this,Pair.of(Approve::getForeignId, 1122334));
    }
    //判断数据是否已存在 eg:同步、保存等场景
    @Transactional(rollbackFor = Exception.class)
    public void isExist() {
      ConcurrentDataUtils.isExist(userInfoService,Pair.of(UserInfo::getIdCard, 1122334),Pair.of(UserInfo::getIsDelete,0));
    }2、工具类源码

package com.example.dlock_demo.utils;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;import com.baomidou.mybatisplus.core.toolkit.support.SFunction;import com.baomidou.mybatisplus.extension.service.IService;import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang3.tuple.Pair;import java.io.Serializable;import java.lang.invoke.SerializedLambda;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.math.BigDecimal;import java.util.Map;import java.util.Objects;import java.util.Optional;import java.util.concurrent.ConcurrentHashMap;/** * 并发校验、处理数据工具类 * * @author: shf * @date: 2025年02月14日 11:13 */@Slf4jpublic class ConcurrentDataUtils {    private static final String DEFAULT_LAST_JOIN_SQL = "ORDER BY id DESC Limit 1 FOR UPDATE";    private static Map
页: [1]
查看完整版本: 数据并发安全校验处理工具类