我是JPA的新手,正在尝试一下,希望能够找出实体生命周期模型。我希望下面的代码抛出一个EntityExistsException。但是,它不是抛出预期的异常,而是在数据库表中创建一个带有新主键的新行(加1)。
任何人都能解释一下吗?我怀疑它可能与我的ID字段上的@GeneratedValue注释以及相应表中的自动增量主键有关。
下面你可以找到3个片段:我尝试运行的代码,我的实体定义和我的表格设计。
我想提前感谢你对我的误解发光。
亲切的问候
ps:我使用eclipselink作为jpa实现和Derby数据库
脚本:
Teacher teacher = new Teacher("John","Doe","English");
//Persist John Doe
EntityManager em = Persistence.createEntityManagerFactory("jpatest").createEntityManager();
em.getTransaction().begin();
em.persist(teacher);
em.getTransaction().commit();
em.close();
//Try to persist John Doe a second time
em = Persistence.createEntityManagerFactory("jpatest").createEntityManager();
em.getTransaction().begin();
em.persist(teacher);
em.getTransaction().commit(); //I Expect a throw here
em.close();
表设计:
CREATE TABLE teachers (id INT GENERATED ALWAYS AS IDENTITY, firstname VARCHAR(20) ,lastname VARCHAR(40), PRIMARY KEY(id))
实体定义:
package testpackage;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
@Entity
@Table(name="teachers", schema="USERNAME")
public class Teacher {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String firstName;
private String lastName;
@Transient
private String course;
/**
* Zero argument constructor for JPA
*/
Teacher(){
}
public Teacher(String firstName, String lastName, String course){
this.firstName = firstName;
this.lastName = lastName;
this.course = course;
}
public int getId(){
return id;
}
public String getFirstName(){
return firstName;
}
public String getLastname(){
return lastName;
}
public String getCourse(){
return course;
}
public void setFirstName(String firstName){
this.firstName = firstName;
}
public void setLastName(String lastName){
this.lastName = lastName;
}
}
答案 0 :(得分:1)
仅当您持久保存与DB关联的同一实体时,才会抛出EntityExistsException。
但是在这里你创建了一个具有一些值的Object,然后使用为每个持久性自动生成的主键持久保存2次。
,因为
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
每次使用实体管理器调用persist方法时,都会生成新的ID。并且就实际情况而言,实体与DB有所不同。因为DB关心主键是unque来区分每条记录。
这样做更好,以获得该异常
首先从DB获取实体并更改它并尝试在其上调用save
EntityManager em = Persistence.createEntityManagerFactory("jpatest").createEntityManager();
em.getTransaction().begin();
Teacher teacher = em.find(Teacher.class,primary key)
em.persist(teacher);
em.getTransaction().commit();
em.close();
或者删除主键的自动生成,并在时间上手动分配相同的ID。 让我知道其他任何问题
答案 1 :(得分:0)
很明显表单异常实体已经存在,如果已经存在,则在调用persist操作时可能抛出EntityExistsException。
EclipseLink在INSERT for Derby IDENTITY中不包含Id,所以你有一些奇怪的事情发生。
您之前是否使用过其他生成器策略而未正确重新编译/部署代码?
还可以尝试使用persistence.xml中的“eclipselink.target-database”=“Derby”来设置平台。
稍作改动
id INT GENERATED ALWAYS AS IDENTITY
使用START WITH 1,INCREMENT BY 1表示PK。
id INT GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1)