为了账号安全,请及时绑定邮箱和手机立即绑定

JPA/Hibernate:传递给持久化的分离实体

JPA/Hibernate:传递给持久化的分离实体

潇湘沐 2019-06-28 09:52:11
JPA/Hibernate:传递给持久化的分离实体我有一个JPA持久化的对象模型,它包含一个多对一的关系:一个帐户有许多事务。交易只有一个帐户。下面是代码片段:@Entitypublic class Transaction {     @Id     @GeneratedValue(strategy = GenerationType.AUTO)     private Long id;     @ManyToOne(cascade = {CascadeType.ALL},fetch= FetchType.EAGER)     private Account fromAccount;....@Entitypublic class Account {     @Id     @GeneratedValue(strategy = GenerationType.AUTO)     private Long id;     @OneToMany(cascade = {CascadeType.ALL},fetch= FetchType.EAGER, mappedBy = "fromAccount")     private Set<Transaction> transactions;我能够创建一个帐户对象,向它添加事务,并正确地持久化帐户对象。但是,当我创建一个交易时,使用现有的已持久化帐户,并坚持交易我有个例外:Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: com.paulsanwald.Account     at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:141)因此,我能够持久化一个包含事务的帐户,而不是一个有帐户的事务。我认为这是因为帐户可能没有附加,但这段代码仍然给了我同样的例外:if (account.getId()!=null) {     account = entityManager.merge(account);}Transaction transaction = new Transaction(account,"other stuff");  // the below fails with a "detached entity" message. why?entityManager.persist(transaction);如何正确保存与已持久化帐户对象关联的事务?
查看完整描述

3 回答

?
红糖糍粑

TA贡献1815条经验 获得超6个赞

这是一个典型的双向一致性问题。

您需要在双向关系的两边修复设置者。

更正设置器后,要将实体访问类型声明为“Property”。声明“Property”访问类型的最佳实践是将所有注释从成员属性移动到相应的getter。一个重要的警告是不要将“Field”和“Property”访问类型混合在实体类中,否则JSR-317规范就没有定义这种行为。


查看完整回答
反对 回复 2019-06-28
?
不负相思意

TA贡献1777条经验 获得超10个赞

解决方案很简单,只需使用CascadeType.MERGE而不是CascadeType.PERSISTCascadeType.ALL.

我也有过同样的问题CascadeType.MERGE为我工作过。

我希望你能解决。


查看完整回答
反对 回复 2019-06-28
?
jeck猫

TA贡献1909条经验 获得超7个赞

使用合并是危险和棘手的,因此在您的情况下,这是一个肮脏的解决方法。您至少需要记住,当您传递要合并的实体对象时,它停下来被附加到事务中,而是返回一个新的、现在附加的实体。这意味着,如果任何人仍然拥有旧的实体对象,则对其的更改将被静默忽略,并在提交时丢弃。

您没有在这里显示完整的代码,所以我不能再次检查您的事务模式。要达到这样的情况,一种方法是在执行合并和持久化时没有活动的事务。在这种情况下,持久性提供程序将为您执行的每个JPA操作打开一个新事务,并在调用返回之前立即提交并关闭它。如果是这样的话,合并将在第一个事务中运行,然后在Merge方法返回之后,事务被完成并关闭,返回的实体现在被分离。下面的持久化将打开第二个事务,并试图引用一个被分离的实体,从而提供一个异常。始终将代码包装在事务中,除非您非常清楚自己在做什么。

使用容器管理的事务,它看起来像这样。注意:这假设方法在会话bean中,并通过本地或远程接口调用。

@TransactionAttribute(TransactionAttributeType.REQUIRED)public void storeAccount(Account account) {
    ...

    if (account.getId()!=null) {
        account = entityManager.merge(account);
    }

    Transaction transaction = new Transaction(account,"other stuff");

    entityManager.persist(account);}


查看完整回答
反对 回复 2019-06-28
  • 3 回答
  • 0 关注
  • 569 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号