學習hibernate(二) -- session緩存

    session對象是操做數據庫的主要接口,能夠對數據庫進行保存、更新和刪除等一系列的操做,而且能夠將數據庫中的數據加載到java對象中。java

    session對象中有一個緩存,是session級別的,也稱之爲一級緩存。緩存中存儲的java對象被稱之爲持久化對象。持久化對象和數據庫中的相關記錄相互對應。sql

    看一段代碼:
數據庫

    private SessionFactory sessionFactory;
    private Session session;
    private Transaction transaction;

    @Before
    public void onLoad() {
        // 0.建立configuration對象,該對象保存着hibernate的配置信息和對象關係映射的信息。
        Configuration cfg = new Configuration().configure();
        // 1.建立sessionfactory對象
        StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder()
                .applySettings(cfg.getProperties());
        StandardServiceRegistry registry = builder.build();
        sessionFactory = cfg.buildSessionFactory(registry);
        // 2.建立session對象
        session = sessionFactory.openSession();
        // 3.開始事務
        transaction = session.beginTransaction();
    }

    @After
    public void onUnLoad() {
        // 1.提交事務
        transaction.commit();
        // 2.關閉session對象
        session.close();
        // 3.關閉sessionfactory對象
        sessionFactory.close();
    }

    @Test
    public void test() {
        User user = (User)session.load(User.class, 1);
        System.out.println(user);
        //    第二次get時,是從session cache中得到的。
        User user2 = (User)session.load(User.class, 1);
        System.out.println(user2);
    }

    

    能夠看到從數據庫中查詢了2次user對象,只輸出了一條sql語句。第二次的get操做其實是從緩存中得到的user對象,並無從對數據庫進行select查詢。緩存減小了對數據庫的操做。
緩存

    緩存與數據庫之間能夠經過某些方法互相同步,session能夠提取緩存中的對象向數據庫進行操做,也能夠將提取數據庫中的記錄來更新緩存中的對象。還能夠對session緩存進行清空。session

    經常使用的操做session緩存的方法有3個,它們分別是:app

  • flush測試

    當調用flush方法時,session將保證緩存中的對象與數據表中的記錄一致。也就是說,若緩存中的對象與數據庫表中的記錄不一致,則會發送update語句更新數據庫。ui

    若不顯示調用flush方法,當事務進行commit的時候會自動的調用一次flush方法。hibernate

    固然也有例外,在同一個事務中使用QBC或HQL語句也會隱士調用一次flush方法。
    code

  • refresh

    當調用refresh方法時,其實與flush大體相反。若緩存中的對象與數據庫表中的記錄不一致,則會發送一個select語句來更新session緩存中的對象。

  • clear

    當調用clear的時候,將清空session緩存中的對象。

    進行一些測試,來測試一下這幾個方法,首先是flush方法:

    @Test
    public void testSessionFlush() {
        //    從數據庫中加載一個對象。
        User user = (User)session.get(User.class, 1);
        user.setName("Kobe");
        System.out.println(user);
    }

    數據庫中的保存的Name是"Jack"這個值,get到User對象後,進行一次set,而後commit後會發現生成了一條update語句,數據庫中的值也改變了,這就是flush方法起到的做用,控制檯輸出以下圖:

     接下來測試一下refresh方法,寫一段代碼:

    @Test
    public void testSessionRefresh() {
        User user = (User)session.get(User.class, 1);
        System.out.println(user);
        session.refresh(user);
        User user2 = (User)session.get(User.class, 1);
        System.out.println(user);
    }

    在session.refresh(user)處打一個短點,在程序暫停後,去數據庫中手動修改name字段的值,在調用refresh方法後看看是否數據庫的值會更新緩存中對象的值,操做過程以下:

    程序運行到refresh方法以前,進行一次get,而且進行了輸出。能夠看到控制檯輸出了select和user的值。以後進入斷點等待繼續。

    手動修改了數據庫中name字段的值,將"Kobe"改爲了"Mark"。

    斷點向下一步,執行了refresh,能夠看到控制檯又輸出了一條select語句。說明對手動修改了數據庫中的數據後,與session緩存中的對象不一致了。須要獲取數據庫中的數據對持久化對象進行覆蓋。因而執行了一次select語句。

    最後輸出結構,這裏能夠看到雖然執行了select語句,可是並無改變持久化對象中的數據。這是因爲hibernate的事務隔離機制致使的。一共有4個隔離級別,分別是:

  • READ UNCOMMITED = 1

  • READ COMMITED = 2

  • REPEATABLE READ = 4

  • SERIALIZEABLE = 8

    能夠在配置文件中將隔離級別hibernate.connection.isolation設置成2,這樣refresh就會有預期的效果。

<!-- 設置hibernate的事務隔離機制 -->
<property name="hibernate.connection.isolation">2</property>

    設置後在進行一次測試,結果以下:

    當改變隔離級別後,先修改數據庫的值,在調用refresh方法,則會當即更新持久化對象。

    最後測試一下clear方法,該方法會清空session的緩衝區:

    @Test
    public void testSessionClear() {
        User user = (User)session.get(User.class, 1);
        session.clear();
        User user2 = (User)session.get(User.class, 1);
    }

    最初測試session緩存時,在一個事務中第二次調用get方法加載同一個對象,不會發送select語句到數據庫進行查詢。而在第二次調用get方法前,調用一次clear方法,則會清空session緩衝區中的持久化對象,在次調用get又須要到數據庫進行select操做,控制檯輸出的sql以下:

    能夠看到有兩個select語句被打印,證實了clear會清空緩衝區中的持久化對象。

    以上就是經常使用的操做session緩衝區的三個方法的測試。

相關文章
相關標籤/搜索