1. 程式人生 > >Mybatis延遲加載、緩存、逆向工程

Mybatis延遲加載、緩存、逆向工程

特定 display 單表 指定 mybatis lap 數據庫 bsp bat

一、Mybatis中的延遲加載

  1、延遲加載背景:Mybatis中Mapper配置文件中的resultMap可以實現高級映射(使用association、collection實現一對一及一對多(多對多)映射),同樣的association、collection具備延遲加載功能。所謂延遲加載,就是先單表查詢,需要時再從關聯表去關聯查詢(同樣也可能只是是單表查詢),大大單表查詢速度更快,所以可以間接的提高數據庫性能

  2、在mybatis核心配置文件中配置,其中lazyLoadingEnabled表示懶加載開關、aggressiveLazyLoading表示非懶加載(積極加載),通過在Mybatis核心配置文件中配置這些屬性的值來使用Mybatis的懶加載,具體配置方式如下:

    <settings>
        <!--懶加載模式在Mybatis中默認是關閉的-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--不同於懶加載的:積極加載方式,所以在懶加載的時候設置該屬性為false-->
        <setting name="aggressiveLazyLoading" value="false"></setting>
    </settings>

  3、由於是使用懶加載,所以我們顯然可以將Mapper配置文件中的查詢分為兩張單表查詢的statment,其中User表的查詢放在Order查詢配置的resultMap中,並進行延遲加載的設置

技術分享圖片
    <select id="findUserByUid" parameterType="int" resultType="cn.mybatis.po.User">
        SELECT * FROM USER WHERE uid = #{id}
    </select>

    <resultMap id="OrderAndUserByLazyLoading" type="cn.mybatis.po.Order">
        <id column="oid" property="oid"></id>
        <
result column="total" property="total"></result> <result column="ordertime" property="ordertime"></result> <result column="name" property="name"></result> <!-- 實現延遲加載功能 select:指定延遲加載需要執行的statment的id(即根據用戶id查詢用戶信息的select的statment) column:關聯查詢的列信息--> <association property="user" javaType="cn.mybatis.po.User" select="findUserByUid" column="uid"> </association> </resultMap> <select id="findOrderAndUserByLazyLoading" resultMap="OrderAndUserByLazyLoading"> SELECT * FROM orders </select>
LazyLoading配置文件信息

技術分享圖片

  4、在Mapper.java中添加了延遲加載的測試方法

    //延遲加載測試方法
    public List<Order> findOrderAndUserByLazyLoading() throws Exception;

  5、使用Junit測試延遲加載的測試代碼

 1     @Test
 2     public void testFindOrderAndUserByLazyLoading() throws Exception {
 3         SqlSession sqlSession = sqlSessionFactory.openSession();
 4         OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
 5 
 6         List<Order> orderList= orderMapper.findOrderAndUserByLazyLoading();
 7 
 8         for (Order order : orderList) {
 9             System.out.println(order.getUser());
10         }
11 
12         sqlSession.close();
13     }

  6、測試結果,從測試結果可以看出,我們首先只是單表查詢了order是表的信息,然後在遍歷查詢到的結果(打印User信息)的時候,又發出查詢user信息的Sql,從而實現了延遲加載的功能

技術分享圖片

二、Mybatis中的一級緩存

  1、一級緩存是在SqlSession 層面進行緩存的。即在同一個SqlSession 中,多次調用同一個Mapper中的同一個statment並且是同一個參數的話,只會進行一次數據庫查詢,然後把數據緩存到緩沖中,如果以後要查詢相同的Sql和參數,就直接先從緩存中取出數據,不會直接去查數據庫。? 但是不同的SqlSession對象,因為不用的SqlSession都是相互隔離的,所以相同的Mapper、參數和方法,他還是會再次發送到SQL到數據庫去執行,返回結果。(本質上是在SqlSession作用域下面的HashMap本地緩存,當 SqlSession 刷新或 關閉之後,該Session中的所有 緩存數據就將清空。)可以用下面的這張圖來表示一級緩存

技術分享圖片

  2、我們來使用一級緩存進行測試,首先通過上面一級緩存的簡單定義,我們可以得到下面的這張簡略圖,用以示解一級緩存。在實例圖中,第一次查詢某條記錄時候,Mybatis所做的就是將查詢到的結果放在該SqlSession的緩存中,如果期間沒有該數據的修改、刪除、或者增加操作,那麽之後再讀取該數據就會直接從緩存中得到數據,而不用再向數據庫發Sql請求,當然,如果第一次查詢之後,對數據進行了delete、update、insert操作,那麽就會刪除緩存中的數據,這樣做的目的也很顯然,保證數據的最新性,避免出現臟讀的情況。

技術分享圖片

  3、一級緩存的測試(Mybatis中默認開啟的是一級緩存)

  做個簡單的測試:按照上面的圖中所示,我們查詢兩次id=1的User信息,並且兩次查詢期間沒有進行會清空緩存的操作,結果應該是只向數據庫發送一次Sql查詢

 1     @Test
 2     public void testUpdateUserInfo() throws Exception {
 3         SqlSession sqlSession = sqlSessionFactory.openSession();
 4         UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 5 
 6         User user1 = userMapper.findUserById(1);
 7         System.out.println(user1);
 8 
 9         User user2 = userMapper.findUserById(1);
10         System.out.println(user2);
11 
12         sqlSession.close();
13     }

  4、我們通過觀察日誌可以看出,只是在第一次查詢的時候發送了Sql,第二次是直接打印user信息

  技術分享圖片

  當然,接下來要做的測試就是在兩次查詢期間做insert操作,然後觀察日誌,結果應該是發現會想數據庫發送兩次sql

 1     @Test
 2     public void testUpdateUserInfo() throws Exception {
 3         SqlSession sqlSession = sqlSessionFactory.openSession();
 4         UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 5 
 6         User user1 = userMapper.findUserById(1);
 7         System.out.println(user1);
 8 
 9         User user = new User("InsertTest","insert","insert","man");
10         userMapper.insertUserInfo(user);
11         sqlSession.commit();
12 
13         User user2 = userMapper.findUserById(1);
14         System.out.println(user2);
15 
16         sqlSession.close();
17     }

  5、我們在測試代碼中加了insert之後,通過觀察日誌可以發現,在查詢過程中,向Database發送了兩條select語句,可以驗證上面的猜想

  技術分享圖片

三、Mybatis中的二級緩存

  1、二級緩存的實現機制基本上和一級緩存機制相同,不同的作用域不一樣,二級緩存區域在一個個的mapper中。顯然,由於多個SqlSession可以操作同一個mapper,所以二級緩存比一級緩存域更大。二級緩存按照mapper劃分,簡而言之,也可說成按照mapper中的namespace進行劃分,這樣看來,每一個namespace下面都有一個二級緩存區域,而如果兩個mapper的namespace相同,那麽數據會緩存在相同的緩存區域中。當然,類似於一級緩存的特點,如果不同的SqlSession進行數據的insert、delete、update操作的話,也會清空二級緩存中的數據

  2、開啟二級緩存後,進行測試。具體使用二級緩存在配置文件中的配置為:

  首先在Mybatis的核心配置文件中配置二級緩存(本項目中的SQLMapConfig.xml)

    <!--settings配置二級緩存 -->
    <settings>
        <setting name="cacheEnabled" value="true"></setting>
    </settings>

  然後在需要配置二級緩存的特定mapper配置文件中進行添加二級緩存的配置

  技術分享圖片

  3、編寫測試程序並運行

 1  @Test
 2     public void testCache() throws Exception {
 3         SqlSession sqlSession1 = sqlSessionFactory.openSession();
 4         UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
 5         User user1 = userMapper1.findUserById(1);
 6         System.out.println(user1);
 7         //需要將SqlSession關閉才能將數據寫入緩存
 8         sqlSession1.close();
 9 
10 
11         SqlSession sqlSession2 = sqlSessionFactory.openSession();
12         UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
13         User user2 = userMapper2.findUserById(1);
14         System.out.println(user2);
15         sqlSession2.close();
16 
17 
18     }

  在運行的時候出現了下面的異常,原因就是沒有實現序列化接口,由於緩存數據可能再本地內存中,也可能在其他存儲介質上,所以存在對象的序列化和反序列化

技術分享圖片

  所以在實現序列化接口之後,再次運行,得到下面的結果

技術分享圖片

Mybatis延遲加載、緩存、逆向工程