MVCC模式下HSQLDB执行SELECT ... FOR UPDATE未锁行,是否支持悲观行锁?
HSQLDB悲观锁不生效问题解答
HSQLDB 2.6.1是否支持悲观行锁
HSQLDB 2.0及以上版本(包含你使用的2.6.1版本)支持悲观行锁,你遇到的多线程同时获取锁的问题,是MVCC并发控制模型的默认配置导致的,和代码实现无关。
默认MVCC模式下,HSQLDB的SELECT ... FOR UPDATE语句不会对查询到的行加排他锁,而是直接读取最新提交的行快照,因此多个事务可以同时获取到查询结果,不会出现预期的阻塞排队效果。
解决方案
- 方案1:开启MVCC模式下的FOR UPDATE锁配置
在HSQLDB的连接参数、数据库配置文件或者启动参数中添加配置项hsqldb.lock.forupdate=true。开启该配置后,MVCC模式下的SELECT ... FOR UPDATE语句会对匹配行加排他锁,其他事务查询同一条数据时会被阻塞,直到持有锁的事务提交或回滚,完全符合悲观锁的预期逻辑,同时可以保留MVCC模式的高并发性能。 - 方案2:切换并发控制模型为两阶段锁(2PL)
将HSQLDB的事务控制模式配置修改为hsqldb.tx=locks,该模式下读写操作都会加锁,天然支持悲观行锁的阻塞逻辑,无需额外配置其他参数。不过2PL模式的并发性能低于MVCC模式,更适合对并发要求不高的测试场景使用。 - 方案3:验证事务边界正确性
你当前的代码配置了@Transactional(propagation = Propagation.REQUIRES_NEW),需要确认该方法被Spring AOP正确代理,每个调用确实开启了独立事务。可以添加日志打印当前事务标识验证:// 引入Spring事务工具类 import org.springframework.transaction.support.TransactionSynchronizationManager; public void sync() { // 打印当前事务名称,确认每个线程事务独立 log.debug("current transaction: {}", TransactionSynchronizationManager.getCurrentTransactionName()); MyEntity entity = entityManager.find(MyEntity.class, entityId, LockModeType.PESSIMISTIC_WRITE); log.debug("entity {} was locked", entity.getKey()); }
内容的提问来源于stack exchange,提问作者Andrey Biryukov
相关产品推荐
相关产品推荐

