From 19e413fb48a88f18be10baaaec625b1aac8316ba Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Mon, 17 Aug 2026 22:30:18 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=E5=9B=9B=E4=B8=AA=20SEQUENCE=20?= =?UTF-8?q?=E4=B8=BB=E9=94=AE=E5=AE=9E=E4=BD=93=E6=98=BE=E5=BC=8F=E5=A3=B0?= =?UTF-8?q?=E6=98=8E=E5=BA=8F=E5=88=97=E5=90=8D=E5=B9=B6=E5=9B=BA=E5=8C=96?= =?UTF-8?q?=20allocationSize=3D50=EF=BC=8C=E5=85=BC=E5=AE=B9=E8=BE=BE?= =?UTF-8?q?=E6=A2=A6=E6=89=8B=E5=B7=A5=E9=A2=84=E5=BB=BA=E5=BA=8F=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - FlowRecord/FlowTodoRecord/FlowTodoMarge/SubProcessRecord 显式 @SequenceGenerator, 序列名固定为 t_<表名>_seq,不再依赖 Hibernate 隐式命名(避免因 db_structure_naming_strategy 或方言差异导致序列名推导不一致、Hibernate 找不到序列) - allocationSize 固定 50,与序列 INCREMENT BY 严格一致,规避 pooled 优化器主键重复 - application-dm.properties 补充达梦序列部署约定:ddl-auto=update 在达梦自动建序列不可靠, 需手工预建;起始值按表是否有历史数据设置(空表 start with 1,有数据 start with max(id)+1) Co-Authored-By: Claude --- .../main/resources/application-dm.properties | 17 +++++++++++++++++ .../flow/infra/entity/FlowRecordEntity.java | 3 ++- .../flow/infra/entity/FlowTodoMargeEntity.java | 3 ++- .../flow/infra/entity/FlowTodoRecordEntity.java | 3 ++- .../infra/entity/SubProcessRecordEntity.java | 4 +++- 5 files changed, 26 insertions(+), 4 deletions(-) diff --git a/flow-engine-example/src/main/resources/application-dm.properties b/flow-engine-example/src/main/resources/application-dm.properties index b801958a..94de4f29 100644 --- a/flow-engine-example/src/main/resources/application-dm.properties +++ b/flow-engine-example/src/main/resources/application-dm.properties @@ -6,6 +6,23 @@ spring.jpa.properties.hibernate.dialect=com.codingapi.example.dialect.HydDmDiale # 开启 JDBC 批次插入,配合 SEQUENCE 主键(t_flow_record/t_flow_todo_record/t_flow_todo_marge/t_flow_sub_process_record) # 将批量创建流程记录/待办/合并/子流程时的多次串行 INSERT 合并为批次往返,显著降低远程库耗时 +# +# ⚠️ 达梦主键序列约定: +# 这四个实体显式声明了 @SequenceGenerator,序列名固定为 t_flow_record_seq / +# t_flow_todo_record_seq / t_flow_todo_marge_seq / t_flow_sub_process_record_seq, +# allocationSize = 50。 +# Hibernate 的 ddl-auto=update 在达梦上自动建序列并不可靠,请【首次部署前手工预建】这四个序列, +# 且 INCREMENT BY 必须与 allocationSize(50) 严格一致(否则 pooled 优化器可能主键重复)。 +# 起始值 start with 按表是否有历史数据决定(pooled 发号从 start 起连续递增,绝不下探到 start 以下): +# ⚪ 表为空: start with 1 increment by 50 +# 🟠 表已存在数据(id 到 N): start with (N+1) increment by 50 ← 务必为已占用的最大 id + 1,否则新号撞历史主键 +# 示例(空表): +# create sequence t_flow_record_seq increment by 50 start with 1; +# create sequence t_flow_todo_record_seq increment by 50 start with 1; +# create sequence t_flow_todo_marge_seq increment by 50 start with 1; +# create sequence t_flow_sub_process_record_seq increment by 50 start with 1; +# 注意:INCREMENT BY(序列步长)与下方的 jdbc.batch_size(JDBC 批插行数)是两个独立概念, +# 两者无需一致;真正必须一致的是 序列步长 == allocationSize。 spring.jpa.properties.hibernate.jdbc.batch_size=100 spring.jpa.properties.hibernate.order_inserts=true spring.jpa.properties.hibernate.order_updates=true diff --git a/flow-engine-starter-infra/src/main/java/com/codingapi/flow/infra/entity/FlowRecordEntity.java b/flow-engine-starter-infra/src/main/java/com/codingapi/flow/infra/entity/FlowRecordEntity.java index 75716479..9e8c8764 100644 --- a/flow-engine-starter-infra/src/main/java/com/codingapi/flow/infra/entity/FlowRecordEntity.java +++ b/flow-engine-starter-infra/src/main/java/com/codingapi/flow/infra/entity/FlowRecordEntity.java @@ -11,7 +11,8 @@ public class FlowRecordEntity { * 记录id */ @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "flow_record_seq") + @SequenceGenerator(name = "flow_record_seq", sequenceName = "t_flow_record_seq", allocationSize = 50) private Long id; /** * 工作id diff --git a/flow-engine-starter-infra/src/main/java/com/codingapi/flow/infra/entity/FlowTodoMargeEntity.java b/flow-engine-starter-infra/src/main/java/com/codingapi/flow/infra/entity/FlowTodoMargeEntity.java index 5d699e8c..62f9d3a3 100644 --- a/flow-engine-starter-infra/src/main/java/com/codingapi/flow/infra/entity/FlowTodoMargeEntity.java +++ b/flow-engine-starter-infra/src/main/java/com/codingapi/flow/infra/entity/FlowTodoMargeEntity.java @@ -9,7 +9,8 @@ public class FlowTodoMargeEntity { @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "flow_todo_marge_seq") + @SequenceGenerator(name = "flow_todo_marge_seq", sequenceName = "t_flow_todo_marge_seq", allocationSize = 50) private Long id; /** * 待办id diff --git a/flow-engine-starter-infra/src/main/java/com/codingapi/flow/infra/entity/FlowTodoRecordEntity.java b/flow-engine-starter-infra/src/main/java/com/codingapi/flow/infra/entity/FlowTodoRecordEntity.java index 88555dda..69387f30 100644 --- a/flow-engine-starter-infra/src/main/java/com/codingapi/flow/infra/entity/FlowTodoRecordEntity.java +++ b/flow-engine-starter-infra/src/main/java/com/codingapi/flow/infra/entity/FlowTodoRecordEntity.java @@ -14,7 +14,8 @@ public class FlowTodoRecordEntity { *

使用序列生成(而非数据库自增),配合 hibernate 批插,降低高频批量写表的 DB 往返。 */ @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "flow_todo_record_seq") + @SequenceGenerator(name = "flow_todo_record_seq", sequenceName = "t_flow_todo_record_seq", allocationSize = 50) private Long id; /** diff --git a/flow-engine-starter-infra/src/main/java/com/codingapi/flow/infra/entity/SubProcessRecordEntity.java b/flow-engine-starter-infra/src/main/java/com/codingapi/flow/infra/entity/SubProcessRecordEntity.java index ef0da7c6..b9de6b28 100644 --- a/flow-engine-starter-infra/src/main/java/com/codingapi/flow/infra/entity/SubProcessRecordEntity.java +++ b/flow-engine-starter-infra/src/main/java/com/codingapi/flow/infra/entity/SubProcessRecordEntity.java @@ -7,6 +7,7 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Lob; +import jakarta.persistence.SequenceGenerator; import jakarta.persistence.Table; import jakarta.persistence.UniqueConstraint; import jakarta.persistence.Version; @@ -28,7 +29,8 @@ public class SubProcessRecordEntity { * 主键,由序列生成(替代数据库自增,配合 hibernate 批插降低批量往返) */ @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "flow_sub_process_record_seq") + @SequenceGenerator(name = "flow_sub_process_record_seq", sequenceName = "t_flow_sub_process_record_seq", allocationSize = 50) private Long id; /** From 4d74edbc774552ed4504371adbe8433c96712953 Mon Sep 17 00:00:00 2001 From: lorne <1991wangliang@gmail.com> Date: Mon, 17 Aug 2026 22:57:33 +0800 Subject: [PATCH 2/2] =?UTF-8?q?docs:=20=E6=96=B0=E5=A2=9E=E8=BE=BE?= =?UTF-8?q?=E6=A2=A6=E4=B8=BB=E9=94=AE=E5=BA=8F=E5=88=97=E9=A2=84=E5=BB=BA?= =?UTF-8?q?=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 提供 t_flow_record/t_flow_todo_record/t_flow_todo_marge/t_flow_sub_process_record 四张 SEQUENCE 主键表的建序脚本 - 幂等可反复执行;START WITH 自动取 表 max(id)+1,表空为 1,规避撞历史主键 - INCREMENT BY 固定 50,与实体 allocationSize=50 严格一致,避免 pooled 优化器主键重复 Co-Authored-By: Claude --- .../src/main/resources/sql/dm-sequences.sql | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 flow-engine-example/src/main/resources/sql/dm-sequences.sql diff --git a/flow-engine-example/src/main/resources/sql/dm-sequences.sql b/flow-engine-example/src/main/resources/sql/dm-sequences.sql new file mode 100644 index 00000000..0c4b20bd --- /dev/null +++ b/flow-engine-example/src/main/resources/sql/dm-sequences.sql @@ -0,0 +1,74 @@ +-- ===================================================================== +-- 达梦( DM ) 主键序列预建脚本 +-- ===================================================================== +-- 适用表( SEQUENCE 主键,配合 hibernate 批插 ): +-- t_flow_record -> t_flow_record_seq +-- t_flow_todo_record -> t_flow_todo_record_seq +-- t_flow_todo_marge -> t_flow_todo_marge_seq +-- t_flow_sub_process_record-> t_flow_sub_process_record_seq +-- +-- 序列名 / 步长 与实体 @SequenceGenerator(sequenceName=..., allocationSize=50) 严格一致, +-- 请勿修改,否则 hibernate 会在 insert 时报“无法解析的成员访问表达式[...NEXTVAL]”或出现主键重复。 +-- +-- 特性: +-- * INCREMENT BY 固定 50(必须 == allocationSize,paired/pooled 优化器要求,否则可能主键重复) +-- * START WITH 自动取 「表 max(id) + 1」:表为空则 1,表有历史数据则最大 id+1(绝不撞已有主键) +-- * 幂等:序列已存在则跳过,可反复执行 +-- * 基于当前登录用户(USER)所在模式,与表和序列归属一致 +-- +-- 执行方式:DBA 工具(达梦管理工具/disql) 以应用同款账号(默认 SYSDBA) 执行本脚本即可。 +-- ===================================================================== + +DECLARE + v_cnt INT; + v_start BIGINT; +BEGIN + -- ---------- 1. t_flow_record_seq ---------- + SELECT COUNT(*) INTO v_cnt FROM all_sequences + WHERE sequence_name = 'T_FLOW_RECORD_SEQ' AND sequence_owner = USER; + IF v_cnt = 0 THEN + BEGIN + SELECT NVL(MAX(id), 0) + 1 INTO v_start FROM t_flow_record; + EXCEPTION WHEN OTHERS THEN + v_start := 1; -- 表不存在或为空 + END; + EXECUTE IMMEDIATE 'CREATE SEQUENCE t_flow_record_seq INCREMENT BY 50 START WITH ' || v_start; + END IF; + + -- ---------- 2. t_flow_todo_record_seq ---------- + SELECT COUNT(*) INTO v_cnt FROM all_sequences + WHERE sequence_name = 'T_FLOW_TODO_RECORD_SEQ' AND sequence_owner = USER; + IF v_cnt = 0 THEN + BEGIN + SELECT NVL(MAX(id), 0) + 1 INTO v_start FROM t_flow_todo_record; + EXCEPTION WHEN OTHERS THEN + v_start := 1; + END; + EXECUTE IMMEDIATE 'CREATE SEQUENCE t_flow_todo_record_seq INCREMENT BY 50 START WITH ' || v_start; + END IF; + + -- ---------- 3. t_flow_todo_marge_seq ---------- + SELECT COUNT(*) INTO v_cnt FROM all_sequences + WHERE sequence_name = 'T_FLOW_TODO_MARGE_SEQ' AND sequence_owner = USER; + IF v_cnt = 0 THEN + BEGIN + SELECT NVL(MAX(id), 0) + 1 INTO v_start FROM t_flow_todo_marge; + EXCEPTION WHEN OTHERS THEN + v_start := 1; + END; + EXECUTE IMMEDIATE 'CREATE SEQUENCE t_flow_todo_marge_seq INCREMENT BY 50 START WITH ' || v_start; + END IF; + + -- ---------- 4. t_flow_sub_process_record_seq ---------- + SELECT COUNT(*) INTO v_cnt FROM all_sequences + WHERE sequence_name = 'T_FLOW_SUB_PROCESS_RECORD_SEQ' AND sequence_owner = USER; + IF v_cnt = 0 THEN + BEGIN + SELECT NVL(MAX(id), 0) + 1 INTO v_start FROM t_flow_sub_process_record; + EXCEPTION WHEN OTHERS THEN + v_start := 1; + END; + EXECUTE IMMEDIATE 'CREATE SEQUENCE t_flow_sub_process_record_seq INCREMENT BY 50 START WITH ' || v_start; + END IF; +END; +/ \ No newline at end of file