Hibernate EntityManager 在 persist 操作时未抛出 EntityExistsException 异常

4

我有一个Hibernate EntityManager的问题。

这是我的DAO函数:

public Boolean create(T element)
{
    System.out.println("To persist: "+element);
    System.out.println("PersistanceHolder: "+holder);
    System.out.println("EntityManager: "+entityManager);
    System.out.println("CRUDDao: "+this);
    System.out.println("Thread: "+Thread.currentThread());

    entityManager.getTransaction().begin();

    try
    {
        entityManager.persist(element);
    }
    catch(EntityExistsException e)
    {
        entityManager.getTransaction().rollback();
        return Boolean.FALSE;
    }

    entityManager.getTransaction().commit();

    return Boolean.TRUE;
}

这是我的元素:

@Entity
public class Event {

    @Id
    String name;

    Maturity maturity;

    Integer delay;

    public Event() {
    }

    public Event(String name, Maturity maturity, Integer delay) {
        super();
        this.name = name;
        this.maturity = maturity;
        this.delay = delay;
    }

    public String getName() {
        return name;
    }
    public Maturity getMaturity() {
        return maturity;
    }
    public Integer getDelay() {
        return delay;
    }

    @Override
    public String toString() {
        return "Event [name=" + name + ", maturity=" + maturity + ", delay="
                + delay + ", toString()=" + super.toString() + "]";
    }
}

数据库中的元素如下所示:

Added: Event [name=Mercury, maturity=monthEnd, delay=0, toString()=bc.bacon.egg.data.local.pojos.events.Event@3b43dc25]

如果我现在插入一个已存在的索引(名称)的元素,我会收到以下消息:
To persist: Event [name=Mercury, maturity=monthEnd, delay=0, toString()=bc.bacon.egg.data.local.pojos.events.Event@7025bd08]
PersistanceHolder: bc.bacon.egg.data.local.PersistanceHolder@3d9d91bd
EntityManager: org.hibernate.jpa.internal.EntityManagerImpl@33cb2ee5
CRUDDao: bc.bacon.egg.data.local.dao.events.EventsDao@6073d6f3
Thread: Thread[qtp1055127737-17,5,main]

所以会抛出EntityExistsException,一切都很好。
但是第二次运行时,我得到了这个:

To persist: Event [name=Mercury, maturity=monthEnd, delay=0, toString()=bc.bacon.egg.data.local.pojos.events.Event@700576a4]
PersistanceHolder: bc.bacon.egg.data.local.PersistanceHolder@3d9d91bd
EntityManager: org.hibernate.jpa.internal.EntityManagerImpl@33cb2ee5
CRUDDao: bc.bacon.egg.data.local.dao.events.EventsDao@6073d6f3
Thread: Thread[qtp1055127737-16,5,main]
Hibernate: insert into Event (delay, maturity, name) values (?, ?, ?)
Jun 18, 2015 3:10:34 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 23505, SQLState: 23505
Jun 18, 2015 3:10:34 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: Eindeutiger Index oder Primärschlüssel verletzt: "PRIMARY_KEY_3 ON PUBLIC.EVENT(NAME) VALUES ('Mercury', 1)"
Unique index or primary key violation: "PRIMARY_KEY_3 ON PUBLIC.EVENT(NAME) VALUES ('Mercury', 1)"; SQL statement:
insert into Event (delay, maturity, name) values (?, ?, ?) [23505-187]
Jun 18, 2015 3:10:34 PM org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl release
INFO: HHH000010: On release of batch it still contained JDBC statements
Jun 18, 2015 3:10:34 PM com.vaadin.server.DefaultErrorHandler doDefault

现在我的问题是,为什么第一次调用可以,并且发现了重复,但在第二次运行时却不可以? 好的,我可以捕获在commit()函数中抛出的异常,但那么,我该如何移除仍然存在的JDBC语句呢?
谢谢, Josh

你是指“删除剩余的JDBC语句”是什么意思? - Jens Schauder
两次运行之间发生了什么?原始实例从哪里来? - Jens Schauder
信息: HHH000010: 在批处理释放时,它仍包含JDBC语句<<在与数据库的下一次交互中,因为批处理不为空,所以会抛出错误。
- schnawel007
实例是由用户输入创建的。第一个实例在数据库中,第二个(成功的那个)是通过其构造函数(用户输入)生成的,最后一个也是如此。只有一个按钮(Vaadin)点击在实例之间进行(该按钮创建实例)。 - schnawel007
2个回答

2
你应该只为处于NEW/TRANSIENT状态的实体调用persist。因为你正在使用分配的标识符,所以最好使用merge(因为Hibernate无法确定提供的实体是NEW还是DETACHED)。
所以,不要这样做:
entityManager.persist(element);

使用这个:
entityManager.merge(element);

1
我得到了答案。这里为那些遇到同样错误的人提供解决方法:在persist操作之前添加一个merge操作。
PS: 我不知道为什么这个问题会被down vote,因为这是一个合法的问题。persist的Javadoc说:
使实例成为托管和持久化状态。
它并没有将其置于托管状态!它试图在数据库中创建它。所以它首先尝试将其持久化,然后再管理它。merge的Javadoc说:
将给定实体的状态合并到当前持久化上下文中。
它听起来像是覆盖,所以我认为你不能在这里使用它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接