问题
I am new to JPA and was experimenting a bit in hope of figuring out the Entity lifecycle model. I expected the code below to throw an EntityExistsException. However, instead of throwing the expected exception, it just creates a new row in database table with a new primary key (incremented by one).
Can anyone explain this? I suspect it might have something to do with the @GeneratedValue annotation on my ID field in combination with my autoincrementing primary key in the corresponding table.
Below you can find 3 snippets: the code I try to run, my entity definition and my table design.
I would like to thank you in advance for shining your light on my misunderstanding.
Kind regards
ps: I use eclipselink as jpa implementation and a Derby database
Script:
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();
Table Design:
CREATE TABLE teachers (id INT GENERATED ALWAYS AS IDENTITY, firstname VARCHAR(20) ,lastname VARCHAR(40), PRIMARY KEY(id))
Entity definition:
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;
}
}
回答1:
EntityExistsException will be thrown only when you are persisting the same entity associated with DB.
but here you have created one Object with some values and then persisting 2 times with primary key generated automatically unique for each persistence.
because
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
will generate new ID each time you call persist method with Entity manager. and henc eboth the entities becomes different with respect to DB is concerned. because DB cares for primary key to be unque to distinguish each record.
so better you do this to get that exception
get the entity from DB first and change it and try to call save on it
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();
or else remove autogeneration of primary key and assign it manually same id both the time. let me know for any other questions
回答2:
It is clear form exception the entity already exists, if already exists the EntityExistsException may be thrown when the persist operation is invoked.
EclipseLink does not include the Id in the INSERT for Derby IDENTITY, so you have something odd going on.
Did you previously use another generator strategy and not recompile/deploy your code correctly?
Also try setting your platform using the"eclipselink.target-database"="Derby" in your persistence.xml.
make little change
id INT GENERATED ALWAYS AS IDENTITY
use START WITH 1, INCREMENT BY 1 for PK.
id INT GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1)
来源:https://stackoverflow.com/questions/23217972/jpa-throws-no-entityexistsexception-but-generates-a-duplicate-row-auto-generate