我有时会注意到我的父/子对象或多对多关系,我需要调用SaveOrUpdate
或Merge
。通常,当我需要调用SaveOrUpdate
时,调用Merge
时遇到的异常与未首先保存的瞬态对象有关。
请解释两者之间的区别。
答案 0 :(得分:155)
这是来自Hibernate参考文档的10.7. Automatic state detection部分:
saveOrUpdate()执行以下操作:
- 如果该对象在此会话中已经持久化,则不执行任何操作
- 如果与会话关联的另一个对象具有相同的标识符, 抛出异常
- 如果对象没有标识符属性,则保存()它
- 如果对象的标识符具有分配给新的值 实例化对象,save()它
- 如果对象是版本化的(通过< version>或< timestamp>),并且 版本属性值是分配给新的相同值 实例化对象,save()它
- 否则更新()对象
和merge()非常不同:
- 如果当前存在具有相同标识符的持久性实例 与会话相关联,将给定对象的状态复制到 持久化实例
- 如果当前没有与之关联的持久性实例 session,尝试从数据库加载它,或者创建一个新的持久化 实例
- 返回持久化实例
- 给定的实例不会与会话相关联,它 保持独立
如果您尝试更新与会话分离的某个点的对象,则应使用Merge(),尤其是当可能存在当前与会话关联的那些对象的持久实例时。否则,在这种情况下使用SaveOrUpdate()会导致异常。
答案 1 :(得分:9)
据我了解,merge()
将获取一个可能与当前会话无关的对象,并将其状态(属性值等)复制到 的对象与当前会话相关联(当然具有相同的PK值/标识符)。
saveOrUpdate()
会根据给定对象的标识值在您的会话中调用保存或更新。
答案 2 :(得分:4)
SaveOrUpdateCopy()
现已弃用。应该使用Merge()
代替。
答案 3 :(得分:1)
我发现this链接在解释此类异常方面做得非常好:
对我有用的是:
cascade="merge"
SaveOrUpdate
。SaveOrUpdate
父对象。但是,这种解决方案有局限性。也就是说,你必须注意保存你的孩子/依赖对象,而不是让冬眠为你做这件事。
如果有人有更好的解决方案,我希望看到。
答案 4 :(得分:1)
新用户名,所以我无法对Quoc Truong的帖子发表评论或投票。但是,我也认为这个链接非常有用,如前所述。
http://www.roseindia.net/hibernate/hibernate4/org_hibernate_nonuniqueobjectexception.shtml
答案 5 :(得分:1)
** Update()**
: - 如果您确定会话不包含具有相同标识符的已持久实例,则使用update将数据保存在休眠中
** Merge()**
: - 如果你想在不知道会话状态的情况下随时保存你的修改,那么在hibernate中使用merge()。
答案 6 :(得分:-2)
@Entity
@Table(name="emp")
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="emp_id")
private int id;
@Column(name="emp_name")
private String name;
@Column(name="salary")
private int Salary;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return Salary;
}
public void setSalary(int salary) {
this.Salary = salary;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
public enum HibernateUtil {
INSTANCE;
HibernateUtil(){
buildSessionFactory();
}
private SessionFactory sessionFactory=null;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
private void buildSessionFactory() {
Configuration configuration = new Configuration();
configuration.addAnnotatedClass (TestRefresh_Merge.Employee.class);
configuration.setProperty("connection.driver_class","com.mysql.jdbc.Driver");
configuration.setProperty("hibernate.connection.url", "jdbc:mysql://localhost:3306/hibernate");
configuration.setProperty("hibernate.connection.username", "root");
configuration.setProperty("hibernate.connection.password", "root");
configuration.setProperty("dialect", "org.hibernate.dialect.MySQLDialect");
configuration.setProperty("hibernate.hbm2ddl.auto", "update");
configuration.setProperty("hibernate.show_sql", "true");
configuration.setProperty(" hibernate.connection.pool_size", "10");
/* configuration.setProperty(" hibernate.cache.use_second_level_cache", "true");
configuration.setProperty(" hibernate.cache.use_query_cache", "true");
configuration.setProperty(" cache.provider_class", "org.hibernate.cache.EhCacheProvider");
configuration.setProperty("hibernate.cache.region.factory_class" ,"org.hibernate.cache.ehcache.EhCacheRegionFactory");
*/
// configuration
StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties());
sessionFactory = configuration.buildSessionFactory(builder.build());
setSessionFactory(sessionFactory);
}
public static SessionFactory getSessionFactoryInstance(){
return INSTANCE.getSessionFactory();
}
}
public class Main {
public static void main(String[] args) {
HibernateUtil util=HibernateUtil.INSTANCE;
SessionFactory factory=util.getSessionFactory();
//save(factory);
retrieve(factory);
}
private static void retrieve(SessionFactory factory) {
Session sessionOne=factory.openSession();
Employee employee=(Employee)sessionOne.get(Employee.class, 5);
sessionOne.close(); // detached Entity
employee.setName("Deepak1");
Session sessionTwo=factory.openSession();
Employee employee1=(Employee)sessionTwo.get(Employee.class, 5);
sessionTwo.beginTransaction();
sessionTwo.saveOrUpdate(employee); // it will throw exception
//sessionTwo.merge(employee); // it will work
sessionTwo.getTransaction().commit();
sessionTwo.close();
}
private static void save(SessionFactory factory) {
Session sessionOne=factory.openSession();
Employee emp=new Employee();
emp.setName("Abhi");
emp.setSalary(10000);
sessionOne.beginTransaction();
try{
sessionOne.save(emp);
sessionOne.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
}finally{
sessionOne.close();
}
}
}