You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何带IF NOT EXISTS的H2主键添加语句在并发下报错?

问题分析与解决

问题本质

这是H2数据库内存模式下,并发执行初始化脚本时的竞态条件bug。

原因解释

  • 当多个连接同时通过INIT=RUNSCRIPT执行初始化脚本时,CREATE TABLE IF NOT EXISTS是原子性操作,只会创建一次表。
  • 但ALTER TABLE ADD CONSTRAINT IF NOT EXISTS的检查与添加操作并非原子:多个连接可能同时通过“主键是否存在”的检查,随后尝试添加同一个主键约束,导致冲突报错。
  • 连接池重试后错误消失,是因为重试时已有连接成功添加了主键,后续检查会发现约束已存在,不再执行添加操作。

解决办法

  1. 将主键定义整合到建表语句中(最稳妥的方案)
    修改QRTZ_CALENDARS的建表语句,直接在表定义里声明主键:

    CREATE TABLE IF NOT EXISTS QRTZ_CALENDARS (
        SCHED_NAME VARCHAR(120) NOT NULL,
        CALENDAR_NAME VARCHAR (200) NOT NULL,
        CALENDAR IMAGE NOT NULL,
        PRIMARY KEY (SCHED_NAME, CALENDAR_NAME)
    );
    

    这样CREATE TABLE的原子性会确保主键只被定义一次,不会出现并发冲突。

  2. 确保初始化脚本仅执行一次
    不要通过JDBC URL的INIT参数让每个连接都执行脚本,而是在应用启动阶段,用单个连接执行一次初始化逻辑,避免并发执行脚本的情况。

  3. 升级H2版本
    检查H2的最新版本,部分后续版本可能修复了这个并发场景下的约束检查原子性问题。


内容的提问来源于stack exchange,提问作者Jakub Bochenski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 19:50:13