文档章节

学习hibernate(三) -- session常用方法

XuePeng77
 XuePeng77
发布于 2016/03/25 23:10
字数 2634
阅读 74
收藏 5

    hibernate将orm对象的种类分为四种,分别是:

  • 临时状态

    临时状态一般来说就是我们使用new关键字创建的对象,还没有和session关联上,并且对象的id为null。调用session的save方法、saveorupdate方法、persist方法、merge方法、get方法和load方法都可以使临时状态对象变为持久化状态对象。

  • 持久化状态

    持久化状态也被称为托管状态,又session缓存进行托管,持久化对象的id不为空,并且与数据库中的记录相互对应。调用session的evict方法、clear方法和close方法可以使持久化状态对象变为游离状态对象。

  • 游离状态

    游离状态可以理解为对象从session缓存中取出后,session缓存被清空了,或者session被关闭了,又或者调用了evict方法将该对象手动从session缓存中删除了,这时session不再对该对象进行托管。游离状态与临时状态的一个区别就是,游离状态的对象的id不为空,并且数据库中有可能还保存着这个对象的信息。

    调用session的update方法、saveorupdate方法和merge方法可以使游离状态对象变为持久化状态对象。

  • 删除状态

    调用了session的delete方法后,被delete的对象的状态将变为删除状态。一般来说删除状态的对象将不会在使用了,当事务commit的时候,数据库中也会将该对象删除。

    以上就是orm对象在session中的四种状态,接下来测试一下session的常用方法。首先是save方法:

    @Test
    public void testSave() {
        // 创建一个对象,该对象现在为临时状态。
        User user = new User();
        // 此处设置id的值不会生效
        // save方法将调用sql本地生成方式从新为对象id赋值。
        user.setId(100);
        user.setName("Kobe");
        user.setBirthday(new Date());
        // 调用save方法将对象状态改变为持久化状态,由session缓存托管。
        session.save(user);
        // 持久化后的对象id不允许修改,否则将出现异常。
        // org.hibernate.HibernateException:
        // identifier of an instance of cn.net.bysoft.model.User was altered
        // from 1 to 13
        // user.setId(13);
    }

    上面是save方法的测试,需要注意的就是在save之前,设置对象的id无效,save方法将调用id生成方式生成一个id复制给对象。在save后,不可修改id,否则将会抛出异常。接下来了persist方法:

    @Test
    public void testPersist() {
        User user = new User();
        // 使用persist保存对象,如果设置了id值将会抛出异常。
        // user.setId(111);
        user.setName("Jordan");
        user.setBirthday(new Date());
        session.persist(user);
    }

    使用persist方法也可以将对象从临时状态改变为持久化状态,并且保存到数据库中。与save方法的区别在于如果,调用save方法前设置的id无效,但不会发生异常,而使用persist方法之前如果设置了id,将会抛出异常。

    在看看get方法:

    @Test
    public void testGet() {
        // 从数据库中获得id=3的记录,加载到User对象中。
        // User对象从临时状态改变到持久化状态。
        User user = (User) session.get(User.class, 3);
        System.out.println(user);
        /**
         * output: User [id=3, name=Jordan, birthday=2016-03-25 19:56:14.0]
         * */
        // 如果传入的id在数据库中找不到记录,则返回null。
        User user2 = (User) session.get(User.class, 44);
        System.out.println(user2);
        /**
         * output: null
         * */
    }

    调用get方法后,会发送一条select语句到数据库,查找id对应的记录,如果查找到,则将记录加载到对象中,并把对象的状态改变为持久化状态,如果没用通过id获得记录,则返回null。

    get方法之后,看看load方法:

    @Test
    public void testLoad() {
        //    load方法创建了一个user的代理对象,执行load后并不会发送select语句。
        User user = (User) session.load(User.class, 3);
        //    在使用user对象的属性时,才发送select语句查询数据,这种机制叫做延迟加载。
        System.out.println(user);
        /**
         * output: User [id=3, name=Jordan, birthday=2016-03-25 19:56:14.0]
         * */
        // 如果传入的id在数据库中找不到记录。
        User user2 = (User) session.load(User.class, 44);
        //    在使用该对象时会抛出异常。
        System.out.println(user2);
    }

    在执行load方法后,hibernate不会立即去发送select语句查询数据库,而是创建一个代理,等到调用对象的属性时,由代理去发送select语句查询数据。

    若load对象使用的id在数据库中不存在,则会抛出异常。

    虽然都是从数据库查询数据加载到对象,但两个方法略有不同,对比一下get方法与load方法:


get方法
load方法
何时执行select语句
调用get方法后立即执行select语句。

调用load方法后不执行select语句,而是创建一个代理。

等到使用对象的属性时再执行select语句。

如果id在数据库中不存在
调用get方法返回null
调用load方法后,在使用该对象时会抛出异常。
在使用对象前调用session.close
不会抛出异常
会抛出异常

    以上是get方法与load方法,接下来测试一下update方法:

    @Test
    public void testUpdate(){
        //    update方法可以将游离对象变为持久化对象。
        User user = new User();
        user.setId(2);
        user.setName("Jack");
        user.setBirthday(new Date());
        
        //    调用update将上面的游离状态对象变为持久化状态对象。
        //    并且更新数据库中的记录。
        session.update(user);
    }

    创建一个User对象,这里因为给user设置了id,id不为空的话就不是临时对象,而是游离对象。通过update方法把游离对象的状态改成持久化对象,并且向数据库发送了update语句。

    在调用flush的时候,如有必要,hibernate也会发送update语句,这里,数据库中若有触发器,则会频繁出发。这些出发中可能有不必要的update操作。hibernate提供了select-before-update属性来解决这个问题,将该属性设置成true,在update之前会查询一次数据库,如果对象没有变化则不执行update。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <!-- update之前先进行select,对象与数据库中的记录一致,则不执行update -->
    <class name="cn.net.bysoft.model.User" table="S_USER" select-before-update="true">
        <id name="id" type="integer" column="ID">
            <!-- 指定主键的生成方式,native是使用数据库本地的方式 -->
            <generator class="native"></generator>
        </id>
        <property name="name" type="string" column="NAME"></property>
        <property name="birthday" type="timestamp" column="BIRTHDAY"></property>
    </class>
</hibernate-mapping>

    update时,传入的id如果数据库中不存在,则抛出异常。

    saveorupdate方法顾名思义是传入一个对象,由hibernate分析是save还是update。规则是,如果对象id是null就save,如果id不是null就update。

    @Test
    public void testSaveOrUpdate() {
        User user = new User();
        user.setName("Mary");
        user.setBirthday(new Date());
        //    user的id为null,执行insert操作。
        session.saveOrUpdate(user);
        
        User user2 = new User();
        user2.setId(2);
        user2.setName("Kobe");
        user2.setBirthday(new Date());
        //    user的id为2,数据库中有id等于2的记录,将执行update操作。
        session.saveOrUpdate(user2);
    }

    第一个saveorupdate将输出insert语句,因为id is null。第二个将输出update语句,因为id=2,在数据库中存在这条记录。

    若在*.hbm.xml的id属性上设置了unsaved-value的值,在做saveorupdate时,id不为null,但是值等于unsaved-value设置的值,也会进行save。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <!-- update之前先进行select,对象与数据库中的记录一致,则不执行update -->
    <class name="cn.net.bysoft.model.User" table="S_USER" select-before-update="true">
        <id name="id" type="integer" column="ID" unsaved-value="11">
            <!-- 指定主键的生成方式,native是使用数据库本地的方式 -->
            <generator class="native"></generator>
        </id>
        <property name="name" type="string" column="NAME"></property>
        <property name="birthday" type="timestamp" column="BIRTHDAY"></property>
    </class>
</hibernate-mapping>

        将id节点的设置了一个unsaved-value属性,值是11。

    @Test
    public void testSaveOrUpdate() {
        User user = new User();
        user.setId(11);
        user.setName("Mark");
        user.setBirthday(new Date());
        //    user的id为null,执行insert操作。
        session.saveOrUpdate(user);
    }

        这里设置了user的id等于11,与unsaved-value中的值一样。执行saveorupdate会发送一条insert语句。


    但是数据库中的id值不是11,而是自增的id数值。


    以上就是saveorupdate的基本应用。还剩下两个方法,一个是delete,一个是evict。先测试一下delete方法:

    @Test
    public void testSaveOrUpdate() {
        User user = new User();
        user.setId(6);
        session.delete(user);
        // 调用delete后,对象的状态变为删除状态。
        // 在事务commit之前,打印这个对象看看。
        System.out.println(user);
        /**
         * output: User [id=6, name=null, birthday=null]
         * */
        // 可以看到在commit之前,user对象还有id,那么在commit之前调用save或者update就会出现问题。
        // 建议不要删除状态的对象。
    }

    调用delete方法会把传入方法中的对象的状态改变成删除状态,但是在commit之前,这个对象还可以进行操作。建议不要使用删除状态的对象。

    hibernate提供了hibernate.use_identifier_rollback属性,在hibernate.cfg.xml中设置,将属性的值等于true。在调用delete方法时,hibernate会自动将删除的对象的id置空。

<!-- 删除对象时,将对象的id设置成null -->
<property name="hibernate.use_identifier_rollback">true</property>
    @Test
    public void testSaveOrUpdate() {
        User user = new User();
        user.setId(5);
        session.delete(user);
        System.out.println(user);
        /**
         * output:User [id=0, name=null, birthday=null]
         * */
    }

    设置了hibernate.use_identifier_rollback=true后,在删除对象可以看到输出的结果,对象的id被设置成了0。

    还有就是,如果删除的对象id在数据库中不存在,将会抛出异常。

    最后一个方法是evict,这个方法用来送session缓存中移除一个托管对象。也就是说将对象从持久化状态编程游离状态。

@Test
    public void testSaveOrUpdate() {
        //    持久化对象。
        User user = (User) session.get(User.class, 3);
        System.out.println(user);
        //    调用evict方法变成游离对象。
        session.evict(user);
    }

    还有一点需要注意的,同一个id的对象在session的缓存中只能有一个。

    @Test
    public void testSaveOrUpdate() {
        //    持久化对象。
        User user = (User) session.get(User.class, 3);
        System.out.println(user);
        //    调用evict方法把id为3的user变成游离对象。
        //    这是session缓存中已经没有对象了。
        session.evict(user);
        //    把一个新的id为3的user对象放到缓存中。
        User user1 = (User) session.get(User.class, 3);
        //    在尝试把旧的id为3的user对象放到缓存中,会抛出异常。
        //    此时session的缓存中已经有一个id为3的user对象了
        //    org.hibernate.NonUniqueObjectException: 
        //    A different object with the same identifier value was already associated with the session : 
        //    [cn.net.bysoft.model.User#3]
        session.update(user);
    }

    以上就是session的常用方法。

© 著作权归作者所有

XuePeng77
粉丝 47
博文 145
码字总数 193261
作品 0
丰台
私信 提问
SSH框架整合中Hibernate实现Dao层常用结构

一、疑惑   一直以来,我在使用SSH框架的时候经常会发现后者有疑虑到底使用hibernate的那种方法或者如何配置hibernate来操作数据库,经过 一段时间的学习下面我来总结一下,常用的dao层配置...

四季写爱
2018/07/19
0
0
Hibernater学习笔记(三)

1.Hibernate缓存 Hibernate一级缓存 hibernate 的一级缓存默认是打开的 hibernate的一级缓存使用范围,是session范围,从session创建到session关闭范围 hibernate的一级缓存中,储存数据必须...

Mr_欢先生
2017/12/08
0
0
Hibernate的一级缓存与二级缓存的区别

一、一级缓存与二级缓存的概念 一级缓存就是Session级别的缓存,一个Session做了一个查询操作,它会把这个操作的结果放在一级缓存中,如果短时间内这个session(一定要同一个session)又做了...

玄空
2012/08/01
23
0
关于hibernate,spring,lucene的几道题,答对几道算是对他们有基本了解了?

1, hibernate有哪三种检索方式?适用于那种场合? 2,持久化的三种状态及相互的转换? 3,映射继承的方式? 4,hibernate.cfg.xml中配置的方言是用来干什么的? 5,请阐述Session的作用和特...

军区文工团
2012/06/09
666
2
Hibernate 学习教程

第1课 课程内容. 6 第2课Hibernate UML图. 6 第3课 风格. 7 第4课 资源. 7 第5课 环境准备. 7 第6课 第一个示例HibernateHelloWorld 7 第7课 建立Annotation版本的HellWorld 9 第8课 什么是O...

梅_95
2016/08/15
51
0

没有更多内容

加载失败,请刷新页面

加载更多

rime设置为默认简体

转载 https://github.com/ModerRAS/ModerRAS.github.io/blob/master/_posts/2018-11-07-rime%E8%AE%BE%E7%BD%AE%E4%B8%BA%E9%BB%98%E8%AE%A4%E7%AE%80%E4%BD%93.md 写在开始 我的Arch Linux上......

zhenruyan
今天
4
0
简述TCP的流量控制与拥塞控制

1. TCP流量控制 流量控制就是让发送方的发送速率不要太快,要让接收方来的及接收。 原理是通过确认报文中窗口字段来控制发送方的发送速率,发送方的发送窗口大小不能超过接收方给出窗口大小。...

鏡花水月
今天
8
0
OSChina 周日乱弹 —— 别问,问就是没空

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @tom_tdhzz :#今日歌曲推荐# 分享容祖儿/彭羚的单曲《心淡》: 《心淡》- 容祖儿/彭羚 手机党少年们想听歌,请使劲儿戳(这里) @wqp0010 :周...

小小编辑
今天
907
11
golang微服务框架go-micro 入门笔记2.1 micro工具之micro api

micro api micro 功能非常强大,本文将详细阐述micro api 命令行的功能 重要的事情说3次 本文全部代码https://idea.techidea8.com/open/idea.shtml?id=6 本文全部代码https://idea.techidea8....

非正式解决方案
今天
5
0
Spring Context 你真的懂了吗

今天介绍一下大家常见的一个单词 context 应该怎么去理解,正确的理解它有助于我们学习 spring 以及计算机系统中的其他知识。 1. context 是什么 我们经常在编程中见到 context 这个单词,当...

Java知其所以然
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部