• save(),saveOrUpdate(),merge()的区别


    save(),saveOrUpdate(),merge()的区别

     

     Save

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

     saveOrUpdate

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

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

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

    HibernateSaveOrUpdateExample.java

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    /*
     * @(#)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;
        }
    }

      

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    ***********************************************
    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()方法。看一段代码:

     
     

    再看hibernate的sql语句:

     
     

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

     
     

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

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

    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();  
    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();  

     再看控制台打印结果:

     
     

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

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

     
     

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

  • 相关阅读:
    桃花扇
    望故乡
    Unity资源加载方式总结
    [Spark]-RDD详解之变量&操作
    [Spark]-RDD之创建
    [Spark]-RDD初识
    [Spark]-编译(2.3.1)&部署(YARN-Cluster)
    [Spark]-背景
    [Hive]-常规优化以及执行计划解析
    [转载]线上应用故障排查之一:高memory占用
  • 原文地址:https://www.cnblogs.com/Smile-123/p/5826763.html
Copyright © 2020-2023  润新知