H2 1.4.199 getGeneratedKeys返回其他事务ID或Future混叠问题求解
问题根因
- H2 1.4.199版本存在原生BUG:该版本在复用数据库连接的场景下,
getGeneratedKeys()有概率返回当前连接上一次插入操作生成的ID,而非当前执行语句的生成ID,若开启了H2的MVCC模式,触发概率会进一步提升。 - 生成ID读取时序不合理:代码在事务提交前就读取生成的主键,此时H2的自增ID还未完成全局持久化,极端时序下会读取到未生效的ID值。
- 冗余锁无实际作用:代码中对
singleExecutor加的synchronized完全多余,ExecutorService的submit方法本身已经保证线程安全,额外加锁不会影响问题的触发,但会带来不必要的性能损耗。
解决方案
根治方案
直接将H2版本升级到1.4.200及以上稳定版,该版本已经官方修复了getGeneratedKeys()返回历史ID的问题,是成本最低的100%规避方案。
兜底兼容方案(无法升级H2时使用)
- 替换主键生成逻辑:不再依赖
Statement.RETURN_GENERATED_KEYS获取数据库生成的ID,改为业务层手动生成全局唯一主键(如雪花ID)直接写入数据库,从根源上避免依赖数据库返回ID的风险。 - 调整ID读取时序:如果必须使用数据库生成主键,将
getGeneratedKeys()的读取逻辑放到事务提交之后执行,确保读取到的是已经持久化的正式ID值。 - 调整H2配置:在连接参数中添加
;MVCC=FALSE关闭MVCC模式,大幅降低BUG触发概率。 - 优化连接池配置:开启连接池的会话状态清理逻辑,每次从连接池获取连接时执行一次会话重置操作,避免连接复用带来的上下文残留问题。
- 增加业务校验:插入操作完成后新增校验步骤,拿着返回的ID查询数据库,确认对应记录存在且数据匹配,校验失败直接重试插入,从业务层面兜底避免ID重复的问题。
内容的提问来源于stack exchange,提问作者Andrew Snejovski
相关产品推荐
相关产品推荐

