Java Hibernate 之 Session 狀態

偶my耶的部落格發表於2015-04-18

Session介面是Hibernate向程式提供操縱資料庫的最主要介面,是單執行緒物件,它提供了基本的儲存、更新、刪除和查詢方法。它有一個快取,儲存了持久化物件,當清理快取時,按照這些持久化物件同步更新資料庫。

注意:session的某些方法(persist,load)不會立即把改動寫入資料庫,而是快取到session的一級快取中,除非顯示呼叫flush,或者關閉session時才會更新到資料庫

  1. 臨時狀態(Transient):沒與session關聯
  2. 持久化狀態(Persistent):與session關聯,沒close
  3. 遊離狀態(Detached):當session.close後

Session的方法詳解

1.儲存

save:立即插入資料庫,並且返回主鍵

persist:不立即(延遲)插入資料庫,無返回值

2.獲取

load:載入物件後,對物件的改動不會立即重新整理到db,必須flush到db

ex: User user=session.load(User.class,2);

user.setName(‘gt’);

user.flush();   (延遲載入)

get:載入物件後,對物件的改動立即重新整理到db

3.更新

update:持久化物件,更新

saveOrUpdate:包含save()和update()功能,如果傳入的引數是臨時物件(沒有儲存過)就呼叫save()方法;如果傳入的引數是遊離物件,就呼叫update()方法

merge:不會持久化物件,只會把託管物件的修改更新到db

4.刪除

delete:從資料庫中刪除與JAVA物件對應的記錄

5.清理

flush:把快取同步到db

clear:清除session的快取大小(更新批量時,應考慮)

三種狀態的轉換關係

java框架篇---hibernate之session狀態

下面通過例項講解:

實體:

package cn.itcast.h_session_method;

public class User {
    private Integer id;
    private String name;
    private byte[] data = new byte[1024 * 1024 * 5];

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

對映檔案:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="cn.itcast.h_session_method">

    <!-- 
        lazy屬性:預設為true,預設可以懶載入。
     -->
    <class name="User" table="user" lazy="true">
        <id name="id">
            <generator class="native"></generator>
        </id>
        <property name="name"/>
    </class>

</hibernate-mapping>

配置檔案:hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

<session-factory>

    <!--資料庫連線設定 -->
    <property name="connection.driver_class">
        com.mysql.jdbc.Driver
    </property>
    <property name="connection.url">
        jdbc:mysql://localhost:3306/mytest
    </property>
    <property name="connection.username">root</property>
    <property name="connection.password">root</property>

    <!-- 方言 -->
    <property name="dialect">
        org.hibernate.dialect.MySQL5Dialect
    </property>

    <!-- 控制檯顯示SQL -->
    <property name="show_sql">true</property>

    <!-- 自動更新表結構 -->
    <property name="hbm2ddl.auto">update</property>
    <mapping resource="cn/itcast/h_session_method/User.hbm.xml" />

</session-factory>

</hibernate-configuration>

測試檔案

package cn.itcast.h_session_method;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

import com.java1234.util.HibernateSessionFactory;

public class App {

    private static SessionFactory sessionFactory = HibernateSessionFactory.getSessionFactory();

    // save():把臨時狀態變為持久化狀態(交給Sessioin管理)
    // 會生成:insert into ...
    @Test
    public void testSave() throws Exception {
        Session session = sessionFactory.openSession();
        session.beginTransaction();
        // --------------------------------------------

        User user = new User(); // 臨時狀態
        user.setName("test");
        session.save(user); // 變為了持久化狀態

        // --------------------------------------------
        session.getTransaction().commit();
        session.close();

        user.setName("李四"); // 遊離狀態
        System.out.println(user.getName()); // 遊離狀態
    }

    // update():把遊離狀態變為持久化狀態
    // 會生成:update ...
    // 在更新時,物件不存在就報錯
    @Test
    public void testUpdate() throws Exception {
        Session session = sessionFactory.openSession();
        session.beginTransaction();
        // --------------------------------------------

        User user = (User) session.get(User.class, 1);
        System.out.println(user.getName()); // 持久化狀態

        // session.clear(); // 清除Session中所有的物件
        session.evict(user); // 清除Session中一個指定的物件

        user.setName("newname3");
        session.update(user);
        System.out.println("----");
        // session.flush(); // 刷出到資料庫

        // --------------------------------------------
        session.getTransaction().commit(); // 
        session.close();
    }

    // saveOrUpdate():把臨時或遊離狀態轉為持久化狀態
    // 會生成:insert into 或 update ...
    // 在更新時,物件不存在就報錯
    // 本方法是根據id判斷物件是什麼狀態的:如果id為原始值(物件的是null,原始型別數字是0)就是臨時狀態,如果不是原始值就是遊離狀態。
    @Test
    public void testSaveOrUpdate() throws Exception {
        Session session = sessionFactory.openSession();
        session.beginTransaction();
        // --------------------------------------------

        User user = new User();
        user.setId(3); // 自己生成一個遊離狀態物件
        user.setName("newName");

        session.saveOrUpdate(user);

        // --------------------------------------------
        session.getTransaction().commit();
        session.close();
    }

    // delete():把持久化或遊離轉為刪除狀態
    // 會生成:delete ...
    // 如果刪除的物件不存在,就會拋異常
    @Test
    public void testDelete() throws Exception {
        Session session = sessionFactory.openSession();
        session.beginTransaction();
        // --------------------------------------------

        // User user = (User) session.get(User.class, 2); // 持久化

        User user = new User();
        user.setId(300);

        session.delete(user);
        session.flush();

        System.out.println("---");

        // --------------------------------------------
        session.getTransaction().commit();
        session.close();
    }

    // get():獲取資料,是持久化狀態
    // 會生成:select ... where id=?
    // 會馬上執行sql語句
    // 如果資料不存在,就返回null
    @Test
    public void testGet() throws Exception {
        Session session = sessionFactory.openSession();
        session.beginTransaction();
        // --------------------------------------------

        User user = (User) session.get(User.class, 5); // 持久化
        System.out.println(user.getClass());
        // System.out.println("---");
        // System.out.println(user.getName());

        // --------------------------------------------
        session.getTransaction().commit();
        session.close();
    }

    // load():獲取資料,是持久化狀態
    // 會生成:select ... where id=?
    // load()後返回的是一個代理物件,要求類不能是final的,否則不能生成子類代理,就不能使用懶載入功能了。
    // 讓懶載入失效的方式:一、把實體寫成final的;二、在hbm.xml中寫<class ... lazy="false">
    // 不會馬上執行sql語句,而是在第1次使用非id或class屬性時執行sql。
    // 如果資料不存在,就拋異常:ObjectNotFoundException
    @Test
    public void testLoad() throws Exception {
        Session session = sessionFactory.openSession();
        session.beginTransaction();
        // --------------------------------------------

        User user = (User) session.load(User.class, 5);
        System.out.println(user.getClass());
        System.out.println("---");
        System.out.println(user.getId());
        System.out.println(user.getName());
        // System.out.println(user.getName());

        // --------------------------------------------
        session.getTransaction().commit();
        session.close();
    }

    // 操作大量資料,要防止Session中物件過多而記憶體溢位
    @Test
    public void testBatchSave() throws Exception {
        Session session = sessionFactory.openSession();
        session.beginTransaction();
        // --------------------------------------------

        for (int i = 0; i < 30; i++) {
            User user = new User();
            user.setName("測試");
            session.save(user);

            if (i % 10 == 0) {
                session.flush(); // 先刷出
                session.clear(); // 再清空
            }
        }

        // --------------------------------------------
        session.getTransaction().commit();
        session.close();
    }

    @Test
    public void test2() throws Exception {
        Session session = sessionFactory.openSession();
        session.beginTransaction();
        // --------------------------------------------

        User user = (User) session.get(User.class, 5); // 持久化
        System.out.println(user.getName());

        // session.clear();
        // user = (User) session.get(User.class, 5); // 持久化

        session.refresh(user); // 重新整理Session快取中物件的狀態,即重新select一下
        System.out.println(user.getName());

        // --------------------------------------------
        session.getTransaction().commit();
        session.close();
    }
}

對於剛建立的一個物件,如果session中和資料庫中都不存在該物件,那麼該物件就是臨時物件(Transient)

臨時物件呼叫save方法,或者遊離物件呼叫update方法可以使該物件變成持久化物件,如果物件是持久化物件時,那麼對該物件的任何修改,都會在提交事務時才會與之進行比較,如果不同,則傳送一條update語句,否則就不會傳送語句

遊離物件就是,資料庫存在該物件,但是該物件又沒有被session所託管

相關文章