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

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

  • 临时状态sql

    临时状态通常来讲就是咱们使用new关键字建立的对象,尚未和session关联上,而且对象的id为null。调用session的save方法、saveorupdate方法、persist方法、merge方法、get方法和load方法均可以使临时状态对象变为持久化状态对象。
    数据库

  • 持久化状态编程

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

  • 游离状态session

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

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

  • 删除状态测试

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

    以上就是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的经常使用方法。

相关文章
相关标签/搜索