我有一个主线程,我从数据库中获取一个对象,然后关闭EntityManager,然后将该对象放入队列。工作线程与对象进行一些业务,然后将其放入已完成的队列中。然后主线程从完成的队列中获取对象并合并对象:
onActionSomething(data) {
this.waitFor(NotificationStore);
this.pages = data;
}
我通过在合并之前打印它来确认对象的主键ID,是的,它存在于数据库中。不幸的是,它会抛出MySQL的重复键异常。怎么样?不应该知道JPA知道对象有ID并更新它,而不是插入?
异常中提到的SQL语句是EntityManager em = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
// Print the primary key ID of the object,
// it is NOT empty yes it exists in the db.
em.merge(myObject);
em.getTransaction().commit();
em.close();
语句,而不是INSERT
。
该实体的主键如下:
UPDATE
我正在将对象的List字段设置为另一个新创建的对象的List字段。然后,由于某些我不理解的原因,EclipseLink认为该对象是一个新对象。天知道为什么。这种JPA的东西非常违反直觉。你必须是真正的专家才能使用它。否则它完全没用,因为任何时候你都可以搞砸它。在实践中,它造成的总头痛和时间损失远不止它的优势!
无论如何,我通过将另一个对象的元素添加到旧对象来解决了这个问题,如下所示:
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "COMPANYID")
private long companyId;
现在EclipseLink正确更新而不是插入新的。如果有人能解释为什么会出现这种行为,我会很高兴吗?
答案 0 :(得分:2)
这是因为您的EntityManager不知道对象myObject。
为了使你的代码能够工作,你应该做这样的事情:
EntityManager em = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
Object myObject = em.findById(someId);
em.getTransaction().commit();
object.setName("yourNewName");
.....................
//And now run
em.getTransaction().begin();
em.merge(myObject);
em.getTransaction().commit();
em.close();
请注意,只有在完成数据库所需的所有事务后才会关闭EntityManager。 myObject正是我从em.findById收到的那个,我不是简单地创建一个新对象,因为那不起作用。
这是一个tutorial可能可以帮助您了解更多。(右侧有一个播放列表,其中包含更多关于JPA的视频)。