mybits对达梦数据插入数据时,自增列返回的值不对

文章讲述了作者在将pg库数据迁移到梦数据库时遇到的问题,用户新增时自增ID导致关联用户角色失败。解决方法是通过查询唯一的用户名来确保数据一致性。

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

今天在做pg库转达梦数据库时,程序运行,发现一个问题。对用户进行新增时,发现用户角色没有同时添加成功。经过代码排查,发现在对用户进行新增时,用户的id是自增的。插入user表后,user对象的userid和数据库的值不对。导致后续插入用户角色表的时候,关联错误。网上找了下资料,也没找到好的解决办法。我这边的解决办法是,通过用户名再去数据库查询一次,因为用户名也是惟一的。

<think>我们面对的问题是:达梦数据库在使用MyBatisPlus进行批量插入,自增列为null导致BatchUpdateException异常,异常信息为“当 IDENTITY_INSERT 设置为 OFF ,不能为表 'xxx' 中的标识列插入显式”。 根据引用[3]中的描述,类似的问题在SQL Server中出现过,是因为数据库表的标识列(自增列)没有设置自动加,导致在插入如果显式给自增列(包括赋为null)会报错。而达梦数据库也可能存在类似的机制。 解决方案思路: 1. 检查数据库表结构,确保自增列已经设置为“自动加”(标识列)。 2. 在MyBatisPlus中,我们通常使用`@TableId`注解来标识主键,并设置主键生成策略。对于自增列,我们通常使用`IdType.AUTO`。 3. 在批量插入,确保没有显式给自增列(即不要设置自增列,或者设置为null,但需要数据库允许插入null自动生成自)。然而,达梦数据库可能不允许在自增列插入null(当IDENTITY_INSERT为OFF),所以我们需要避免给自增列。 但是,MyBatisPlus插入,如果实体对象的主键字段有(非null)会尝试插入,如果主键字段为null,则不会插入,由数据库生成。所以,我们通常的做法是让实体的主键字段为null,这样MyBatisPlus在生成SQL就不会包含自增列,从而由数据库自动生成。 然而,在批量插入,我们可能遇到一个问题:即使我们将主键字段设置为null,MyBatisPlus生成的SQL语句中可能仍然包含了自增列(列名出现在插入列中),并且赋为null,这就会导致达梦数据库抛出异常。 因此,我们需要调整MyBatisPlus的配置或实体注解,使得在批量插入不包含自增列。 具体步骤: 步骤1:确认数据库表结构 在达梦数据库中,检查表结构,确保自增列已经设置为“自”(标识列)。可以使用如下SQL查询表结构: ```sql SELECT * FROM USER_TAB_COLUMNS WHERE TABLE_NAME = '表名'; ``` 或者使用图形化工具查看,确保该列是自增列。 步骤2:在MyBatisPlus中配置主键生成策略 在实体类的主键字段上,使用`@TableId`注解,并指定`type = IdType.AUTO`,表示使用数据库的自策略。 例如: ```java @TableId(value = "id", type = IdType.AUTO) private Long id; ``` 步骤3:在批量插入,确保主键字段为null 在插入之前,将每个实体的id字段设置为null,这样MyBatisPlus就不会尝试插入该字段(理想情况下)。 但是,MyBatisPlus的默认行为在插入,如果主键字段为null,它仍然会在插入的列中包含该字段(赋为null),这会导致达梦数据库报错。因此,我们需要修改MyBatisPlus的全局配置,告诉它在插入忽略null字段。 步骤4:配置MyBatisPlus忽略null字段 在MyBatisPlus的全局配置中,设置插入策略为忽略null字段: ```java mybatis-plus: global-config: db-config: insert-strategy: not_empty # 或者使用ignore,但注意:not_empty会忽略空字符串和null,ignore只忽略null ``` 或者,我们可以使用`@TableField`注解在字段上设置插入策略: ```java @TableField(insertStrategy = FieldStrategy.NOT_INSERT) private Long id; ``` 但是,对于主键字段,我们通常不希望插入包含,所以我们可以使用`insertStrategy = FieldStrategy.NEVER`,表示该字段永远不会出现在插入语句中。 因此,我们可以将主键字段的注解改为: ```java @TableId(value = "id", type = IdType.AUTO) @TableField(insertStrategy = FieldStrategy.NEVER) private Long id; ``` 这样,在插入操作中,MyBatisPlus就不会将id字段包含在插入列中。 步骤5:使用MyBatisPlus的批量插入方法 使用MyBatisPlus的`saveBatch`方法进行批量插入,并确保在插入之前每个实体的id字段为null(或者不设置)。 步骤6:处理事务 批量插入,如果部分插入失败,我们需要处理事务回滚。建议在业务方法上使用`@Transactional`注解。 如果以上步骤仍然不能解决问题,我们可以考虑使用MyBatis的XML映射文件,自定义插入SQL,在SQL中不包含自增列。 自定义SQL示例(在Mapper.xml中): ```xml <insert id="insertBatch"> INSERT INTO 表名 (col1, col2, ...) VALUES <foreach collection="list" item="item" separator=","> (#{item.col1}, #{item.col2}, ...) </foreach> </insert> ``` 在这个SQL中,我们显式指定要插入的列(不包含自增列),这样数据库就会自动生成自增列。 总结解决方案: 1. 确保数据库表自增列设置正确。 2. 在实体类的主键字段上使用`@TableId(type = IdType.AUTO)`和`@TableField(insertStrategy = FieldStrategy.NEVER)`。 3. 配置MyBatisPlus全局忽略null字段(可选,如果步骤2已经设置则不需要)。 4. 如果仍然不行,使用自定义SQL进行批量插入,避免包含自增列。 注意:达梦数据库可能需要设置自增列允许插入null,但通常自增列数据库中是自动生成的,不应该插入任何(包括null)。因此,最根本的方法是确保生成的SQL语句中不包含自增列。 根据引用[3]中的经验,数据库表需要设置标识规范(自)并且设置自动加。所以,请先检查数据库表结构。 如果问题仍然存在,可能需要检查达梦数据库的JDBC驱动版本,以及MyBatisPlus的版本兼容性。 最后,如果使用的是MyBatisPlus的批量插入方法,注意默认情况下,它并不是真正的批量插入(而是循环单条插入),需要配置使用批处理模式。在application.yml中配置: ```yaml mybatis-plus: configuration: default-executor-type: batch ``` 并且,在数据源url中需要添加参数`rewriteBatchedStatements=true`(如果达梦支持的话)。 但是,请注意,达梦数据库的JDBC驱动可能不支持`rewriteBatchedStatements`,所以可能需要使用自定义的批量插入方法。 因此,如果遇到批量插入性能问题,也可以考虑使用自定义的批量插入SQL(通过XML映射文件实现)。 希望这些解决方案能帮助您解决异常。 §§相关问题§§ 1. 达梦数据库如何设置自增列? 2. MyBatisPlus中如何配置批量插入? 3. 如何自定义MyBatisPlus的SQL语句? 4. MyBatisPlus中主键生成策略有哪些? 5. 如何处理数据库批量插入中的部分失败情况?</think>### 达梦数据库 MyBatisPlus 批量插入增列为 null 的解决方案 #### 问题分析 当达梦数据库的自增列(标识列)在 MyBatisPlus 批量插入被赋为 `null`,会触发 `java.sql.BatchUpdateException` 异常,错误信息为:**当 IDENTITY_INSERT 设置为 OFF ,不能为表 'xxx' 中的标识列插入显式**。核心原因是: 1. 达梦数据库的自增列需显式开启 `IDENTITY_INSERT` 才能插入显式(含 `null`)[^3]。 2. MyBatisPlus 默认会将实体类的 `null` 字段写入 SQL,导致自增列被显式赋为 `null`。 --- ### 解决方案 #### 方法 1:配置 MyBatisPlus 忽略自增列(推荐) 在实体类的主键字段添加注解,禁止插入操作包含自增列: ```java public class YourEntity { @TableId(value = "id", type = IdType.AUTO) // 声明自主键 @TableField(insertStrategy = FieldStrategy.NEVER) // 禁止插入包含该字段 private Long id; // 自增列 // 其他字段... } ``` **效果**: 生成的 SQL 将自动排除自增列,如: ```sql INSERT INTO your_table (col1, col2) VALUES (?, ?) -- 不包含自增列 ``` #### 方法 2:开启 IDENTITY_INSERT(需谨慎) 在批量插入前开启 `IDENTITY_INSERT`,插入后关闭: ```java @Transactional public void batchInsert(List<YourEntity> list) { // 开启 IDENTITY_INSERT jdbcTemplate.execute("SET IDENTITY_INSERT your_table ON"); // 批量插入(需确保实体的 id 不为 null) yourService.saveBatch(list); // 关闭 IDENTITY_INSERT jdbcTemplate.execute("SET IDENTITY_INSERT your_table OFF"); } ``` **注意**: - 需确保插入的实体 `id` 字段非 `null`(如由程序生成 ID)。 - 需处理事务和异常,避免未关闭 `IDENTITY_INSERT`[^1]。 #### 方法 3:自定义 SQL 批量插入 使用 XML 或注解编写 SQL,动态排除自增列: ```xml <!-- Mapper.xml --> <insert id="insertBatch"> INSERT INTO your_table (col1, col2) VALUES <foreach item="item" collection="list" separator=","> (#{item.col1}, #{item.col2}) <!-- 不包含 id 字段 --> </foreach> </insert> ``` --- ### 关键配置验证 1. **数据库表结构**: 确认达梦表的自增列已启用“标识规范”和“自动递”[^3]。 ```sql CREATE TABLE your_table ( id BIGINT IDENTITY(1,1) PRIMARY KEY, -- 标识列 col1 VARCHAR(50), col2 INT ); ``` 2. **MyBatisPlus 配置**: 在 `application.yml` 中启用批处理: ```yaml mybatis-plus: global-config: db-config: id-type: auto # 全局自主键 ``` --- ### 总结流程 ```mermaid graph TD A[开始] --> B{自增列是否赋为 null?} B -->|是| C[方案1:配置 @TableField 忽略自增列] B -->|需显式插入 ID| D[方案2:开启 IDENTITY_INSERT] C --> E[生成不包含自增列的 SQL] D --> F[确保 ID 非空并管理事务] E --> G[批量插入成功] F --> G G --> H[结束] ``` 通过以上方案,可避免 `BatchUpdateException` 异常,确保批量插入增列数据库自动生成。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值