一、業務需求中對象之間的關係
在實際的開發當中,不僅要對錶與表之間的關係進行的詳細分析,也要針對在業務意義上對象之間的關係,通常的關係爲:一對一、一對多、多對多;
二、針對使用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;
完成的需求:根據訂單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的,範圍是mapper的namespace,相同的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)
- l 設置statement是否開啓二級緩存
如果讓某個statement啓用二級緩存,設置useCache=true(默認值爲true)
3.2、二級緩存原理
如果二緩存開啓,首先從二級緩存查詢數據,如果二級緩存有則從二級緩存中獲取數據,如果二級緩存沒有,從一級緩存找是否有緩存數據,如果一級緩存沒有,查詢數據庫。
4、使用Ehcache進行二級緩存
Mybatis控制二級緩存策略,二級緩存緩存介質使用Ehcache。
讓Ehcache和mybatis進行整合。
實際上還是mybatis進行控制Ehcache,把緩存的數據存儲在內存當中!
示例代碼:https://github.com/libolibolibo/mybatis1217_22.git
這裏附上mybatis的逆向工程(開發時可以使用該工程):https://github.com/libolibolibo/generatorSqlmapCustom