Hibernate-Session

来源:互联网 发布:java项目描述范文 编辑:程序博客网 时间:2024/05/06 13:22
1:Session 概述
Session 接口是 Hibernate 向应用程序提供的操纵数据库的最主要的接口, 它提供了基本的保存, 更新, 删除和加载 Java 对象的方法.
Session 具有一个缓存, 位于缓存中的对象称为持久化对象, 它和数据库中的相关记录对应. Session 能够在某些时间点, 按照缓存中对象的变化来执行相关的 SQL 语句, 来同步更新数据库, 这一过程被称为刷新缓存(flush)
站在持久化的角度, Hibernate 把对象分为 4 种状态: 持久化状态, 临时状态, 游离状态, 删除状态. Session 的特定方法能使对象从一个状态转换到另一个状态. 
在 Session 接口的实现中包含一系列的 Java 集合, 这些 Java 集合构成了 Session 缓存. 只要 Session 实例没有结束生命周期, 且没有清理缓存,则存放在它缓存中的对象也不会结束生命周期
Session 缓存可减少 Hibernate 应用程序访问数据库的频率。:
2:flush 缓存:
flush:Session 按照缓存中对象的属性变化来同步更新数据库
默认情况下 Session 在以下时间点刷新缓存:
显式调用 Session 的 flush() 方法
当应用程序调用 Transaction 的 commit()方法的时, 该方法先 flush ,然后在向数据库提交事务
当应用程序执行一些查询(HQL, Criteria)操作时,如果缓存中持久化对象的属性已经发生了变化,会先 flush 缓存,以保证查询结果能够反映持久化对象的最新状态
flush 缓存的例外情况: 如果对象使用 native 生成器生成 OID, 那么当调用 Session 的 save() 方法保存对象时, 会立即执行向数据库插入该实体的 insert 语句.
commit() 和 flush() 方法的区别:flush 执行一系列 sql 语句,但不提交事务;commit 方法先调用flush() 方法,然后提交事务. 意味着提交事务意味着对数据库操作永久保存下来。

Flush使数据表中的记录和Session缓存中的对象的状态保持一致,为了保持一致则可能发送对应的sql

     * 1:调用session的commit方法  要先进行flush 在进行提交事物
     * 2:flush方法可能会发送sql语句  不会提交事物
     * 3:注意:在未提交事物或显示的调用session.flush()方法之前,也有可能会进行flush操作
     *   1>执行HQL或QBC查询,会先进行flush()操作,以得到数据表的最新数据
     *   2>若记录的ID是由底层,数据库使用自增的方式生成的,则在调用save()方法后,就会立即发送insert
     *   .因为save方法后,必须保证对象的id是存在的。oracle不是,因为oracle有序列

//第二条get方法不会再去查数据库,会直接从session中获取
   News news = (News)session.get(News.class,1);
        System.out.println(news);
        News news2 = (News)session.get(News.class,1);
        System.out.println(news2);
//1>执行HQL或QBC查询,会先进行flush()操作,以得到数据表的最新数据,即会执行update操作
        News news = (News)session.get(News.class, 1);
        news.setAuthor("TestCui00");
        News news00 = (News)session.createCriteria(News.class).uniqueResult();
        System.out.println(news00);
//refresh,会强制发送select语句,以使Session缓存中的对象状态和数据表中的对应的记录保持一致
   News news = (News)session.get(News.class, 21);
        System.out.println(news);
        session.refresh(news);
        System.out.println(news);
//清理缓存后,hibernate还需要在查询一次数据库
   News news = (News)session.get(News.class, 21);
        System.out.println(news);
        session.clear();
        //清理缓存后,hibernate还需要在查询一次数据库
        news = (News)session.get(News.class, 21);
        System.out.println(news);

3:在 Hibernate 中设置隔离级别
JDBC 数据库连接使用数据库系统默认的隔离级别. 在 Hibernate 的配置文件中可以显式的设置隔离级别. 每一个隔离级别都对应一个整数:
1. READ UNCOMMITED
2. READ COMMITED
4. REPEATABLE READ
8. SERIALIZEABLE
Hibernate 通过为 Hibernate 映射文件指定 hibernate.connection.isolation 属性来设置事务的隔离级别

4:持久化对象的状态
站在持久化的角度, Hibernate 把对象分为 4 种状态: 持久化状态, 临时状态, 游离状态, 删除状态. Session 的特定方法能使对象从一个状态转换到另一个状态. 
持久化对象的状态:
临时对象(Transient): 
在使用代理主键的情况下, OID 通常为 null
不处于 Session 的缓存中
在数据库中没有对应的记录
持久化对象(也叫”托管”)(Persist):
OID 不为 null
位于 Session 缓存中
若在数据库中已经有和其对应的记录, 持久化对象和数据库中的相关记录对应
Session 在 flush 缓存时, 会根据持久化对象的属性变化, 来同步更新数据库
在同一个 Session 实例的缓存中, 数据库表中的每条记录只对应唯一的持久化对象
删除对象(Removed)
在数据库中没有和其 OID 对应的记录
不再处于 Session 缓存中
一般情况下, 应用程序不该再使用被删除的对象
游离对象(也叫”脱管”) (Detached):
OID 不为 null
不再处于 Session 缓存中
一般情况需下, 游离对象是由持久化对象转变过来的, 因此在数据库中可能还存在与它对应的记录
5:对象转化状态涉及的接口
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() 方法时会抛出一个异常.

    /**     * persist和save的区别: 在调用persist方法之前,若对象已经有id,则不会执行insert,而会抛出一个异常 /     * /* 1:save方法, 1>使一个临时对象转变为持久化对象 2>为对象分配Id 3>在flush缓存时会发送一条insert语句 4>在save方法之前的id是无效的 5>持久化对象的id是不能被修改的     * */    @Test    public void testmyPersist()    {        News news = new News(1999, "TestZq", "test", new Date(new java.util.Date().getTime()));        session.persist(news);        System.out.println(news);    }    @Test    public void testMySave()    {        News news = new News(100, "TestA", "test", new Date(new java.util.Date().getTime()));        System.out.println(news);        // [id=null, title=Test, author=test, newsDate=2015-10-21]        session.save(news);        System.out.println(news);        // [id=23, title=Test, author=test, newsDate=2015-10-21]        news.setId(13444);    }
Session 的 get() 和 load() 方法

都可以根据跟定的 OID 从数据库中加载一个持久化对象
区别:
当数据库中不存在与 OID 对应的记录时, load() 方法抛出 ObjectNotFoundException 异常, 而 get() 方法返回 null

两者采用不同的延迟检索策略:load 方法支持延迟加载策略。而 get 不支持。

    // get和lode的区别,    // 1:执行get方法会立即加载对象,执行lode方法 若不使用该对象,则不会立即执行查询操作,    // 而返回一个代理对象(com.cgc.hibernate.test.News_$$_javassist_0).也就是说 get是立即检索,lode是延迟检索    // 2:lode可能会抛出LazyInitializationException异常,导致异常发生原因是在需要初始化代理对象之前已经关闭的Session    // 3:若数据表中没有对应的记录 且Session也没有被关闭,同时需要使用对象时,get返回null,lode若不使用该对象的任何属性 不出现异常,若需要初始化    // 则抛出一个异常(org.hibernate.ObjectNotFoundException: No row with the given identifier exists:    // [com.cgc.hibernate.test.News#1])    @Test    public void testmyLode()    {        News news = (News)session.load(News.class, 1);        System.out.println(news.getClass().getName());        // session.close();        System.out.println(news);    }    @Test    public void testmyGet()    {        News news = (News)session.get(News.class, 21);        // session.close();        System.out.println(news);    }
Session 的 update() 方法

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

当 update() 方法关联一个游离对象时, 如果在数据库中不存在相应的记录, 也会抛出异常. 

    /**     * <一句话功能简述> <功能详细描述>     *      * @see [类、类#方法、类#成员] update: 1:若更新一个持久化对象,不需要显示的调用session的update方法,因为在调用Transaction的commit方法时 会先执行session的flush方法     *      2:更新为一个游离的对象 需要显示的使用session的update方法,可以把一个游离的对象变为持久化对象     *      *      需要注意的是: 1>无论要更新的游离的对象和数据表的记录是否一致,都会发送update语句     *      那么如何才能让update方法不再盲目的触发update语句,在.hbm.xml文件中设置select-before-update="true", <class name="News" table="NEWS"     *      select-before-update="true" dynamic-insert="true"> 但通常不需要设置该属性 即在更新前先查一把 2>若数据表,没有对应的记录 但还调用了update方法,会抛出异常。     *      3>当update()方法关联一个游离对象时,如果Session的缓存中已经存在相同OID的持久化对象,会抛异常 //因为在session中不能有两个OID相同的对象     */    @Test    public void testmyUpdate()    {        News news = (News)session.get(News.class, 21);        transaction.commit();        session.close();        // news.setId(2345);        session = sessionFactory.openSession();        transaction = session.beginTransaction();                // 当update()方法关联一个游离对象时,如果Session的缓存中已经存在相同OID的持久化对象,会抛异常        // 因为在session中不能有两个OID相同的对象        // News news00 = (News)session.get(News.class, 21);                // 此时的news已经是一个游离的对象        // news.setAuthor("XXXX");        // 更新为一个游离的对象 需要显示的使用session的update方法,可以把一个游离的对象变为持久化对象        session.update(news);    }
Session 的 saveOrUpdate() 方法

Session 的 saveOrUpdate() 方法同时包含了 save() 与 update() 方法的功能
判定对象为临时对象的标准
Java 对象的 OID 为 null

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

    /**     * <一句话功能简述>游离的对象执行update方法,临时的对象执行save方法 <功能详细描述>     *      * @see [类、类#方法、类#成员] 1:若OID不为null,但数据表中还没有和其对应的记录会抛异常StaleStateException     *      2:了解:若OID值等于unsaved-value属性值的对象,也会被认为是一个游离对象     */    @Test    public void testmySaveorUpdate()    {        News news = new News("KKK", "fff", new Date(new java.util.Date().getTime()));        news.setId(1);        session.saveOrUpdate(news);    }
Session 的 delete() 方法

Session 的 delete() 方法既可以删除一个游离对象, 也可以删除一个持久化对象
Session 的 delete() 方法处理过程
计划执行一条 delete 语句
把对象从 Session 缓存中删除, 该对象进入删除状态.

Hibernate 的 cfg.xml 配置文件中有一个 hibernate.use_identifier_rollback 属性, 其默认值为 false, 若把它设为 true, 将改变 delete() 方法的运行行为: delete() 方法会把持久化对象或游离对象的 OID 设置为 null, 使它们变为临时对象

    /**     * <一句话功能简述> <功能详细描述>     *      * @see [类、类#方法、类#成员] delete 执行删除操作,只要OID和数据表中的一条记录对应,就会准备执行delete操作 若OID在数据表中没有记录 则抛出异常     */    @Test    public void testDelete()    {        // 游离对象        // News news = new News();        // news.setId(21);        // news.setTitle("test");                // 持久化对象        News news = (News)session.get(News.class, 24);                session.delete(news);        // 删除并不是立即删除,还没commit,并且调用删除对象 其值还有id值存在,可以设置        // 一个配置属性在.cfg.xml文件中设置<property name="use_identifier_rollback">true</property>        // 则返回值没有id了        System.out.println(news);    }
Session的evict方法:

    /**     * <一句话功能简述> <功能详细描述>     *      * @see [类、类#方法、类#成员] evict从session缓存中把指定的持久化对象移除     */    @Test    public void testEvict()    {        News news00 = (News)session.get(News.class, 29);        News news01 = (News)session.get(News.class, 30);        news00.setAuthor("WW");        news01.setAuthor("WW");                session.evict(news01);    }
通过 Hibernate 调用存储过程

Work 接口: 直接通过 JDBC API 来访问数据库的操作
Session 的 doWork(Work) 方法用于执行 Work 对象指定的操作, 即调用 Work 对象的 execute() 方法. Session 会把当前使用的数据库连接传递给 execute() 方法.
1 0
原创粉丝点击