保存更新时hibernate NonUniqueObjectException

时间:2011-12-06 22:48:38

标签: java hibernate hibernate-cascade

我有这种简单的情况:

@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有不同的类别没有probs,但是如果p和p1有相同的类别我在类别上有NonUniqueObjectException因为同一类别在会话中,而hibernate尝试save_update它。

我在产品和类别实体中都需要CascadeType.SAVE_UPDATE,那么我该如何解决这个问题呢? 感谢。

1 个答案:

答案 0 :(得分:2)

问题可能是由于糟糕的交易管理。您的所有代码都应该在一个事务中完成,而不是为每个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必须将category1和category2附加到会话。由于它们都具有相同的ID,因此可能无法完成其中一个级联。
  4. 如果您使用单个事务来获取这两个产品,它们将具有相同的类别实例,并且不会出现问题。调用merge而不是saveOrUpdate也应该有效:Hibernate会将两个类别的状态复制到第三个类别。但正确的做法是使用涉及对DAO的两次调用的事务。