session.Merge 和 session.SaveOrUpdate 有啥区别?

Posted

技术标签:

【中文标题】session.Merge 和 session.SaveOrUpdate 有啥区别?【英文标题】:What's the difference between session.Merge and session.SaveOrUpdate?session.Merge 和 session.SaveOrUpdate 有什么区别? 【发布时间】:2010-09-15 07:38:34 【问题描述】:

我注意到有时对于我的父/子对象或多对多关系,我需要调用SaveOrUpdateMerge。通常,当我需要调用SaveOrUpdate 时,我调用Merge 时遇到的异常与未先保存临时对象有关。

请解释一下两者的区别。

【问题讨论】:

【参考方案1】:
@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();
        

    

【讨论】:

您应该考虑编辑您的答案以显示受影响的代码,然后在最后考虑完整的代码转储。就目前而言,我们必须向下滚动并在 cmets 中找到机会。见How to Answer。【参考方案2】:
** Update()**

:- 如果您确定会话不包含具有相同标识符的已持久实例,则使用更新将数据保存在休眠中

** Merge()**

:-如果你想在不知道会话状态的情况下随时保存你的修改,那么在休眠中使用merge()。

【讨论】:

【参考方案3】:

据我了解,merge() 将获取一个可能与当前会话无关的对象,并将其状态(属性值等)复制到 与之关联的对象当前会话(当然,具有相同的 PK 值/标识符)。

saveOrUpdate() 将根据给定对象的标识值在您的会话中调用 SaveUpdate

【讨论】:

【参考方案4】:

我发现 this 链接很好地解释了这种类型的异常:

对我有用的是:

    在映射Myclass.hbm.xml文件中,设置cascade="merge" SaveOrUpdate 先将子/从属对象分配给父对象。 SaveOrUpdate 父对象。

但是,此解决方案有局限性。即,您必须注意保存您的子/依赖对象,而不是让 hibernate 为您做这件事。

如果有人有更好的解决方案,我想看看。

【讨论】:

【参考方案5】:

来自 Hibernate 参考文档的 10.7. Automatic state detection 部分:

saveOrUpdate() 执行以下操作:

如果对象已在此会话中持久存在,则不执行任何操作 如果与会话关联的另一个对象具有相同的标识符, 抛出异常 如果对象没有标识符属性,则保存()它 如果对象的标识符具有分配给新的值 实例化对象,保存()它 如果对象是版本化的(通过 ),并且 version 属性值与分配给新的值相同的值 实例化对象,保存()它 否则更新()对象

和merge()很不一样:

如果当前存在具有相同标识符的持久实例 与会话关联,将给定对象的状态复制到 持久化实例 如果当前没有与 会话,尝试从数据库中加载它,或者创建一个新的持久化 实例 持久化实例被返回 给定的实例没有与会话关联,它 保持分离

如果您尝试更新在某一时刻与会话分离的对象,则应使用 Merge(),尤其是当这些对象当前与会话相关联的持久实例可能存在时。否则,在这种情况下使用 SaveOrUpdate() 会导致异常。

【讨论】:

好答案...我想知道 - 如果我在新实体上使用合并,是否有任何理由使用保存后记,或者我可以假设合并肯定在数据库中创建了新实体? (如果它是一个分离的实体,一旦合并,数据库的更改会自动省略吗?) 你确定吗?查看 NHiberante 源 SaveOrUpdateCopy 会触发 Merge 事件,其参数与 Merge 函数相同。我认为它们是相同的,SaveOrUpdateCopy 函数是自 1.0 以来在 hibernate/nhibernate 中存在的东西 Merge 函数是新的,并被添加到 hibernate 以符合新的 java 标准(我认为) @Torkel - SaveOrUpdateCopySaveOrUpdate 不同。我不确定提问者是想比较 Merge 前者还是后者。 SaveOrUpdateCopy 是一个现已过时的方法,它在导入 Merge 之前在 NHibernate 中进行了合并。 很高兴知道... SaveOrUpdate 仍然在教程中大量使用。【参考方案6】:

SaveOrUpdateCopy() 现在从 NHibernate 3.1 开始被弃用。应该改用Merge()

【讨论】:

标记为Obsolete 的是SaveOrUpdateCopy,而不是SaveOrUpdate。在这个问题和后续答案中,这两种不同的方法之间似乎存在很多混淆。

以上是关于session.Merge 和 session.SaveOrUpdate 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

get() 还是 merge() 哪个更快?

sqlalchemy的merge使用

spring boot项目启动报(No session repository could be auto-configured, check your configuration (session s

dedecms怎么获取session

关于php的session.serialize_handler的问题

锁表语句