• Hibernate4.x之Session--常用方法


    接上篇文章继续学习Hibernate的Session(http://www.cnblogs.com/dreamfree/p/4111777.html)

    持久化对象的状态;
      站在持久化的角度,Hibernate把对象分为4种状态:持久化状态、临时状态、游离状态、删除状态。
      Session的特定方法能使对象从一个状态转换到另一个状态。

      临时对象(Transient):
        在使用代理主键的情况下,OID通常为null
        不处于Session的缓存中
        在数据库中没有对应的记录
      持久化对象(也叫“托管”)(Persist)
        OID为null
        位于Session缓存中
        若在数据库中已经有和其对应的记录,持久化对象和数据库中的相关记录对应
        Session在flush缓存时,会根据持久化对象的属性变化,来同步更新数据库
        在同一个Session实例的缓存中,数据库表中的每条记录只对应唯一的持久化对象
      删除对象(Removed):
        在数据库中没有和其OID对应的记录
        不再处于Session缓存中
        一般情况下,应用程序不该再使用被删除的对象
      游离对象(也叫"脱管")(Detached):
        OID不为null
        不再处于Session缓存中
        一般情况下,游离对象是由持久化对象转变过来的,因此在数据库中可能还存在与它对应的记录

    下面的图片说明了Hibernate中对象状态的转换:


    Session的save方法
      Session的save()方法使一个临时对象转变为持久化对象
      Session的save()方法完成以下操作:
        把News对象加入到Session缓存中,使它进入持久化状态
        选用映射文件指定的标识符生成器,为持久化对象分配唯一的OID,在使用代理主键的情况下,setId()方法为News对象设置OID是无效的
        计划执行一条insert语句:在flush缓存的时候
      Hibernate通过持久化对象的OID来维持它和数据库相关记录的对应关系。当News对象处于持久化状态时,不允许程序随意修改它的ID


      persist()和save()的区别:
        当对一个OID不为null的对象执行save()方法时,会把该对象以一个新的OID保存到数据库中;但执行persist()方法时会抛出一个异常

    Session的get()和load()方法
      都可以根据给定的OID从数据库加载一个持久化对象
    区别:
      当数据库中不存在与OID对应的记录时,load()方法抛出ObjectNotFoundException异常,而get()方法返回null
      两者采用不同的延迟检索策略:load()方法支持延迟加载策略。而get不支持

    Session的update()方法
      Session的update()方法使一个游离对象转变为持久化对象,并且计划执行一条update语句
      若希望Session仅当修改了News对象的属性时,才执行update()语句,可以把映射文件中<class>元素的select-before-update设为true。该属性的默认值为false
      当update()方法关联一个游离对象时,如果在Session的缓存中已经存在相同的OID的持久化对象,会抛出异常
      当update()方法关联一个游离对象时,如果数据库中不存在相应的记录,也会抛出异常

    Session的saveOrUpdate()方法
      Session的saveOrUpdate()方法同时包含了save()与update()方法的功能

      

      


    判定对象为临时对象的标准
      Java对象的OID为null
      映射文件中的<id>设置了unsaved-value属性,并且Java对象的OID取值与这个unsaved-value属性值匹配

    Session的merge()方法

      

      


    Session的delete()方法
      Session的delete()方法既可以删除一个游离对象,也可以删除一个持久化对象
      Session的delete()方法处理过程
      计划执行一条delete语句
      把对象从Session的缓存中删除,该对象进入删除状态
      Hibernate的cfg.xml配置文件中有一个hibernate.use_identifier_rollback属性,其默认值为false,若把它设为true,将改变delete()方法的运行行为:delete()方法会把持久化对象或游离对象的OID设置为null,使它们变为临时对象

    通过Hibernate调用存储过程
      work接口:直接通过JDBC API来访问数据库的操作

      Session的doWork(Work)方法用于执行Work对象指定的操作,即调用Work对象的execute()方法。Session会把当前使用的数据库连接传递给execute()方法

    Hibernate与触发器协同工作
      Hibernate与数据库中的触发器协同工作时,会造成两类问题
        触发器使Session的缓存中的持久化对象与数据库中对应的数据不一致;触发器运行在数据库中,它执行的操作对Session是透明的
        session的update()方法盲目地激发触发器;无论游离对象的属性是否发生变化,都会执行update语句,而update语句会激发数据库中相应的触发器
    解决方案:
      在执行完Session的相关操作后,立即调用Session的flush()方法和refresh()方法,迫使Session的缓存与数据库同步(refresh()方法重新从数据库加载对象)

      在映射文件的<class>元素中设置select-before-update属性;当Session的update或saveOrUpdate()方法更新一个游离对象时,会先执行select语句,获得当前游离对象在数据库中的最新数据。只有在一致的情况下才会执行update语句

    测试类:

      1 package com.yl.hibernate.entities;
      2 
      3 import static org.junit.Assert.*;
      4 
      5 import java.sql.CallableStatement;
      6 import java.sql.Connection;
      7 import java.sql.SQLException;
      8 import java.util.Date;
      9 
     10 import org.hibernate.Session;
     11 import org.hibernate.SessionFactory;
     12 import org.hibernate.Transaction;
     13 import org.hibernate.cfg.Configuration;
     14 import org.hibernate.jdbc.Work;
     15 import org.hibernate.service.ServiceRegistry;
     16 import org.hibernate.service.ServiceRegistryBuilder;
     17 import org.junit.After;
     18 import org.junit.Before;
     19 import org.junit.Test;
     20 
     21 public class HibernateTest {
     22 
     23     private SessionFactory sessionFactory;
     24     private Session session;
     25     private Transaction transaction;
     26     
     27     @Before
     28     public void init() {
     29         Configuration configuration = new Configuration().configure();
     30         ServiceRegistry serviceRegistry = 
     31                 new ServiceRegistryBuilder().applySettings(configuration.getProperties())
     32                                             .buildServiceRegistry();
     33 
     34         sessionFactory = configuration.buildSessionFactory(serviceRegistry);
     35         
     36         session = sessionFactory.openSession();
     37 
     38         transaction = session.beginTransaction();
     39     }
     40     @After
     41     public void destory() {
     42         transaction.commit();
     43         
     44         session.close();
     45         
     46         sessionFactory.close();
     47     }
     48     
     49     @Test
     50     public void testSessionCache() {
     51         News news = (News)session.get(News.class, 21);
     52         System.out.println(news);
     53         session.flush();
     54         News news2 = (News)session.get(News.class, 21);
     55         System.out.println(news2);
     56         
     57         System.out.println(news == news2);//true
     58     }
     59 
     60     /**
     61      * flush:使数据库表中的记录和Session缓存中的对象的状态保持一致。为了保持一致,则可能会发送对应的SQL语句。
     62      *     1.在Transaction的commit()方法中:先调用session的flush方法,再提交事务
     63      *  2.flush()方法可能会发送SQL语句,但不会提交事务
     64      *  3.注意:在为提交事务或显示调用session.flush()方法 之前,也有可能会flush()操作。
     65      *      1).执行HQL或QBC查询,会先进行flush操作,以得到数据表的最新纪录
     66      *      2).若记录的ID是由底层数据库使用自增的方式生成的,则在调用save方法时,就会立即发送INSERT语句
     67      *  因为save方法后,必须保证对象的ID是存在的!
     68      */
     69     @Test
     70     public void testFlush2() {
     71         News news = new News("Hibernate", "oracle", new Date());
     72         session.save(news);
     73     }
     74     
     75     @Test
     76     public void testFlush() {
     77         /*News news = (News)session.get(News.class, 21);
     78         news.setAuthor("Bruce Eckel");
     79         
     80         News news2 = (News)session.createCriteria(News.class).uniqueResult();
     81         System.out.println(news2);*/
     82         News news = (News)session.get(News.class, 22);
     83         session.flush();
     84         System.out.println(news);
     85     }
     86     
     87     /**
     88      * refresh():会强制发送SELECT 语句,以使Session缓存中对象的状态和数据表中对应的记录保持一致!
     89      */
     90     @Test
     91     public void testRefresh() {
     92         News news = (News) session.get(News.class, 22);
     93         System.out.println(news);
     94         session.refresh(news);
     95         System.out.println(news);
     96     }
     97     
     98     /**
     99      * clear():清理缓存
    100      */
    101     @Test
    102     public void testClear() {
    103         News news1 = (News) session.get(News.class, 21);
    104         session.clear();
    105         News news2 = (News) session.get(News.class, 21);
    106     }
    107     
    108     /**
    109      * save()方法:
    110      *     1.使一个临时对象变为持久化对象
    111      *     2.为对象分配ID
    112      *     3.在flush缓存时会发送一条insert语句
    113      *     4.在save方法之前的id是无效的
    114      *     5.持久化对象的ID是不能被修改的!
    115      */
    116     @Test
    117     public void testSave() {
    118         News news = new News();
    119         news.setTitle("AA");
    120         news.setAuthor("aa");
    121         news.setNewsDate(new Date());
    122         //news.setId(100);//不起效果
    123         System.out.println(news);
    124         //news.setId(101);//抛出异常
    125         session.save(news);
    126         System.out.println(news);
    127     }
    128     /**
    129      * persist():也会执行insert操作
    130      * 和save()的区别:
    131      * 在调用persist方法之前,若对象已经有ID了,则不会执行insert,而抛出异常
    132      */
    133     @Test
    134     public void testPsesist() {
    135         News news = new News();
    136         news.setTitle("DD");
    137         news.setAuthor("dd");
    138         news.setNewsDate(new Date());
    139         //news.setId(200);//抛出异常
    140         System.out.println(news);
    141         session.save(news);
    142         System.out.println(news);
    143     }
    144     
    145     /**
    146      * 
    147      */
    148     @Test
    149     public void testGet() {
    150         News news = (News) session.get(News.class, 21);
    151         System.out.println(news);
    152     }
    153     
    154     /**
    155      * get 和   load
    156      * 
    157      * 1.执行get方法,会立即加载对象。
    158      *        而执行load方法,若不使用该对象,则不会立即执行查询操作,而返回一个代理对象
    159      * 
    160      *      get是立即检索,load是延迟检索
    161      * 
    162      * 2.load方法可能会抛出LazyInitializationException(懒加载异常):在需要初始化代理对象之前已经关闭了session
    163      * 
    164      * 3.若数据表中没有对应的记录,且session也没有被关闭。同时需要使用对象时
    165      *         get 返回null
    166      *         load 若不使用该对象的任何属性,则不会出问题;若要初始化了,抛出异常
    167      * 
    168      * 
    169      */
    170     @Test
    171     public void testLoad() {
    172         News news = (News) session.load(News.class, 21);
    173         System.out.println(news);
    174     }
    175     
    176     /**
    177      * update:
    178      * 1.若更新一个持久化对象,不需要显式的调用update对象。因为在调用Transaction的commit方法时,会先执行session的flush方法。
    179      * 2.更新一个游离对象,需要显式的调用session的update方法。可以把一个游离对象变为持久化对象
    180      * 
    181      * 需要注意的:
    182      * 1.无论要更新的游离对象和数据表中的记录是否一致,都会发送update语句。
    183      *      如何能让update方法不再盲目的发送update语句,在.hbm.xml文件的class节点设置select-before-update的值为true,默认为flase。但通常不需要设置该属性
    184      * 
    185      * 2.若数据表中没有对应的记录,但还调用了update方法,会抛出异常
    186      * 
    187      * 3.当update()方法关联一个游离对象时,如果在Session的缓存中已经存在相同OID的持久化对象,会抛出异常。因为在Session缓存中不能有两个OID相同的对象
    188      */
    189     @Test
    190     public void testUpdate() {
    191         /*News news = (News) session.get(News.class, 22);
    192         news.setAuthor("Sun");//此时news的author字段已经更新到数据库中,因为在执行commit语句时会先执行flush,flush将session缓存中的修改同步到数据库中。
    193         */
    194         
    195         News news = (News) session.get(News.class, 22);
    196         transaction.commit();
    197         session.close();
    198         
    199         session = sessionFactory.openSession();
    200         transaction = session.beginTransaction();
    201         
    202         
    203         //news.setAuthor("Sun");
    204         session.update(news);
    205         
    206     }
    207     
    208     /**
    209      * 注意:
    210      * 1.若OID不为空,但数据表还没有和其对应的记录。会抛出一个异常。
    211      * 2.了解:OID值等于id的unsaved-value属性值的对象,也被认为是一个游离对象
    212      */
    213     @Test
    214     public void testSaveOrUpdate() {
    215         News news = new News("FF", "ff", new Date());
    216         news.setId(41);
    217         session.saveOrUpdate(news);
    218         
    219     }
    220     
    221     /**
    222      * delete: 执行删除操作,只要OID和数据表中一条记录对应,就会准备执行delete操作
    223      * 若OID在数据表中没有对应的记录,则抛出异常
    224      * 
    225      * 可以通过设置一个Hibernate配置文件hibernate.use_identifier_rollback 为true,使删除对象后,把其OID置为null
    226      */
    227     @Test
    228     public void testDelete() {
    229         /*//游离对象删除
    230         News news = new News();
    231         news.setId(42);
    232         
    233         session.delete(news);*/
    234         
    235         //持久化对象删除
    236         News news = (News) session.get(News.class, 41);
    237         session.delete(news);//计划删除,并不立即执行。在commit中的flush时执行delete
    238         System.out.println(news);//依然可以打印
    239     }
    240     
    241     /**
    242      * evict:从session缓存中把指定的持久化对象移除
    243      */
    244     @Test
    245     public void testEvict() {
    246         News news1 = (News) session.get(News.class, 22);
    247         News news2 = (News) session.get(News.class, 41);
    248         
    249         news1.setTitle("AA");
    250         news2.setTitle("BB");
    251         
    252         session.evict(news1);
    253     }
    254     
    255     /**
    256      * 调用存储过程
    257      */
    258     @Test
    259     public void testDoWork() {
    260         session.doWork(new Work() {
    261             
    262             @Override
    263             public void execute(Connection connection) throws SQLException {
    264                 System.out.println(connection);
    265                 //调用存储过程
    266                 
    267                 //创建存储过程的对象  
    268                 CallableStatement c = connection.prepareCall("{call getsum(?,?)}");
    269                 
    270                 //给存储过程的第一个参数设置值  
    271                 c.setInt(1,100);  
    272                  
    273                 //注册存储过程的第二个参数  
    274                 c.registerOutParameter(2,java.sql.Types.INTEGER);  
    275                  
    276                 //执行存储过程  
    277                 c.execute();  
    278                 
    279                 connection.close();
    280             }
    281         });
    282     }
    283 }
  • 相关阅读:
    Redis宣言
    软件工程
    分布式编程
    编程泛型
    tcp/ip高效编程总结
    IP协议详解
    gevent程序员指南
    网站架构
    这些话,是乔布斯给世间留下的真正伟大礼物
    Flink/Spark 如何实现动态更新作业配置
  • 原文地址:https://www.cnblogs.com/dreamfree/p/4119830.html
Copyright © 2020-2023  润新知