
@SQLInsert(sql = "insert ignore into tb_vip_code (code, duration) value (?, ?)") public class VipCode extends BaseModel { private static final long serialVersiOnUID= -4697221755301869573L; private String code; private Integer duration; private Integer status; privae Long userId; // 构造函数 } 如上实体类定义,@SQLInsert 注解的本意是在批量插入数据遇到唯一性约束时忽略,继续插入不重复的数据,但在调用 repository 的 save 方法插入数据是,总是报参数越界错误,有朋友遇到过吗?
Caused by: java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 2).
单元测试代码如下:
@Test public void addOne() throws Exception { VipCode vipCode = new VipCode("123456", 1); service.addOne(vipCode); } 第一个问题解决了,SQL 里要把除自增主键外的所有字段写全,而且顺序要跟实体类属性定义的顺序保持一致,父类的属性在最前面,后面接着是子类的属性,如下:
insert ignore into tb_vip_code (create_at, update_at, code, duration, status, user_id) values (?, ?, ?, ?, ?, ?)
但,又出现了另外一个问题,插入不重复记录的时候,可以正常插入数据,插入重复记录报异常:
org.springframework.orm.jpa.JpaSystemException: The database returned no natively generated identity value
欢迎大家继续讨论。
1 reid2017 OP 自己 up 一下 |
2 uuau 2018 年 11 月 14 日 你先找到 Hibernate 生成的 insert 语句,在此基础上 diy。 |
3 johnniang 2018 年 11 月 14 日 这个错误似乎是因为参数的问题。本来只需要两个参数,而 https://raymondhlee.wordpress.com/2012/01/07/using-sqlinsert-to-insert-entity-in-hibernate-with-custom-sql/ |
5 Aideboss 2018 年 11 月 14 日 要不还是写在 VipCodeRepository 里面吧? ``` interface VipCodeRepository { @Modify @Query(sql = "..." , nativeSql = true) @Transcational public void save(SString code, int duration); } ``` |
6 sutra 2018 年 11 月 14 日 status 和 userId 字段是怎么定义的?还有 BaseModel 里面是不是有 id 字段的定义,怎么没有在 @SQLInsert 里出现呢? |
7 TommyLemon 2018 年 11 月 14 日 @SQLInsert(sql = "insert ignore into tb_vip_code (code, duration) value (?, ?)") 首先 value 得改成 values 如果还不行,可能就是如楼上所说 BaseModel 里有额外的字段,很可能还是用基本类型有默认值的。 如果是基本类型,改成对应的封装类型再试。 另外你代码都没发全,都不知道构造函数里是否给其它字段 set 了值,难以判断。 |
8 TommyLemon 2018 年 11 月 14 日 @TommyLemon 默认值得去掉,或者改成 null。 |
9 TommyLemon 2018 年 11 月 14 日 @TommyLemon 如果以上试过都不行,或许是 serialVersionUID 有个对应的 getSerialVersionUID 方法(自动生成时错误勾选), 导致序列化时多转了一个字段。 某些 JSON 库可以通过 @JSONField(serialize = false) 这种注解等方式来忽略要序列化的变量或方法。 |
11 reid2017 OP @TommyLemon 把 serialVersionUID 注释掉也不行,构造函数里没有对其它字段设置值 ``` public VipCode(String code, Integer duration) { this.code = code; this.duration = duration; } ``` |
14 TommyLemon 2018 年 11 月 15 日 @reid2017 也有可能这个库默认加了一个 主键 或 创建时间 之类的字段, 最好还是断点调试下下它最终到 JDBC 时 set 进去的值,这样最容易看出问题所在。 |
15 sutra 2018 年 11 月 15 日 |
16 passerbytiny 2018 年 11 月 15 日 把 ID 的 @GeneratedValue 去掉试试,你用了自定义 SQL,GeneratedValue 很有可能被判定成由程序或序列自动生成(而不是数据库自增长)。 |
17 ZiLong 2018 年 11 月 15 日 加日志看下最终执行的 sql 和对应的参数 |
18 reid2017 OP @passerbytiny 去掉这注解就需要自己手动给主键赋值了 |
19 reid2017 OP |
20 passerbytiny 2018 年 11 月 15 日 差不多知道问题了,跟 ID 没关系,而是你的实体有 4 个非自动属性,SQl 语句只有两个字段。Hibernate 不会在手工 SQL 处理上放太多重心,这里可能只是简单做了实体属性跟 SQL 字段的映射,但是没有自动判断参数数量。 你的 SQL 语句要把所有字段写全,另外除了“类属性表字段”的自动映射外,不要期望 Hibernate 帮你做其它的自动处理。 你现在这个是批量、仅部分字段、遇重复就忽略的操作,已经是一个很复杂的数据处理了,建议在 Dao/Repository,甚至 Service 中处理,并且全盘交给 SQL,不要再实体定义上处理。 |
21 reid2017 OP 主键 ID 策略如下: @Id @GeneratedValue(strategy = GenerationType.IDENTITY) //@GeneratedValue(strategy = GenerationType.AUTO) private Long id; 两个策略都尝试过,一样的异常。 |
22 sutra 2018 年 11 月 15 日 把日志打开吧,然后就知道生成的 SQL 语句到底什么样子了: <Logger name="org.hibernate.SQL" level="DEBUG" includeLocation="true" additivity="false"> <AppenderRef ref="file-hibernate" /> </Logger> <Logger name="org.hibernate.type" level="TRACE" includeLocation="true" additivity="false"> <AppenderRef ref="file-hibernate" /> </Logger> |