refactor(sip-service): 添加线程安全锁以确保编码生成操作的线程安全性在 `AgentInfoServiceImpl`, `CustomerInfoServiceImpl`, `PartnerInfoServiceImpl` 和 `VendorInfoServiceImpl` 中添加了 `ReentrantLock`以确保生成编码的操作是线程安全的。具体修改包括:
- 在每个服务实现类中引入 `Lock` 和 `ReentrantLock`。- 在插入和更新操作中使用锁来保证编码生成的唯一性。
- 在 `ProjectOrderInfoMapper.xml` 中修正了一个 SQL 语句的格式问题。

这些改动有助于避免多线程环境下可能发生的编码冲突问题。
```
dev_1.0.0
chenhao 2025-09-11 15:50:16 +08:00
parent c688decad4
commit 3c58f9f254
5 changed files with 98 additions and 42 deletions

View File

@ -1,6 +1,8 @@
package com.ruoyi.sip.service.impl; package com.ruoyi.sip.service.impl;
import java.util.List; import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.ShiroUtils; import com.ruoyi.common.utils.ShiroUtils;
@ -22,7 +24,6 @@ public class AgentInfoServiceImpl implements IAgentInfoService
{ {
@Autowired @Autowired
private AgentInfoMapper agentInfoMapper; private AgentInfoMapper agentInfoMapper;
/** /**
* *
* *

View File

@ -1,6 +1,8 @@
package com.ruoyi.sip.service.impl; package com.ruoyi.sip.service.impl;
import java.util.List; import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.ServiceException;
@ -29,6 +31,8 @@ public class CustomerInfoServiceImpl implements ICustomerInfoService
private CustomerInfoMapper customerInfoMapper; private CustomerInfoMapper customerInfoMapper;
@Autowired @Autowired
private ICnareaService cnareaService; private ICnareaService cnareaService;
// 添加静态锁,确保生成编码的操作是线程安全的
private static final Lock lock = new ReentrantLock();
/** /**
* *
* *
@ -63,12 +67,18 @@ public class CustomerInfoServiceImpl implements ICustomerInfoService
public int insertCustomerInfo(CustomerInfo customerInfo) public int insertCustomerInfo(CustomerInfo customerInfo)
{ {
customerInfo.setCreateBy(ShiroUtils.getUserId().toString()); customerInfo.setCreateBy(ShiroUtils.getUserId().toString());
lock.lock();
try {
customerInfo.setCustomerCode(generateCode(customerInfo.getProvince())); customerInfo.setCustomerCode(generateCode(customerInfo.getProvince()));
int i = customerInfoMapper.selectCountByCode(customerInfo); int i = customerInfoMapper.selectCountByCode(customerInfo);
if (i > 0){ if (i > 0) {
throw new ServiceException("客户编码已存在"); throw new ServiceException("客户编码已存在");
}
return customerInfoMapper.insertCustomerInfo(customerInfo);
} finally {
lock.unlock();
} }
return customerInfoMapper.insertCustomerInfo(customerInfo);
} }
private String generateCode(String province) { private String generateCode(String province) {
@ -120,16 +130,23 @@ public class CustomerInfoServiceImpl implements ICustomerInfoService
// 如果省份发生变化,需要重新生成客户编码 // 如果省份发生变化,需要重新生成客户编码
CustomerInfo oldCustomerInfo = customerInfoMapper.selectCustomerInfoById(customerInfo.getId()); CustomerInfo oldCustomerInfo = customerInfoMapper.selectCustomerInfoById(customerInfo.getId());
if (oldCustomerInfo != null && !oldCustomerInfo.getProvince().equals(customerInfo.getProvince())) { if (oldCustomerInfo != null && !oldCustomerInfo.getProvince().equals(customerInfo.getProvince())) {
String newCustomerCode = generateCode(customerInfo.getProvince()); lock.lock();
customerInfo.setCustomerCode(newCustomerCode); try {
String newCustomerCode = generateCode(customerInfo.getProvince());
customerInfo.setCustomerCode(newCustomerCode);
// 检查新生成的编码是否已存在 // 检查新生成的编码是否已存在
CustomerInfo codeCheckParam = new CustomerInfo(); CustomerInfo codeCheckParam = new CustomerInfo();
codeCheckParam.setCustomerCode(newCustomerCode); codeCheckParam.setCustomerCode(newCustomerCode);
int count = customerInfoMapper.selectCountByCode(codeCheckParam); int count = customerInfoMapper.selectCountByCode(codeCheckParam);
if (count > 0) { if (count > 0) {
throw new ServiceException("客户编码已存在"); throw new ServiceException("客户编码已存在");
}
return customerInfoMapper.updateCustomerInfo(customerInfo);
} finally {
lock.unlock();
} }
} }
return customerInfoMapper.updateCustomerInfo(customerInfo); return customerInfoMapper.updateCustomerInfo(customerInfo);

View File

@ -2,6 +2,7 @@ package com.ruoyi.sip.service.impl;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
@ -21,20 +22,23 @@ import com.ruoyi.common.core.text.Convert;
/** /**
* Service * Service
* *
* @author mula * @author mula
* @date 2025-04-30 * @date 2025-04-30
*/ */
@Service @Service
public class PartnerInfoServiceImpl implements IPartnerInfoService public class PartnerInfoServiceImpl implements IPartnerInfoService
{ {
@Autowired @Autowired
private PartnerInfoMapper partnerInfoMapper; private PartnerInfoMapper partnerInfoMapper;
@Autowired @Autowired
private ICnareaService cnareaService; private ICnareaService cnareaService;
// 添加静态锁,确保生成编码的操作是线程安全的
private static final Lock lock = new ReentrantLock();
/** /**
* *
* *
* @param id * @param id
* @return * @return
*/ */
@ -54,7 +58,7 @@ public class PartnerInfoServiceImpl implements IPartnerInfoService
/** /**
* *
* *
* @param partnerInfo * @param partnerInfo
* @return * @return
*/ */
@ -66,7 +70,7 @@ public class PartnerInfoServiceImpl implements IPartnerInfoService
/** /**
* *
* *
* @param partnerInfo * @param partnerInfo
* @return * @return
*/ */
@ -74,14 +78,20 @@ public class PartnerInfoServiceImpl implements IPartnerInfoService
public int insertPartnerInfo(PartnerInfo partnerInfo) public int insertPartnerInfo(PartnerInfo partnerInfo)
{ {
partnerInfo.setCreateBy(ShiroUtils.getUserId().toString()); partnerInfo.setCreateBy(ShiroUtils.getUserId().toString());
//生成编码 // 生成编码时加锁,确保线程安全
partnerInfo.setPartnerCode(generateCode(partnerInfo.getProvince())); lock.lock();
try {
//生成编码
partnerInfo.setPartnerCode(generateCode(partnerInfo.getProvince()));
int i = partnerInfoMapper.selectCountByCode(partnerInfo); int i = partnerInfoMapper.selectCountByCode(partnerInfo);
if (i>0){ if (i > 0) {
throw new ServiceException("该编码已存在"); throw new ServiceException("该编码已存在");
}
return partnerInfoMapper.insertPartnerInfo(partnerInfo);
} finally {
lock.unlock();
} }
return partnerInfoMapper.insertPartnerInfo(partnerInfo);
} }
private String generateCode(String province) { private String generateCode(String province) {
@ -109,7 +119,7 @@ public class PartnerInfoServiceImpl implements IPartnerInfoService
/** /**
* *
* *
* @param partnerInfo * @param partnerInfo
* @return * @return
*/ */
@ -120,12 +130,20 @@ public class PartnerInfoServiceImpl implements IPartnerInfoService
// 如果省份发生变化,需要重新生成客户编码 // 如果省份发生变化,需要重新生成客户编码
PartnerInfo existsInfo = partnerInfoMapper.selectPartnerInfoById(partnerInfo.getId()); PartnerInfo existsInfo = partnerInfoMapper.selectPartnerInfoById(partnerInfo.getId());
if (existsInfo != null && !existsInfo.getProvince().equals(partnerInfo.getProvince())) { if (existsInfo != null && !existsInfo.getProvince().equals(partnerInfo.getProvince())) {
String newPartnerCode = generateCode(partnerInfo.getProvince()); // 重新生成编码时加锁,确保线程安全
partnerInfo.setPartnerCode(newPartnerCode); lock.lock();
} try {
int i = partnerInfoMapper.selectCountByCode(partnerInfo); String newPartnerCode = generateCode(partnerInfo.getProvince());
if (i>0){ partnerInfo.setPartnerCode(newPartnerCode);
throw new ServiceException("该编码已存在");
int i = partnerInfoMapper.selectCountByCode(partnerInfo);
if (i > 0) {
throw new ServiceException("该编码已存在");
}
return partnerInfoMapper.updatePartnerInfo(partnerInfo);
} finally {
lock.unlock();
}
} }
return partnerInfoMapper.updatePartnerInfo(partnerInfo); return partnerInfoMapper.updatePartnerInfo(partnerInfo);
} }

View File

@ -1,6 +1,9 @@
package com.ruoyi.sip.service.impl; package com.ruoyi.sip.service.impl;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
@ -32,7 +35,8 @@ public class VendorInfoServiceImpl implements IVendorInfoService {
private VendorInfoMapper vendorInfoMapper; private VendorInfoMapper vendorInfoMapper;
@Autowired @Autowired
private IOmsWarehouseInfoService warehouseInfoService; private IOmsWarehouseInfoService warehouseInfoService;
// 添加静态锁,确保生成编码的操作是线程安全的
private static final Lock lock = new ReentrantLock();
/** /**
* *
* *
@ -63,11 +67,20 @@ public class VendorInfoServiceImpl implements IVendorInfoService {
*/ */
@Override @Override
public int insertVendorInfo(VendorInfo vendorInfo) { public int insertVendorInfo(VendorInfo vendorInfo) {
checkUnqCode(vendorInfo); lock.lock();
vendorInfo.setVendorStatus(VendorInfo.VendorStatusEnum.NORMAL.getCode()); try {
vendorInfo.setCreateTime(DateUtils.getNowDate());
vendorInfo.setCreateBy(ShiroUtils.getUserId().toString()); checkUnqCode(vendorInfo);
return vendorInfoMapper.insertVendorInfo(vendorInfo); vendorInfo.setVendorStatus(VendorInfo.VendorStatusEnum.NORMAL.getCode());
vendorInfo.setCreateTime(DateUtils.getNowDate());
vendorInfo.setCreateBy(ShiroUtils.getUserId().toString());
return vendorInfoMapper.insertVendorInfo(vendorInfo);
} catch (Exception e) {
throw new ServiceException("保存超时,请重试");
} finally {
lock.unlock();
}
} }
private void checkUnqCode(VendorInfo vendorInfo) { private void checkUnqCode(VendorInfo vendorInfo) {
@ -91,10 +104,17 @@ public class VendorInfoServiceImpl implements IVendorInfoService {
*/ */
@Override @Override
public int updateVendorInfo(VendorInfo vendorInfo) { public int updateVendorInfo(VendorInfo vendorInfo) {
checkUnqCode(vendorInfo); lock.lock();
vendorInfo.setUpdateTime(DateUtils.getNowDate()); try {
vendorInfo.setUpdateBy(ShiroUtils.getUserId().toString()); checkUnqCode(vendorInfo);
return vendorInfoMapper.updateVendorInfo(vendorInfo); vendorInfo.setUpdateTime(DateUtils.getNowDate());
vendorInfo.setUpdateBy(ShiroUtils.getUserId().toString());
return vendorInfoMapper.updateVendorInfo(vendorInfo);
} catch (Exception e) {
throw new ServiceException("保存超时,请重试");
} finally {
lock.unlock();
}
} }
/** /**

View File

@ -537,7 +537,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</delete> </delete>
<delete id="deleteProjectOrderInfoByIds" parameterType="String"> <delete id="deleteProjectOrderInfoByIds" parameterType="String">
delete from project_order_info where id in delete from project_order_info where id in
<foreach item="id" collection="array" open="(" separator="," close=")"> <foreach item="id" collection="array" open="(" separator="," close=")">
#{id} #{id}
</foreach> </foreach>