JPA不会抛出EntityExistsException但会生成重复的行(自动生成的PK)

时间:2014-04-22 11:20:07

标签: java jpa eclipselink derby

我是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;
    }
}

2 个答案:

答案 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)