mybatis教程5(延遲加載和緩存)
關聯關系
在關系型數據庫中,表與表之間很少是獨立與其他表沒關系的。所以在實際開發過程中我們會碰到很多復雜的關聯關系。在此我們來分析下載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(延遲加載和緩存)