场景:对增加销售占用的接口服务做并发单元测试
商品库存PO:
@Data
@Entity
@Table(name = "product_sale_stock")
public class ProductSaleStockPo {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
/**
* 商品编码
*/
@Column
private Long productSale;
/**
* 仓库
*/
@Column
private Long dc;
/**
* 库存数量
*/
@Column
private int stock;
/**
* 销售占用
*/
@Column
private int sales;
/**
* 不准确库存
*/
@Column
private int incorrect;
}
增加销售占用接口服务:
@Service("xdtProductSaleStockService")
@Transactional(rollbackFor = Exception.class)
public class XdtProductSaleStockServiceImpl implements XdtProductSaleStockService {
@Override
public void increaseStockSales(int occupancy, long productSale, long dc) throws XdtProductSaleStockException {
if (occupancy < 0) {
occupancy = 0;
}
ProductSaleStockPo productSaleStockPo = productSaleStockDao.getByProductSaleAndDc(productSale, dc);
productSaleStockPo.setSales(productSaleStockPo.getSales()+occupancy);
}
}
模拟并发测试:
@RunWith(SpringRunner.class)
@SpringBootTest
public class XdtProductSaleStockServiceImplTest {
@Autowired
private XdtProductSaleStockService xdtProductSaleStockService;
@Test
public void testHighConcurrencyIncreaseSales() {
TestRunnable runner = new TestRunnable() {
@Override
public void runTest() throws Throwable {
xdtProductSaleStockService.increaseStockSales(2, 1201631745, 1);
}
};
int runnerCount = 10;
//Rnner数组,想当于并发多少个。
TestRunnable[] trs = new TestRunnable[runnerCount];
for (int i = 0; i < runnerCount; i++) {
trs[i] = runner;
}
// 用于执行多线程测试用例的Runner,将前面定义的单个Runner组成的数组传入
MultiThreadedTestRunner mttr = new MultiThreadedTestRunner(trs);
try {
// 开发并发执行数组里定义的内容
mttr.runTestRunnables();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
单元测试结果:
模拟并发之前数据库中sales=0,模拟并发之后期望数据库中sales=20,模拟并发之后实际数据库中sales=6
如何处理增加销售占用接口服务出现的并发问题?
方案一:
使用hibernate的乐观锁机制,在ProductSaleStockPo中添加version字段
方案二:
调整接口服务代码实现
@Override
public voidincreaseStockSales(int occupancy, long productSale, long dc) throws XdtProductSaleStockException {
if (occupancy < 0) {
occupancy = 0;
}
/**
* 修改增量库存占用 sql
*/
String UPDATE_INCREMENT_STOCK_SALES = "update product_sale_stock set sales=if(sales < (-?)," +
"0, convert(sales + (?), signed)) where productsale=? and dc=?";
this.jdbcTemplate.update(UPDATE_INCREMENT_STOCK_SALES, occupancy, occupancy, productSale, dc);
}