延遲加載
1. 需求:
查詢訂單並關聯查詢用戶信息
- 先對orders表進行單表查詢,然後通過外鍵user_id對user表進行查詢
- 定義兩個mapper方法對應的statement
1.1只查詢訂單信息
在查詢訂單的statement中使用association去延遲加載(執行)關聯查詢用戶信息
1.2關聯查詢用戶信息
通過查詢到的訂單信息中的user_id來關聯查詢用戶信息
2. SQL
SELECT orders.*,
(SELECT `user`.user_name
FROM `user`
WHERE `user`.user_id = orders.user_id)user_name,
(SELECT `user`.user_birth
FROM `user`
WHERE `user`.user_id = orders.user_id)user_birth
FROM orders
3. mapper.xml
<!-- 延遲加載:查詢訂單並關聯查詢用戶信息 -->
<resultMap type="com.wzw.mybatis.model.Orders" id="OrderAndUserResultMap">
<!-- 配置訂單信息 -->
<id column="orders_id" property="orders_id"/>
<result column="number" property="number"/>
<!-- <result column="user_id" property="user_id"/> -->
<!-- 配置用戶信息,實現延遲加載
select屬性:指定延遲加載需要執行的statement的id
column屬性:訂單信息關聯查詢用戶信息查詢的列,user_id
-->
<association property="user" javaType="com.wzw.mybatis.model.User"
select="com.wzw.mybatis.mapper.UserMapper.selectUserById" column="user_id">
</association>
</resultMap>
<select id="selectOrdersAndUserLazyLoading" resultMap="OrderAndUserResultMap">
SELECT * FROM orders
</select>
UserMapper.xml
<mapper namespace="com.wzw.mybatis.mapper.UserMapper">
<!-- 根據user_id查詢用戶信息 -->
<select id="selectUserById" parameterType="java.lang.Integer" resultType="user">
SELECT * FROM `user` WHERE user_id = #{id}
</select>
</mapper>
4. mapper.java
//延遲加載:查詢訂單並關聯查詢用戶信息
public List<Orders> selectOrdersAndUserLazyLoading() throws IOException;
5. SQLMapConfig.xml延遲加載配置
<!-- 延遲加載 -->
<settings>
<setting name="lazyLoadingEnabled" value="true"/><!-- 默認false -->
<setting name="aggressiveLazyLoading" value="false"/><!-- 默認true -->
</settings>
6. 測試代碼
OrdersMapper mapper = sqlSession.getMapper(OrdersMapper.class);
//查詢訂單信息
List<Orders> ordeList = mapper.selectOrdersAndUserLazyLoading();
//對訂單集合遍歷
for (Orders orders : ordeList) {
//按需加載,查詢用戶信息
User user = orders.getUser();
System.out.print(user);
}
緩存
一級緩存是SqlSession級別的緩存。在操作數據庫時需要創建SqlSession對象。在SqlSession對象中有一個數據結構(HashMap)用於存儲緩存數據。不同的SqlSession之間的緩存數據區域(HashMap)互不影響。
二級緩存是mapper級別的緩存。多個SqlSession執行同一個mapper的SQL語句,多個SqlSession共用二級緩存,二級緩存是跨SqlSession的。
1. 一級緩存
mybatis默認開啓一級緩存
- 第一次對user_id=1的用戶進行查詢,首先看一級緩存中是否存在,不存在,此時將查詢信息user存入SqlSession的一級緩存中
- 此時對user執行更新,刪除等需要SqlSession.commit()操作時,清空SqlSession中一級緩存內的數據
- 第三次對user_id=1的用戶進行查詢,首先看一級緩存中是否存在,不存在,此時將查詢信息user存入SqlSession的一級緩存中
- 第四次對user_id=1的用戶進行查詢,發現一級緩存中存在數據,從一級緩存中讀取數據
2. 二級緩存
按mapper區分,每一個mapper都有自己的二級緩存區域,此處mapper按namespace區分。既每一個namespace的mapper有一個二級緩存區域。如果兩個mapper的namespace相同,則執行這兩個mapper中的SQL語句查詢到的數據都存儲在同一個二級緩存中。
2.1 開啓二級緩存
SQLMapConfig.xml
<settings>
<!-- 延遲加載 -->
<setting name="lazyLoadingEnabled" value="true"/><!-- 默認false -->
<setting name="aggressiveLazyLoading" value="false"/><!-- 默認true -->
<!-- 配置二級緩存,默認開啓 -->
<setting name="cacheEnabled" value="true"/>
</settings>
UserMapper.xml
<!-- 開啓二級緩存 -->
<cache></cache>
2.2 pojo類實現序列號Serializable
public class User implements Serializable
2.3 禁用二級緩存
useCache=false,在statement中配置該條命令,可禁用二級緩存,默認true。
針對每次查詢都需要最新的數據
<!-- 根據user_id查詢用戶信息 -->
<select id="selectUserById" parameterType="java.lang.Integer" resultType="user" useCache="false">
SELECT * FROM `user` WHERE user_id = #{id}
</select>
2.4 刷新緩存(清空緩存)
flushCache=true,默認爲true。在insert、update、delete時,每次操作後需要刷新。避免出現髒讀。
2.5 Cache標籤參數
- flushInterval(刷新間隔):可設置爲任意的正整數,表示一個毫秒爲單位的時間段。默認不設置(無刷新間隔),緩存在調用語句時刷新。
- size(引用數目):可以設置爲任意整數,要記住你緩存的對象數目和你運行環境的可用內存資源數目。默認爲1024。
- readOnly(只讀):true/false。只讀的緩存會給所有調用者返回緩存對象的相同實例。因此這些對象不能被修改。可讀寫的緩存會返回對象的拷貝(通過序列號)。這會慢一些,但是安全,因此默認false。
3 mybatis整合ehcache
Mybatis提供了一個cache接口,如果要實現自己的緩存邏輯,實現cache接口開發即可。
Mybatis和ehcache整合,mybatis和ehcache整合包中提供了一個cache接口的實現類。