Hibernate中的并发控制

这篇博客探讨了在Hibernate中处理并发控制的问题,具体场景是对增加销售占用的接口服务进行并发单元测试。测试发现存在并发导致的数据不一致问题。提出了两种解决方案:一是采用Hibernate的乐观锁机制,增加version字段;二是优化接口服务代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

场景:对增加销售占用的接口服务做并发单元测试

商品库存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);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值