0

我有这个简单的情况:

@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,那么我该如何解决这个问题?谢谢。

4

1 回答 1

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 必须将类别 1 和类别 2 附加到会话。由于它们都具有相同的 ID,因此可能无法完成其中一个级联。

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

于 2011-12-07T22:36:27.063 回答