zoukankan      html  css  js  c++  java
  • save(),saveOrUpdate(),merge()的区别

     Save

     save()方法能够保存实体到数据库,正如方法名称save这个单词所表明的意思。我们能够在事务之外调用这个方法,这也是我不喜欢使用这个方法保存数据的原因。假如两个实体之间有关系(例如employee表和address表有一对一关系),如果在没有事务的情况下调用这个方法保存employee这个实体,除非调用flush()这个方法,否则仅仅employee实体会被保存。 

     saveOrUpdate

     saveOrUpdate()方法会执行插入或者更新操作。如果该对象在数据库中已经存在则更新,不存在则插入。

    saveOrUpdate()方法可以在没有事务的情况下执行,但是如果没有手动调用flush()方法会面临关联对象不被保存的问题

    save()方法与saveOrUpdate()方法最大的不同点在于,saveOrUpdate()方法会将实体对象添加到持久化上下文中,该实体的后续改变会被跟踪。

    HibernateSaveOrUpdateExample.java

    以下是简单的hibernate程序,演示saveOrUpdate()方法的使用。

    /* 
     * @(#)HibernateSaveOrUpdateExample.java    Created on 2016年4月10日
     * Copyright (c) 2016. All rights reserved.
     */
    package nd.esp.com.hibernate.example;
    
    import nd.esp.com.hibernate.model.Address;
    import nd.esp.com.hibernate.model.Employee;
    import nd.esp.com.hibernate.utils.HibernateUtil;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    
    public class HibernateSaveOrUpdateExample {
        public static void main(String[] args) {
            // Prep Work
            SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
            System.out.println("***********************************************");
            // saveOrUpdate example - without transaction
            Session session5 = sessionFactory.openSession();
            Employee emp5 = getTestEmployee();
            session5.saveOrUpdate(emp5);
            System.out.println("***********************************************");
    
            // saveOrUpdate example - with transaction
            Session session3 = sessionFactory.openSession();
            Transaction tx3 = session3.beginTransaction();
            Employee emp3 = getTestEmployee();
            session3.saveOrUpdate(emp3);
            emp3.setName("Kumar"); // will be saved into DB
            System.out.println("9. Before committing saveOrUpdate transaction. Id=" + emp3.getId());
            tx3.commit();
            System.out.println("10. After committing saveOrUpdate transaction");
            System.out.println("***********************************************");
    
            Transaction tx4 = session3.beginTransaction();
            emp3.setName("Updated Test Name"); // Name changed
            emp3.getAddress().setCity("Updated City");
            session3.saveOrUpdate(emp3);
            emp3.setName("Kumar"); // again changed to previous value, so no Employee update
            System.out.println("11. Before committing saveOrUpdate transaction. Id=" + emp3.getId());
            tx4.commit();
            System.out.println("12. After committing saveOrUpdate transaction");
            System.out.println("***********************************************");
    
            // Close resources
            sessionFactory.close();
        }
        public static Employee getTestEmployee() {
            Employee emp = new Employee();
            Address add = new Address();
            emp.setName("Test Emp");
            add.setCity("Test City");
            emp.setAddress(add);
            add.setEmployee(emp);
            return emp;
        }
    }
    

      

    执行上述示例程序,输出结果。

    ***********************************************
    Hibernate: insert into EMPLOYEE (emp_name) values (?)
    ***********************************************
    Hibernate: insert into EMPLOYEE (emp_name) values (?)
    9. Before committing saveOrUpdate transaction. Id=21
    Hibernate: insert into ADDRESS (city, emp_id) values (?, ?)
    Hibernate: update EMPLOYEE set emp_name=? where emp_id=?
    10. After committing saveOrUpdate transaction
    ***********************************************
    11. Before committing saveOrUpdate transaction. Id=21
    Hibernate: update ADDRESS set city=? where emp_id=?
    12. After committing saveOrUpdate transaction
    ***********************************************
    

      

    注意如果没有事务,仅仅是employee实体被保存到数据库,而address的信息丢失了。

    在事务tx4中的几行代码employee实体的name属性先被修改为“Updated Test Name”,之后又被赋值为原来的值“Kumar”,因此employee这个实体在事务提交之前并没有改变,所以并没有update操作。

          下面来讲讲Hibernate的merge方法。我打算按照hibernate对象生命周期的三个状态来讲。

    1:如果POJO对象处于游离态,我所说的游离态是指该对象的id值为空。hibernate判断一个对象在数据库中是否存在不是看对象的其他信息,而是判断该id在数据库中是不是存在。如果id为空,那自然是不存在,所以当我们调用merge方法的时候,就会直接执行插入操作。这一点有点像saveorupdate()方法。看一段代码:

    Java代码
    User user = new User();   
    //user.setId(4);   
    user.setUsername("heyuanling2");   
    user.setAge(23);   
    user.setSex("w");   
    user.setPassword("heyuanling");   
    Session session = this.getSession();   
    Transaction tr = session.beginTransaction();   
    //User exituser = (User)session.get(User.class, new Integer(1));   
    session.merge(user);   
    tr.commit();  
    

      

    [java] view plain copy
     
    User user = new User();  
    //user.setId(4);  
    user.setUsername("heyuanling2");  
    user.setAge(23);  
    user.setSex("w");  
    user.setPassword("heyuanling");  
    Session session = this.getSession();  
    Transaction tr = session.beginTransaction();  
    //User exituser = (User)session.get(User.class, new Integer(1));  
    session.merge(user);  
    tr.commit();  
    

      

    再看hibernate的sql语句:

    Java代码
    Hibernate:    
        select   
            max(id)    
        from   
            user_   
    Hibernate:    
        insert    
        into   
            user_   
            (username, password, sex, age, birthday, other, id)    
        values   
            (?, ?, ?, ?, ?, ?, ?)  
    

      

    [java] view plain copy
     
    Hibernate:   
        select  
            max(id)   
        from  
            user_  
    Hibernate:   
        insert   
        into  
            user_  
            (username, password, sex, age, birthday, other, id)   
        values  
            (?, ?, ?, ?, ?, ?, ?)  
    

      

    二:脱管态:如果我们把上面代码里//user.setId(4);的注释去掉,那么它就变成了脱管的对象了(其实从游离到脱管就这么简单,没有官方说的那么邪乎...)。这是我们再来看控制台的sql打印:

    Java代码
    Hibernate:    
        select   
            user0_.id as id4_0_,   
            user0_.username as username4_0_,   
            user0_.password as password4_0_,   
            user0_.sex as sex4_0_,   
            user0_.age as age4_0_,   
            user0_.birthday as birthday4_0_,   
            user0_.other as other4_0_    
        from   
            user_ user0_    
        where   
            user0_.id=?  
    

      

    [java] view plain copy
     
    Hibernate:   
        select  
            user0_.id as id4_0_,  
            user0_.username as username4_0_,  
            user0_.password as password4_0_,  
            user0_.sex as sex4_0_,  
            user0_.age as age4_0_,  
            user0_.birthday as birthday4_0_,  
            user0_.other as other4_0_   
        from  
            user_ user0_   
        where  
            user0_.id=?  
    

      

     看到没有,因为id不为空了,所以hibernate就不会再insert了。由于该对象的信息和数据库里的一模一样,所以hibernate只执行了一个select语句,并没有update,如果我们把字段的值做稍微的变动,那么控制台打印的sql语句还应该有一条update语句。就这一点来说,merge还有和saveorupdate()方法一样。

    三:持久态:持久态更好理解。如果我们从数据库里get一条记录,那么这条记录就处于持久态,如果再调用merge,那么hibernate就会先判断该记录是否被修改,没有则什么也不干,修改了就update。这一点还是和saveorupdate()有点像。

    Java代码
    1. Session session = this.getSession();   
    2. Transaction tr = session.beginTransaction();   
    3. User exituser = (User)session.get(User.class, new Integer(1));   
    4. exituser.setAge(11);   
    5. session.merge(exituser);   
    6. tr.commit();   
    7. session.close();  
    [java] view plain copy
     
    1. Session session = this.getSession();  
    2. Transaction tr = session.beginTransaction();  
    3. User exituser = (User)session.get(User.class, new Integer(1));  
    4. exituser.setAge(11);  
    5. session.merge(exituser);  
    6. tr.commit();  
    7. session.close();  

     再看控制台打印结果:

    Java代码
    Hibernate:    
        select   
            user0_.id as id4_0_,   
            user0_.username as username4_0_,   
            user0_.password as password4_0_,   
            user0_.sex as sex4_0_,   
            user0_.age as age4_0_,   
            user0_.birthday as birthday4_0_,   
            user0_.other as other4_0_    
        from   
            user_ user0_    
        where   
            user0_.id=?   
    Hibernate:    
        update   
            user_    
        set   
            username=?,   
            password=?,   
            sex=?,   
            age=?,   
            birthday=?,   
            other=?    
        where   
            id=?  
    [java] view plain copy
     
    Hibernate:   
        select  
            user0_.id as id4_0_,  
            user0_.username as username4_0_,  
            user0_.password as password4_0_,  
            user0_.sex as sex4_0_,  
            user0_.age as age4_0_,  
            user0_.birthday as birthday4_0_,  
            user0_.other as other4_0_   
        from  
            user_ user0_   
        where  
            user0_.id=?  
    Hibernate:   
        update  
            user_   
        set  
            username=?,  
            password=?,  
            sex=?,  
            age=?,  
            birthday=?,  
            other=?   
        where  
            id=?  
    

      

      如果没有对记录进行修改则不会有后面的那条update语句。

    那么merge和saveorupdate()到底有什么区别呢?看一段代码:

    Java代码
    Session session = this.getSession();   
    Transaction tr = session.beginTransaction();   
    User exituser = (User)session.get(User.class, new Integer(1));   
    tr.commit();   
    session.close();   
    session = getSession();   
    tr = session.beginTransaction();   
    User exituser2 = (User)session.get(User.class, new Integer(1));   
    session.update(exituser);   
    tr.commit();   
    session.close();  
    

      

    [java] view plain copy
     
    Session session = this.getSession();  
    Transaction tr = session.beginTransaction();  
    User exituser = (User)session.get(User.class, new Integer(1));  
    tr.commit();  
    session.close();  
    session = getSession();  
    tr = session.beginTransaction();  
    User exituser2 = (User)session.get(User.class, new Integer(1));  
    session.update(exituser);  
    tr.commit();  
    session.close();  
    

      

     运行上面的代码,hibernate给我们报了一个错误:a different object with the same identifier value was already associated with the session。意思是,在session缓存中以两个标识相同的对象,这是不可以的。那么,吧update改成merge会怎么样呢?改为merge后,一切OK,运行正常。其实merge在执行更新之前会将两个标识符相同的对象进行合并,具体合并的方向是向exituser2合并。

    更多详情请关注 http://www.cnblogs.com/baixingqiang/
  • 相关阅读:
    Serialize and Deserialize Binary Tree
    sliding window substring problem汇总贴
    10. Regular Expression Matching
    《深入理解计算机系统》(CSAPP)读书笔记 —— 第七章 链接
    程序员如何写一份合格的简历?(附简历模版)
    9个提高代码运行效率的小技巧你知道几个?
    《深入理解计算机系统》(CSAPP)读书笔记 —— 第六章 存储器层次结构
    24张图7000字详解计算机中的高速缓存
    《深入理解计算机系统》(CSAPP)实验四 —— Attack Lab
    《深入理解计算机系统》(CSAPP)读书笔记 —— 第五章 优化程序性能
  • 原文地址:https://www.cnblogs.com/baixingqiang/p/5825594.html
Copyright © 2011-2022 走看看