【问题标题】:hibernate NonUniqueObjectException when save update保存更新时休眠 NonUniqueObjectException
【发布时间】:2011-12-06 22:48:37
【问题描述】:

我有这种简单的情况:

@Entity
public class Customer{

    @ManyToMany(fetch=FetchType.EAGER)
    @Cascade(CascadeType.SAVE_UPDATE)
    private List<Product> products=new ArrayList<Product>();

}

@Entity
public class Produtc{

    @ManyToOne
    @Cascade(CascadeType.SAVE_UPDATE)
    private Category category;
}

@Entity
public class Category{

    private String name;
}

插入新客户的例程:

Customer customer=new Customer();
//customer.set data
Product p=dao.getProductBySomeUserInput...
if(p==null){
   p=new Product();
   //p.set data
}
customer.addProduct(p);
dao.save(customer);  //this row throw NonUniqueObjectException on Category class

我该如何解决这个问题?我认为问题与 CascadeType.SAVE_UPDATE 有关,但我需要它... 谢谢大家。


更新

我发现了问题,这是如何复制它:

Customer c=new Customer();
// Load two products by id
Product p=dao.get(Product.class, 2);
Product p1=dao.get(Product.class, 3);
c.addProduct(p);
c.addProduct(p1);
// This try to update products, and category of products becouse CascadeType is SAVE_UDPATE
dao.save(c);

因此,如果 p 和 p 1 具有不同的类别,则没有问题,但如果 p 和 p1 具有相同的类别,我在类别上有 NonUniqueObjectException 因为相同的类别在会话中并且休眠尝试保存_更新它。

我在 Product 和 Category 实体中都需要 CascadeType.SAVE_UPDATE,那么我该如何解决这个问题? 谢谢。

【问题讨论】:

  • 您是否有机会在客户对象上设置 id? hibernate的会话中是否已经存在具有相同id的对象?
  • EntityManager 中没有保存方法。您使用哪种方法来留住客户?此代码是否在唯一的事务中运行?
  • @JB Nizet:抱歉,entityManager 是我的一段代码,但是,dao.get 和 dao.save 都使用事务(我使用 spring 用 @Transactional 标记它们来管理事务),所以不,此代码不会在单个事务中运行。
  • 我对项目中的每个实体都使用了一个实体管理器,因此像 save、delete、findById、findAll 这样的方法,每个都通过事务进行管理。

标签: java hibernate hibernate-cascade


【解决方案1】:

问题可能是由于交易管理不善造成的。您的所有代码都应该在一个事务中完成,而不是每个 DAO 调用都有一个事务。服务层应该是划分事务的层,而不是 DAO 层。

我可以想象 Hibernate 做了什么:

  1. 您致电dao.get(Product.class, 2)。这将返回一个分离的产品,该产品指向 ID 为 67 的类别(例如)。结果是分离的,因为事务在对 DAO 的调用结束时结束。
  2. 您致电dao.get(Product.class, 3)。这将返回一个分离的产品,该产品指向 ID 为 67 的类别(例如)。但由于调用在另一个事务中运行,您会得到第二个不同的 Category 实例(与第一个具有相同的 ID)。
  3. 您在产品上调用 saveOrUpdate。这级联到类别,因此 Hibernate 必须将类别 1 和类别 2 附加到会话。由于它们都具有相同的 ID,因此可能无法完成其中一个级联。

如果你使用单个事务获取两个产品,它们将具有相同的类别实例,并且不会出现问题。调用merge 而不是saveOrUpdate 也应该有效:Hibernate 会将这两个类别的状态复制到第三个,附加一个。但正确的做法是使用涉及对 DAO 的两次调用的事务。

【讨论】:

    猜你喜欢
    • 2011-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-14
    • 1970-01-01
    • 2011-10-15
    相关资源
    最近更新 更多