我正在使用Spring Roo开发一个Spring Web应用程序,仅用于生成持久层类(Web应用程序本身正在使用ZK框架进行开发),使用Roo活动记录模式。
我有一个简单的问题就是从db中检索实体(特别是从持久化类User
,相应的表名为my_user
),让在UI中编辑字段,以及然后将修改后的实体保存在db。
如果我正确地做事,在我的控制器类中,我有方法(A)检索具有username
可用的用户数据:这是通过调用
User user = User.findUsersByUsernameEquals(username).getSingleResult()
并且似乎工作正常(数据在UI上正确显示)和(B)将实体数据保存回数据库。为此,我称之为方法
user.merge()
问题在于,在调用merge()
时,会生成以下异常,因此修改后的数据不会保存在数据库中。
org.hibernate.exception.ConstraintViolationException: could not execute statement; nested exception is javax.persistence.PersistenceException:
org.hibernate.exception.ConstraintViolationException: could not execute statement[SQL: 1062, 23000]
...
caused by:
...
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:
Duplicate entry '<username value>' for key '...'
注意:
1)User
实体作为自动生成的Id密钥。使用Roo生成时,username
字段(非密钥)标记为--unique
。如果我尝试重新生成删除username
上的唯一要求的模式,则合并的效果是在数据库上创建第二条记录(不提供任何异常),具有相同的用户名和不同的Id值(显然不是我申请的理想行为。)
2)查看日志,hibernate(JPA下使用的持久性提供程序)实际上尝试执行sql INSERT
语句(我原本期望UPDATE
):
[DEBUG] (org.hibernate.SQL:104) insert into my_user (address, email, enabled, firstname, password, surname, telephone, username, version) values (?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into my_user (address, email, enabled, firstname, password, surname, telephone, username, version) values (?, ?, ?, ?, ?, ?, ?, ?, ?)
3)如果我调用user.persist()
而不是user.merge()
我得到了与之前相同的异常(这只是一次尝试,调用.persist()不应该是正确的保存方式如果我理解的话,修改后的实体。)
我刚刚开始JPA和Roo编程,所以我不确定我是否以正确的方式做事。我得到的印象是,在我使用findUsersByUsernameEquals和merge()读取数据的那一刻,问题可能与实体分离有关,但这只是一个假设。
提前致谢,
答案 0 :(得分:1)
我想我已经找到了解决方案,感谢这个帖子:JPA Hibernate merge performs insert instead of update
问题是由于Roo在创建jpa实体时自动添加version
字段。我用一组INSERT INTO
填充我的初始数据库,其中我没有设置此字段的值,导致它被初始化为null。
如果我在INSERT INTO
语句中将此值设置为0,则代码可以正常工作。 (当使用persist()
从java代码直接创建实例时,这可能永远不会发生,我猜这正确地初始化了版本字段)