一、MyBatis-Plus主键错误
Mybatis-Plus会将以下两种情况的字段当作主键字段: 1、字段名称为id的字段 2、被@TableId注解标记的字段 在NONE或AUTO主键策略下,Mybatis-Plus本身的insert方法生成的insert语句中不会设置这两种字段的值,也就是代码中如果自行设置了这两种字段的值或者前端传递了这两种字段的值,Mybatis-Plus本身的insert方法也不会设置这两种字段的值,那么在使用Mybatis-Plus自带的insert方法时可能会遇到如下的几个报错(如果是自己写的sql,在执行时以自己的sql为准;并且如果sql中设置了主键的值,那么插入的时候也会按照设置的主键值插入,不会根据如表中的主键自增进行设置主键值):
错误一、Field ‘xxx’ doesn’t have a default value
使用mybatis-plus的insert方法的时候,报错Field ‘id’ doesn’t have a default value 错误提示的意思就是:id字段没有一个默认值 错误原因:id字段被Mybatis-Plus识别为了主键字段,那么使用Mybatis-Plus自带的insert方法生成的insert语句中不会设置id字段的值,此时数据库中id字段也未设置自动递增,那么就出现insert的时候id字段不设置值而主键是非空字段,因此出现无默认值的错误。 解决方案: 1.如果是普通字段可以通过设置默认值解决,第一种是通过设置数据库中该字段有一个默认值,第二种是insert之前将构建的对象为该字段设置默认值 -我这里是报的id的错误,id是表中的主键字段是唯一性索引,所以直接设置默认值的话会主键重复 2.针对主键或者唯一性索引的字段,如果设置默认值的话后面insert的数据如果使用该默认值,因为这个默认值已经被之前的insert的数据占用,会报错误二,那么如果是主键可以使用数据库提供的自动递增解决(前提是主键是数字类型而非字符串类型)或者自己生成唯一性的值(自己生成唯一性的值需要调整下主键的策略,否则NONE默认类型的策略和AUTO类型的策略Mybatis-Plus自带的insert方法不会设置主键值,或者自己写sql设置主键值),如果是非主键字段而是唯一性索引字段,那么可以在代码中将该字段设置为唯一的值,如果有分表的话需要考虑全局唯一索引的生成,比如雪花算法、UUID、redis、zookeeper等方式生成
错误二、Duplicate entry ‘xx’ for key ‘xxx.PRIMARY’
使用mybatis-plus的insert方法的时候,报错Duplicate entry ‘1’ for key ‘test_idcard.PRIMARY’ 错误提示的意思就是:表test_idcard的主键存在重复的值 1 错误原因:表中已经存在主键值为1的数据,然后本次插入使用的主键值也是1 解决方案:针对主键或唯一性索引的字段只要出现插入的数据是该字段在表中已存在的值都会出现该错误,解决方案就是错误一中提到的第二点,不论是使用数据库自带的自增还是生成唯一值都可以。
二、MyBatis-Plus主键策略
以下关于主键策略的介绍都是基于Mybatis-Plus自带的insert方法进行 MyBatis-Plus GitHub主键策略介绍
MyBatis-Plus 官方文档主键策略介绍 本篇介绍的是基于mybatis-plus 3.3.2的版本 @TableId注解的默认主键策略是 NONE 总共有8种主键策略,分别是: AUTO-数据库ID自增 NONE-无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT) INPUT-insert前自行set主键值 ASSIGN_ID-分配ID(主键类型为Number(Long和Integer)或String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法) ASSIGN_UUID-分配UUID,主键类型为String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认default方法) ID_WORKER-分布式全局唯一ID 长整型类型(please use ASSIGN_ID) UUID-32位UUID字符串(please use ASSIGN_UUID) ID_WORKER_STR-分布式全局唯一ID 字符串类型(please use ASSIGN_ID) 先看一下表的sql,表的id主键采用的数据库自增策略
1、AUTO-数据库ID自动递增
AUTO类型的主键策略即告诉Mybatis-Plus该主键值由数据库自动递增实现,那么在调用Mybatis-Plus自带的insert方法的时候不会设置主键的值
2、NONE-无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
NONE类型的主键策略是Mybatis-Plus的默认主键策略,和AUTO类型一样,Mybtais-Plus自带的insert方法不会设置主键的值,此时需要数据库主键自增来维护主键的值
3、INPUT-insert前自行set主键值
INPUT类型的主键策略需要在调用Mybatis-Plus自带的insert方法之前,设置主键的值,并且Mybatis-Plus自带的insert方法生成的insert语句会设置主键的值,如果在调用insert方法之前未设置主键值(主键值是前端传递或后端生成都可以),那么报错如下:Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Column ‘id’ cannot be null 上述错误的前提是:数据库也未设置主键自增,如果数据库有设置主键自增,调用insert方法时未设置主键值也不会有错误,数据库会按照自增值设置主键值,如果有设置主键值则按照设置的主键值插入,不遵循数据库自增值。
4、ASSIGN_ID-分配ID(主键类型为Number(Long和Integer)或String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)
ASSIGN_ID类型的主键策略调用Mybatis-Plus自带的insert方法生成的insert语句会设置主键值,如果有自行设置主键值则使用自行设置的主键值,如果未设置则通过雪花算法生成对应的主键值,此时如果数据库中有设置主键自增,也还是会采用自行设置的主键值或雪花算法生成的主键值。 注意:因为生成的雪花算法的值比较大,所以数据库中主键类型应设置为字符串(如char/varchar)或bigint类型,对应Entity的主键类型为String或Long类型,否则可能会报错如下: Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column ‘id’ at row 1(原因是因为数据库中主键字段的长度不够导致的)
5、ASSIGN_UUID-分配UUID,主键类型为String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认default方法)
ASSIGN_UUID类型的主键策略调用Mybatis-Plus自带的insert方法生成的insert语句会设置主键值,如果有自行设置主键值则使用自行设置的主键值,如果未设置则通过UUID生成对应的主键值,此时如果数据库中有设置主键自增,也还是会采用自行设置的主键值或UUID生成的主键值。 注意:因为UUID是字符串,所以采用ASSIGN_UUID策略时,表中的主键只能设置为字符串类型(因为UUID的长度固定32所以主键字段长度设置为32),那么也就不能设置数据库主键自增,只能通过自行设置主键值或自动生成UUID的主键值
6、ID_WORKER-分布式全局唯一ID 长整型类型(please use ASSIGN_ID)
ID_WORKER主键策略,生成数字的主键值,已经过时;分布式主键可以采用如zookeeper、redis等方式生成;雪花算法和UUID也可以,但有极低极低的概率出现重复值,此时因为主键是唯一性索引,那么可以捕获异常,进行插入重试
7、UUID-32位UUID字符串(please use ASSIGN_UUID)
UUID主键策略和ASSIGN_UUID策略一致,UUID类型有标记已经过时,推荐使用ASSIGN_UUID
8、ID_WORKER_STR-分布式全局唯一ID 字符串类型(please use ASSIGN_ID)
ID_WORKER_STR主键策略,生成字符串的主键值,已经过时;分布式主键可以采用如zookeeper、redis等方式生成;雪花算法和UUID也可以,但有极低极低的概率出现重复值,此时因为主键是唯一性索引,那么可以捕获异常,进行插入重试
三、总结
如果对于Mybatis-Plus自带的insert/update方法会生成什么样的sql语句不熟悉,那么建议自己写sql语句,避免一些不必要的错误发生;如果熟悉的话,那么根据项目的情况选择合适的主键策略,一般来说在项目未分表的情况下很多时候都是使用的数据库id自增,那么也就是AUTO、NONE主键策略使用的最多,其次是INPUT策略自己设置主键值,ASSIGN_ID及ASSIGN_UUID使用很少(因为对于索引树来讲在保证字段值有区分度的情况下,应当是越短越好,可以在调整索引树的结构时速度更快),分表的场景一般也是自己实现主键值生成。
|