1. 程式人生 > >mybatis實現物件之間的關係(一對一、一對多、多對多)以及mybatis的快取機制

mybatis實現物件之間的關係(一對一、一對多、多對多)以及mybatis的快取機制

一、業務需求中物件之間的關係

在實際的開發當中,不僅要對錶與表之間的關係進行的詳細分析,也要針對在業務意義上物件之間的關係,通常的關係為:一對一、一對多、多對多;

二、針對使用mybatis處理這三種關係

1、業務模型說明

這裡用用使用者表、訂單表、訂單詳情表、商品表著四張表之間,說明物件這三種之間的關係:


2、一對一的關係

2.1、用查詢訂單表的詳情orders表,來說明一對一的關係(一個訂單資訊對應一個使用者)

2.2、使用resultType和resultMap都可以實現一對一的關係的

2.21、使用resultType實現一對一的關係

resultType標籤對應的結果對映到一個包裝類上面,這個包裝類包含著order表和user表的所有的屬性資訊;(很好理解啊,就是sql查詢返回的資料要對應到java物件中,如果使用包裝型別的設計方法就是用resultTpye,如果使用在兩者中插入某一類的物件作為屬性,就是用resultMap)

包裝類:

public class OrdersCustom extends  Orders {
	
	//使用者名稱稱 
	private String username;
	//使用者地址
	private String address;
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	
	
}
對映檔案.xml
<!-- 使用resultType實現訂單查詢,關聯查詢使用者資訊 -->
	<select id="findOrdersUserList" resultType="cn.itcast.mybatis.po.OrdersCustom">

		SELECT
		orders.*,
		user.username,
		user.address
		FROM
		orders,
		USER
		WHERE orders.user_id =
		user.id

	</select>

對用的mapper介面
// 查詢訂單及使用者資訊
	public List<OrdersCustom> findOrdersUserList() throws Exception;

2.22、使用resultMap來說明一對一的關係

(這裡resultMap對映到orders物件後,但是裡面又有user要對映,所以,相當於在orders物件對映之後又對映到user一次,相當於連續兩次的對映,所以在是一對一的情況下,使用resultType)

對映到java物件

public class Orders {
	private int id;//訂單id
	private int user_id;//使用者id
	private String order_number;//訂單號
	
	//使用者資訊
	private User user;

對映檔案.xml

<!-- 定義訂單資訊及使用者資訊的resultMap -->
	<resultMap type="orders" id="ordersUserResultMap">
		<!-- id:訂單資訊的唯 一約束 如果由多個欄位決定一條唯 一記錄,id標籤需要定義多個 -->
		<id column="id" property="id" />
		<result column="order_number" property="order_number" />
		<result column="user_id" property="user_id" />


		<!-- 配置使用者對映資訊 將sql查詢的使用者資訊對映到orders中的user屬性中 association:用於單個關聯物件的對映 property:將關聯資訊對映到orders的哪個屬性 
			javaType:對映屬性的型別 -->
		<association property="user" javaType="cn.itcast.mybatis.po.User">
			<!-- id:關聯的使用者資訊的唯 一約束 property:id指定 的列對映到關聯cn.itcast.mybatis.po.User類的哪個屬性 -->
			<id column="user_id" property="id" />
			<result column="username" property="username" />
			<result column="address" property="address" />
		</association>




	</resultMap>


<!-- 使用resultMap實現訂單查詢,關聯查詢使用者資訊 -->
	<select id="findOrdersUserListResultMap" resultMap="ordersUserResultMap">

		SELECT
		orders.*,
		user.username,
		user.address
		FROM
		orders,
		USER
		WHERE orders.user_id
		= user.id

	</select>

對用的mapper介面
// 查詢訂單及使用者資訊使用resultMap
	public List<Orders> findOrdersUserListResultMap() throws Exception;
3、一對多的關係

完成的需求:根據訂單orders查詢到訂單的明細orderdetail

resultMap將訂單明細資訊對映到Orders.java的屬性中;

(實際上就是在orders的物件當中把orderdetail集合又映射了一遍)

對映的java物件中;
public class Orders {
	private int id;//訂單id
	private int user_id;//使用者id
	private String order_number;//訂單號
	
	//使用者資訊
	private User user;
	
	//訂單明細
	private List<Orderdetail> orderdetails;

對映檔案.xml

注意,為了防止程式碼的可重用性,mybatis不止提供了sql片段,還提供了繼承:

<!-- 定義訂單及訂單明細的resultMap extends:繼承哪個resultMap,如果 是跨namespace前邊加namespace是 -->
	<resultMap type="orders" id="ordersUserDetailResultMap"
		extends="ordersUserResultMap">
		<!-- 訂單及使用者資訊,繼承於ordersUserResultMap -->


		<!-- 對映訂單明細資訊 collection:對映集合物件 property:將明細資訊對映到哪個集合屬性中。 ofType:集合中物件的型別 -->
		<collection property="orderdetails" ofType="cn.itcast.mybatis.po.Orderdetail">
			<!-- id:訂單明細的唯 一約束 property:ofType指定 型別的屬性 -->
			<id column="orderdetail_id" property="id" />
			<result column="item_id" property="item_id" />
			<result column="item_num" property="item_num" />
			<result column="item_price" property="item_price" />


		</collection>


<!-- 查詢訂單及訂單明細資訊 -->
	<select id="findOrdersUserDetailList" resultMap="ordersUserDetailResultMap">
		SELECT
		orders.*,
		user.username,
		user.address,
		orderdetail.id orderdetail_id,
		orderdetail.item_id,
		orderdetail.item_num,
		orderdetail.item_price
		FROM
		orders,
		USER,
		orderdetail
		WHERE orders.user_id = user.id AND orders.id =
		orderdetail.orders_id
	</select>
對應的mapper介面:
// 查詢訂單及訂單明細資訊
	public List<Orders> findOrdersUserDetailList() throws Exception;

3、多對多關係

需求:查詢所有訂單資訊及訂單明細的商品資訊

對映到的java物件:

public class Orders {
	private int id;//訂單id
	private int user_id;//使用者id
	private String order_number;//訂單號
	
	//使用者資訊
	private User user;
	
	//訂單明細
	private List<Orderdetail> orderdetails;
因為在   //訂單明細 private List<Orderdetail> orderdetails;中有外來鍵關聯的item資訊,所以這裡可以使用在Orderdetail物件中設定Items的屬性:
public class Orderdetail {
	private int id;//主鍵
	private int orders_id;//訂單id
	private int item_id;//商品id
	private int item_num;//商品數量
	private Float item_price;//商品價格
	
	//商品資訊
	private Items items;//明細對應的商品資訊 

對應的mapper.xml

<!-- 定義訂單及明細和商品資訊 -->
	<resultMap type="orders" id="ordersUserDetailItemResultMap"
		extends="ordersUserResultMap">
		<!-- 訂單及使用者資訊,繼承於ordersUserResultMap -->
		<!-- 對映訂單明細資訊 collection:對映集合物件 property:將明細資訊對映到哪個集合屬性中。 ofType:集合中物件的型別 -->
		<collection property="orderdetails" ofType="cn.itcast.mybatis.po.Orderdetail">
			<!-- id:訂單明細的唯 一約束 property:ofType指定 型別的屬性 -->
			<id column="orderdetail_id" property="id" />
			<result column="item_id" property="item_id" />
			<result column="item_num" property="item_num" />
			<result column="item_price" property="item_price" />




			<!-- 對映商品資訊 property:將商品資訊對映到cn.itcast.mybatis.po.Orderdetail的items屬性中 -->
			<association property="items" javaType="cn.itcast.mybatis.po.Items">
				<!-- id:商品資訊的唯 一標識 -->
				<id column="item_id" property="id" />
				<result column="item_detail" property="item_detail" />
				<result column="item_name" property="item_name" />
				<result column="item_price_price" property="item_price" />
			</association>
		</collection>
	</resultMap>


<!-- 查詢訂單及訂單明細資訊及商品資訊 -->
	<select id="findOrdersUserDetailItemList" resultMap="ordersUserDetailItemResultMap">
		SELECT
		orders.*,
		user.username,
		user.address,
		orderdetail.id orderdetail_id,
		orderdetail.item_id,
		orderdetail.item_num,
		orderdetail.item_price ,
		items.item_detail,
		items.item_name,
		items.item_price item_price_price
		FROM
		orders,
		USER,
		orderdetail,
		items
		WHERE orders.user_id = user.id
		AND
		orders.id = orderdetail.orders_id
		AND orderdetail.item_id = items.id
	</select>

對應的mapper介面:
//查詢訂單及明細和商品資訊
	public List<Orders> findOrdersUserDetailItemList()throws Exception;

三、mybatis的快取機制

將從資料庫中查詢出來的資料快取起來,快取介質:記憶體、磁碟,從快取中取資料,而不從資料庫查詢,減少了資料庫的操作,提高了資料處理效能。


1、mybatis的延遲載入

延遲載入意義:在需求允許的情況下,先查詢單表,當需要關聯其它表查詢時,進行延遲載入,去關聯查詢;

達到目標:不需要關聯資訊時不查詢,需要時再查詢。好處:提高資料庫的效能。

1.1、mybatis延遲載入的配置:

SqlMapConfig.xml中配置setting全域性引數:

lazyLoadingEnabled:延遲載入的總開關,設定為true

aggressiveLazyLoading:設定為false,實現按需載入(將積極變為消極)

<!-- 全域性配置引數 -->
		<settings>
			<!-- 開啟延遲載入  -->
			<setting name="lazyLoadingEnabled" value="true" />
			<setting name="aggressiveLazyLoading" value="false" />
		</settings>

在mapper.xml的配置檔案裡配置延遲載入:(

需求:

查詢訂單資訊,關聯查詢使用者資訊。

延遲載入需求:首次只查詢訂單資訊,當需要關聯查詢使用者資訊時,再查詢使用者資訊。

<!-- 訂單及使用者的resultMap,實現延遲載入 -->
	<resultMap type="orders" id="ordersResultMap">
		<!-- 配置訂單資訊的對映 -->
		<id column="id" property="id" />
		<result column="user_id" property="user_id" />
		<result column="order_number" property="order_number" />
		<!-- 配置延遲載入 使用者資訊
			 select:延遲載入 時呼叫 的statement,如果跨名稱空間,需要加上namespace 
			 column:將哪一列的值作為引數 傳到延遲載入 的statement -->
		<association property="user" javaType="cn.itcast.mybatis.po.User"
			select="cn.itcast.mybatis.mapper.UserMapper.findUserById" column="user_id">

		</association>

	</resultMap>

	<!-- 訂單資訊查詢,使用延遲載入  -->
	<select id="findOrdersList" resultMap="ordersResultMap">
		select * from orders
	</select>

2、mybatis的一級快取

Mybatis預設提供一級快取,快取範圍是一個sqlSession。(也就是指的一條sql語句)

在同一個SqlSession中,兩次執行相同的sql查詢,第二次不再從資料庫查詢。


執行提交清除快取測試:

如果第一次查詢後,執行commit提交,mybatis會清除快取,第二次查詢從資料庫查詢。


一級快取原理:

一級快取採用Hashmap儲存,mybatis執行查詢時,從快取中查詢,如果快取中沒有從資料庫查詢。

如果該SqlSession執行commit()提交,清除快取。


3、mybatis的二級快取

快取範圍是跨SqlSession的,範圍是mappernamespace,相同的namespace使用一個二級快取結構。

需要進行引數配置讓mybatis支援二級快取

3.1、二級快取的配置

在全域性的配置檔案sqlMapConfig.xml中配置:

<!-- 全域性配置引數 -->
		<settings>
			<!-- 開啟二級快取 -->
			<setting name="cacheEnabled" value="true"/>
		</settings>

在mapper.xml中的配置:
<mapper namespace="cn.itcast.mybatis.mapper.UserMapper">


	<!-- 開啟二級快取 -->
	<cache /> 

3.11、使用二級快取注意的事項
  • l實現序列化:

注意:將查詢對映物件結果的pojo物件進行序列化實現 java.io.Serializable介面

  • l 如何清除快取:

執行相同的statement,如果執行提交操作需要清除二級快取。

如果想讓statement執行後重新整理快取(清除快取),在statement中設定flushCache="true" (預設值true

  • 設定statement是否開啟二級快取

如果讓某個statement啟用二級快取,設定useCache=true(預設值為true


3.2、二級快取原理

如果二快取開啟,首先從二級快取查詢資料,如果二級快取有則從二級快取中獲取資料,如果二級快取沒有,從一級快取找是否有快取資料,如果一級快取沒有,查詢資料庫。

4、使用Ehcache進行二級快取

Mybatis控制二級快取策略,二級快取快取介質使用Ehcache

Ehcachemybatis進行整合。


實際上還是mybatis進行控制Ehcache,把快取的資料儲存在記憶體當中!