1. 程式人生 > >mybatis教程5(延遲加載和緩存)

mybatis教程5(延遲加載和緩存)

一個 encoding gre alias 運行時 定時 ble 3.0 manager

關聯關系

在關系型數據庫中,表與表之間很少是獨立與其他表沒關系的。所以在實際開發過程中我們會碰到很多復雜的關聯關系。在此我們來分析下載mybatis中怎麽處理這些關系

1對1關系

我們有一張員工表(T_EMP),一張部門表(T_DEPT)。員工表中的一條記錄對應於部門表中有且僅有一條記錄。這就是一對一的關聯關系。

查詢每個員工的信息及對應的部門信息

對象與對象1對1

部門對象:

    // 部門編號
    private int deptid;
    
    // 部門名稱
    private String dname;
    
    // 部門描述
    private String desc;

員工對象

    private int id;
    
    private String name;
    
    private int age;
    
    // 員工和部門的關聯關系是1對1,
    // 體現在面向對象中就是一個對象中包含有另一個對象
    private Department dept;

映射文件中處理

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 使用接口 代理的方式 namespace必須和接口的全路徑名稱一致 -->
<mapper namespace="com.sxt.dao.EmpMapper">
    <resultMap type="com.sxt.bean.Emp" id="baseMap">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="age" property="age"/>
        <association property="dept" javaType="com.sxt.bean.Department">
            <id column="deptid" property="deptid"/>
            <result column="dname" property="dname"/>
            <result column="desc" property="desc"/>
        </association>
    </resultMap>
    <select id="query" resultMap="baseMap">
        select
            t1.id id
            ,t1.name name
            ,t1.age age
            ,t2.deptid deptid
            ,t2.dname dname
            ,t2.desc 
        from t_emp t1
            left join t_dept t2
            on t1.deptid = t2.deptid
    </select>
    
</mapper>

技術分享圖片

1對多關系

查詢出所有的部門信息及該部門下所有員工的信息

對象與對象1對多

    // 部門編號
    private int deptid;
    
    // 部門名稱
    private String dname;
    
    // 部門描述
    private String desc;
    
    // 1對多  1個部門對象包含多個員工對象
    private List<Emp> emps;

映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 使用接口 代理的方式 namespace必須和接口的全路徑名稱一致 -->
<mapper namespace="com.sxt.dao.DeptMapper">
    <resultMap type="com.sxt.bean.Department" id="baseMap">
        <id column="deptid" property="deptid" />
        <result column="dname" property="dname" />
        <result column="desc" property="desc" />
        <!-- ofType List中泛型的類型 property為變量的名稱 -->
        <collection property="emps" ofType="emp">
            <id column="id" property="id" />
            <result column="name" property="name" />
            <result column="age" property="age" />
        </collection>
    </resultMap>
    <select id="query" resultMap="baseMap">
        select
        t1.deptid
        ,t1.dname
        ,t1.desc
        ,t2.name
        ,t2.age
        ,t2.id
        from t_dept t1
        left join t_emp t2
        on t1.deptid =
        t2.deptid
    </select>
</mapper>

查詢結果
技術分享圖片

多對多關系

==雙向的1對多既是多對多關系==

延遲加載

延遲查詢是一對一和一對多查詢的延續。
在默認的一對一和一對多中,一條SQL就能夠查詢到所有數據,但是,有的數據有時候一時半會用不上,例如查詢員工,捎帶獲取員工的部門數據,但是部門數據使用的頻率很低,這種時候可以使用延遲查詢,首先獲取到所有的員工數據,然後在需要的時候再去獲取部門數據。==當需要使用數據的時候才去加載==既是延遲加載

開啟延遲加載

全局配置文件中配置
技術分享圖片

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <properties resource="db.properties"></properties>
  <settings>
    <!-- 開啟延遲加載 -->
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/>
  </settings>
  <typeAliases>
    <!-- <typeAlias type="com.sxt.bean.User" alias="user"/> -->
    <package name="com.sxt.bean"/>
  </typeAliases>    
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <!-- 註冊映射文件 -->
  <mappers>
    <!-- <mapper resource="com/sxt/dao/UserMapper.xml"/> -->
    <package name="com.sxt.dao"/>
  </mappers>
</configuration>

1對1

查詢的SQL語句就不能通過一個SQL給查詢出來了,得分成多個SQL

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 使用接口 代理的方式 namespace必須和接口的全路徑名稱一致 -->
<mapper namespace="com.sxt.dao.EmpMapper">
    <resultMap type="com.sxt.bean.Emp" id="baseMap">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="age" property="age"/>
        <association property="dept"  javaType="com.sxt.bean.Department"
            column="deptid" select="queryDeptById">
            <id column="deptid" property="deptid"/>
            <result column="dname" property="dname"/>
            <result column="desc" property="desc"/>
        </association>
    </resultMap>
    
    <!-- 需要延遲加載的數據 -->
    <select id="queryDeptById" parameterType="int" resultType="department">
        select * from t_dept where deptid = #{deptid}
    </select>
    <!-- 查詢主表數據 -->
    <select id="query" resultMap="baseMap">
        select * from t_emp
    </select>
</mapper>

技術分享圖片
結果:
技術分享圖片
技術分享圖片

1對多

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 使用接口 代理的方式 namespace必須和接口的全路徑名稱一致 -->
<mapper namespace="com.sxt.dao.DeptMapper">
    <resultMap type="com.sxt.bean.Department" id="baseMap">
        <id column="deptid" property="deptid" />
        <result column="dname" property="dname" />
        <result column="desc" property="desc" />
        <!-- ofType List中泛型的類型 property為變量的名稱 -->
        <collection property="emps" ofType="emp" 
        column="deptid" select="queryEmpByDid">
            <id column="id" property="id" />
            <result column="name" property="name" />
            <result column="age" property="age" />
        </collection>
    </resultMap>
    <select id="queryEmpByDid" resultType="emp" parameterType="int">
        select * from t_emp where deptid=#{deptid}
    </select>
    <select id="query" resultMap="baseMap">
        select
        t1.deptid
        ,t1.dname
        ,t1.desc
        from t_dept t1
    </select>
</mapper>

技術分享圖片

緩存

## 緩存簡介:

緩存(Cache )是計算機領域非常通用的概念。它介於應用程序和永久性數據存儲源(如硬盤上的文件或者數據庫)之間,其作用是==降低==應用程序直接讀寫永久性數據存儲源的==頻率==,從而提高應用的運行性能。緩存中的數據是數據存儲源中數據的拷貝,應用程序在運行時直接讀寫緩存中的數據,只在某些特定時刻按照緩存中的數據來同步更新數據存儲源。
緩存的物理介質通常是內存,而永久性數據存儲源的物理介質通常是硬盤或磁盤,應用程序讀寫內在的速度顯然比讀寫硬盤的速度快,如果緩存中存放的數據量非常大,也會用硬盤作為緩存的物理介質。
緩存的實現不僅需要作為物理介質的硬件,同時還需要用於管理緩存的並發訪問和過期等策略的軟件。因此,緩存是通過軟件和硬件共同實現的
作用:降低訪問數據源【數據庫】頻率

緩存分類

類別 說明
一級緩存 事務範圍:緩存只能被當前事務訪問。緩存的生命周期
依賴於事務的生命周期當事務結束時,緩存也就結束生命周期。
在此範圍下,緩存的介質是內存。
二級緩存 進程範圍:緩存被進程內的所有事務共享。這些事務有
可能是並發訪問緩存,因此必須對緩存采取必要的事務隔離機制。
緩存的生命周期依賴於進程的生命周期,進程結束時,
緩存也就結束了生命周期。進程範圍的緩存可能會存放大量的數據,
所以存放的介質可以是內存或硬盤。
三級緩存 集群範圍:在集群環境中,緩存被一個機器或者多個機器的進程共享。
緩存中的數據被復制到集群環境中的每個進程節點,
進程間通過遠程通信來保證緩存中的數據的一致性,
緩存中的數據通常采用對象的松散數據形式

MyBatis支持1級緩存和2級緩存,在實際開發中,實際上很少使用到MyBatis自帶的緩存,大部分情況下,緩存都是使用EHCache,MemoryCache、Redis等等來實現緩存。

一級緩存

MyBatis中1級緩存是基於SqlSession的

    @Test
    public void query2() throws IOException {
        SqlSession session = DbUtils.getInstace().openSession();
        //通過Java動態代理自動提供了UserMapper的實現類
        EmpMapper mapper = session.getMapper(EmpMapper.class);
        // 第一次查詢,從數據庫中查詢的數據會保存在一級緩存中
        // key:
        List<Emp> list = mapper.query();
        for (Emp emp : list) {
            System.out.println(emp.getId()+","+emp.getName());
        }
        System.out.println("----------");
        // 先查看緩存中是否有該數據,如果沒有就從數據庫中查詢
        Emp emp = mapper.queryById(1);
        System.out.println(emp.getId()+","+emp.getName());
        
        System.out.println("----------");
        // 之前查詢的有,直接從緩存中獲取
        emp = mapper.queryById(1);
        System.out.println(emp.getId()+","+emp.getName());
        session.close();
    }

技術分享圖片跟蹤源碼發現,緩存的key是由id 屬性及sql語句組成的,所以第一個查詢和第二個查詢不同,沒有使用緩存。
技術分享圖片技術分享圖片技術分享圖片

二級緩存

二級緩存基於SqlSessionFactory
一級緩存的作用域只是SqlSession,範圍比較下,用到的不多。
二級緩存是進程級別的緩存,用的比較普遍,二級緩存mybatis本身沒有提供,常用的主鍵有Ehcache和Redis,本文主要講解Ehcache

使用步驟:

導包

<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>1.5.0</version>
</dependency>

<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.1.0</version>
</dependency>

開啟二級緩存

<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>

技術分享圖片

測試

技術分享圖片

mybatis教程5(延遲加載和緩存)