zoukankan      html  css  js  c++  java
  • Hibernate学习5—Hibernate操作对象2

    第二节:Session 常用方法讲解                                        
    2)load和get()方法:
    数据库中不存在与OID 对应的记录,Load()方法会抛出异常:
    load方法默认采用延迟加载,load出来的对象是一个代理类。开始并没有值,只有用到它的属性等的时候,才会去发出sql语句。
    而get方法一开始就发出sql语句。
     
    如果说获取一个对象是为了删除它,可以用load,因为只要获取个引用就行了。
    如果说获取一个对象是为了访问它的属性,建议用get;
    @Test
        public void testLoadClass() {
            Class c = (Class) session.load(Class.class, Long.valueOf(2));    //class id为2的不存在,抛出异常
            System.out.println(c.getStudents());
        }
        
        @Test
        public void testGetClass() {
            Class c = (Class) session.get(Class.class, Long.valueOf(2));    //class id为2的不存在,打印null
            System.out.println(c);
        }
    View Code

    2)update:

    @Test
        public void testUpdateClass(){
            Session session1=sessionFactory.openSession();
            session1.beginTransaction();
            Class c=(Class)session1.get(Class.class, Long.valueOf(1));
            session1.getTransaction().commit(); 
            session1.close();
            
            Session session2=sessionFactory.openSession();
            session2.beginTransaction();
            c.setName("08计算机本科2");
            session2.update(c);
            session2.getTransaction().commit();
            session2.close();
        }
    View Code

     补充:

    update方法:
    1.更新一个detached的对象;
    2.更新一个transient的会报错;但是更新自己设定id的transient对象可以(数据库有对应记录);
    3.上面的,比如更新teacher,我们只是想更新name,但是它会把所有的属性都更新一遍;这样会造成效率低,比如有个字段特别长...
    4.持久化的对象,只要改变了它的内容,session在提交或者关闭的时候,会检查缓存中的和数据库中的是否一致,如果不一致,自动的发update语句;
    但是也和上面一样,虽然只改了一个字段,也会更新所有的字段;
    5.能不能做到:哪个字段改了才更新,哪个字段没改,哪个字段就不更新?怎么做:
    a.xml配置:
    <class name="com.cy.Teacher" dynamic-update="true">.....</class>
    b.跨session更新的问题:
    @Test
        public void testUpdate5() {
            
            
            Session session = sessionFactory.getCurrentSession();
            session.beginTransaction();
            Student s = (Student)session.get(Student.class, 1);
            s.setName("zhangsan5");
            session.getTransaction().commit();
            
            s.setName("z4");
            
            Session session2 = sessionFactory.getCurrentSession();
            session2.beginTransaction();
            session2.update(s);
            session2.getTransaction().commit();
        }
    首先student对象被我们放到了缓存里,s.setName("zhangsan3"),Hibernate会检查哪些属性改过了,这时候生成sql语句,由于使用了dynamic-update,它就只更新name这个字段了;
    session提交之后,关闭了。缓存中的这个对象没了。但是内存中Student s这个对象还在,是detached状态的。
    这个对象又setName("z4"),第二个session2来了,这个session2里面没有s这个对象,然后update(s),它有没有地方来比较哪个字段改过了?
    没有,它没法将内存中的s和session2缓存中的s来比较,所以update(s),发出的sql会更新全部的字段;
    
    c.根据上面,如果想跨session,只更新改过的字段,怎么做:
    将上面的update改为merge:
    @Test
        public void testUpdate6() {
            
            
            Session session = sessionFactory.getCurrentSession();
            session.beginTransaction();
            Student s = (Student)session.get(Student.class, 1);
            s.setName("zhangsan6");
            session.getTransaction().commit();
            
            s.setName("z4");
            
            Session session2 = sessionFactory.getCurrentSession();
            session2.beginTransaction();
            session2.merge(s);
            session2.getTransaction().commit();
        }
    merge:把这个对象给我合并到数据库;原来没改的内容还需要合并吗?不需要。
    merge的时候,它怎么检查哪些字段改过哪些字段没改过呢?缓存中又没有,只能从数据库中load一次,所以它在update之前先发出了一条select语句,然后再比较你给我的对象和我load的对象在什么地方不同,再重新发update语句。
    
    d:dynamic-update这种xml配置,对应的JPA Annotation没有对应的属性;
    在真正开发中建议使用HQL:
    session.createQuery("update Student s set s.name='z5' where s.id = 1");
    @Test
        public void testUpdate7() {
            Session session = sessionFactory.getCurrentSession();
            session.beginTransaction();
            Query q = session.createQuery("update Student s set s.name='z5' where s.id = 1");
            q.executeUpdate();
            session.getTransaction().commit();
            
        }

    3)saveOrUpdate:

    saveOrUpdate(): 如果传的是一个临时对象,则执行save方法;如果传的是游离对象,就调用update方法;
    @Test
        public void testSaveOrUpdateClass(){
            Session session1=sessionFactory.openSession();
            session1.beginTransaction();
            Class c=(Class)session1.get(Class.class, Long.valueOf(1));
            session1.getTransaction().commit();
            session1.close();
            
            Session session2=sessionFactory.openSession();
            session2.beginTransaction();
            c.setName("08计算机本科3");
            
            Class c2=new Class();
            c2.setName("09计算机本科3");
            session2.saveOrUpdate(c);        //c是游离状态,执行update
            session2.saveOrUpdate(c2);        //c2临时状态,执行save
            session2.getTransaction().commit();
            session2.close();
            
            /**
             * 发出的sql:
             *     Hibernate: select class0_.classId as classId1_0_0_, class0_.className as classNam2_0_0_ from t_class class0_ where class0_.classId=?
                Hibernate: insert into t_class (className) values (?)
                Hibernate: update t_class set className=? where classId=?
             */
        }
    View Code

    4)merge:

    有的时候update会报错:session中有两个对象,拥有相同的OID(比如OID为1),更新的时候,session发现缓存中你已经有一个OID为1的对象了,所以更新的时候就报错了;
    比如:
    @Test
        public void testUpdateClass2(){
            Session session1=sessionFactory.openSession();
            session1.beginTransaction();
            Class c=(Class)session1.get(Class.class, Long.valueOf(1));
            session1.getTransaction().commit();
            session1.close();
            
            Session session2=sessionFactory.openSession();
            session2.beginTransaction();
            Class c2=(Class)session2.get(Class.class, Long.valueOf(1));
            c.setName("08计算机本科3");
            
            session2.update(c);
            session2.getTransaction().commit();
            session2.close();
        }     
    View Code

    执行报错:

    为了解决这个问题,多了个merge方法,合并对象:
    更新的时候如果发现这个对象OID和session缓存中另一个对象OID重合了,调用merge方法就会合并,把这两个对象的属性合并,然后更新;
    @Test
        public void testMergeClass(){
            Session session1=sessionFactory.openSession();
            session1.beginTransaction();
            Class c=(Class)session1.get(Class.class, Long.valueOf(1));
            session1.getTransaction().commit(); 
            session1.close();
            
            Session session2=sessionFactory.openSession();
            session2.beginTransaction();
            
            Class c2=(Class)session2.get(Class.class, Long.valueOf(1));
            c.setName("08计算机本科4");
        
            session2.merge(c);
    
            session2.getTransaction().commit(); 
            session2.close();
        }
    View Code

    5)delete:

    @Test
        public void testDeleteStudent(){
            Student student=(Student)session.load(Student.class, Long.valueOf(1));
            session.delete(student);
            session.getTransaction().commit();    
            session.close();
        }
    View Code

     因为删除的时候,只需要获得它的引用,这里使用了load延迟加载就行了。不需要使用get了,因为不需要获取它里面的属性。

    session.delete的时候还没有真正删除,提交事务的时候,才同步数据库,真的删了。

     
     
  • 相关阅读:
    luoguP2657 [SCOI2009] windy 数 数位dp
    LOJ#3280. 「JOISC 2020 Day4」首都城市 点分治+BFS
    luoguP2168 [NOI2015]荷马史诗 哈夫曼树
    转载-如何在博客园随笔中增加章节导航
    转载-MySQL之终端(Terminal)管理数据库、数据表、数据的基本操作
    转载-MySQL之终端(Terminal)管理MySQL
    数据库缓存
    独立图片服务器的部署(了解)
    CDN加速
    MySQL update替换字段部分内容
  • 原文地址:https://www.cnblogs.com/tenWood/p/7253175.html
Copyright © 2011-2022 走看看