JPA 问题请教

2018-11-14 18:05:38 +08:00
 reid2017
@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;
    private 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);
    }
3510 次点击
所在节点    Java
22 条回复
reid2017
2018-11-14 18:07:55 +08:00
自己 up 一下
onnfee
2018-11-14 18:41:17 +08:00
你先找到 Hibernate 生成的 insert 语句,在此基础上 diy。
johnniang
2018-11-14 19:49:43 +08:00
这个错误似乎是因为参数的问题。本来只需要两个参数,而 https://raymondhlee.wordpress.com/2012/01/07/using-sqlinsert-to-insert-entity-in-hibernate-with-custom-sql/
johnniang
2018-11-14 19:50:27 +08:00
忽略 link 前面的文字 @reid2017
Aidenboss
2018-11-14 20:07:26 +08:00
要不还是写在 VipCodeRepository 里面吧?
```
interface VipCodeRepository {
@Modify
@Query(sql = "..." , nativeSql = true)
@Transcational
public void save(SString code, int duration);
}
```
sutra
2018-11-14 20:35:26 +08:00
status 和 userId 字段是怎么定义的?还有 BaseModel 里面是不是有 id 字段的定义,怎么没有在 @SQLInsert 里出现呢?
TommyLemon
2018-11-14 23:45:53 +08:00
@SQLInsert(sql = "insert ignore into tb_vip_code (code, duration) value (?, ?)")
首先 value 得改成 values
如果还不行,可能就是如楼上所说 BaseModel 里有额外的字段,很可能还是用基本类型有默认值的。
如果是基本类型,改成对应的封装类型再试。

另外你代码都没发全,都不知道构造函数里是否给其它字段 set 了值,难以判断。
TommyLemon
2018-11-14 23:46:17 +08:00
@TommyLemon 默认值得去掉,或者改成 null。
TommyLemon
2018-11-14 23:51:47 +08:00
@TommyLemon
如果以上试过都不行,或许是 serialVersionUID 有个对应的 getSerialVersionUID 方法(自动生成时错误勾选),
导致序列化时多转了一个字段。
某些 JSON 库可以通过 @JSONField(serialize = false) 这种注解等方式来忽略要序列化的变量或方法。
reid2017
2018-11-15 09:12:24 +08:00
@sutra
status 数据库里有设置默认值,userid 可空,BaseModel 时有 id 主键自增,这些应该都不影响吧
reid2017
2018-11-15 09:13:52 +08:00
@TommyLemon 把 serialVersionUID 注释掉也不行,构造函数里没有对其它字段设置值

```
public VipCode(String code, Integer duration) {
this.code = code;
this.duration = duration;
}
```
reid2017
2018-11-15 09:17:07 +08:00
@johnniang 跟文章描述的场景并不一样
reid2017
2018-11-15 09:18:08 +08:00
@Aidenboss 就是不想这样写啰,看到有这个注解应该试下
TommyLemon
2018-11-15 09:47:34 +08:00
@reid2017 也有可能这个库默认加了一个 主键 或 创建时间 之类的字段,
最好还是断点调试下下它最终到 JDBC 时 set 进去的值,这样最容易看出问题所在。
sutra
2018-11-15 10:05:34 +08:00
改成这样看看,换句话说就是把所有 @Column 都写全:
@SQLInsert(sql = "insert ignore into tb_vip_code (id, userId, code, duration) value (?, ?, ?, ?)")
passerbytiny
2018-11-15 10:20:42 +08:00
把 ID 的 @GeneratedValue 去掉试试,你用了自定义 SQL,GeneratedValue 很有可能被判定成由程序或序列自动生成(而不是数据库自增长)。
ZiLong
2018-11-15 10:47:25 +08:00
加日志看下最终执行的 sql 和对应的参数
reid2017
2018-11-15 11:01:56 +08:00
@passerbytiny
去掉这注解就需要自己手动给主键赋值了
reid2017
2018-11-15 11:06:33 +08:00
@ZiLong
Hibernate: insert ignore into tb_vip_code (code, duration) values (?, ?)
参数没打印出来
passerbytiny
2018-11-15 11:23:17 +08:00
差不多知道问题了,跟 ID 没关系,而是你的实体有 4 个非自动属性,SQl 语句只有两个字段。Hibernate 不会在手工 SQL 处理上放太多重心,这里可能只是简单做了实体属性跟 SQL 字段的映射,但是没有自动判断参数数量。

你的 SQL 语句要把所有字段写全,另外除了“类属性——表字段”的自动映射外,不要期望 Hibernate 帮你做其它的自动处理。

你现在这个是批量、仅部分字段、遇重复就忽略的操作,已经是一个很复杂的数据处理了,建议在 Dao/Repository,甚至 Service 中处理,并且全盘交给 SQL,不要再实体定义上处理。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/507859

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX