一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務(wù)器之家 - 編程語言 - JAVA教程 - MyBatis高級(jí)映射和查詢緩存

MyBatis高級(jí)映射和查詢緩存

2020-05-23 12:02鹿天斐 JAVA教程

這篇文章主要介紹了MyBatis高級(jí)映射和查詢緩存的相關(guān)資料,需要的朋友可以參考下

MyBatis高級(jí)映射和查詢緩存

 mybatis框架執(zhí)行過程:

1、配置mybatis的配置文件,SqlMapConfig.xml(名稱不固定)
2、通過配置文件,加載mybatis運(yùn)行環(huán)境,創(chuàng)建SqlSessionFactory會(huì)話工廠
SqlSessionFactory在實(shí)際使用時(shí)按單例方式。

3、通過SqlSessionFactory創(chuàng)建SqlSession
SqlSession是一個(gè)面向用戶接口(提供操作數(shù)據(jù)庫方法),實(shí)現(xiàn)對(duì)象是線程不安全的,建議sqlSession應(yīng)用場(chǎng)合在方法體內(nèi)。

4、調(diào)用sqlSession的方法去操作數(shù)據(jù)。
如果需要提交事務(wù),需要執(zhí)行SqlSession的commit()方法。

5、釋放資源,關(guān)閉SqlSession

mapper代理開發(fā)方法(建議使用)

只需要程序員編寫mapper接口(就是dao接口)

程序員在編寫mapper.xml(映射文件)和mapper.java需要遵循一個(gè)開發(fā)規(guī)范:

1、mapper.xml中namespace就是mapper.java的類全路徑。

2、mapper.xml中statement的id和mapper.java中方法名一致。

3、mapper.xml中statement的parameterType指定輸入?yún)?shù)的類型和mapper.java的方法輸入 參數(shù)類型一致。

4、mapper.xml中statement的resultType指定輸出結(jié)果的類型和mapper.java的方法返回值類型一致。

本文內(nèi)容:

對(duì)訂單商品數(shù)據(jù)模型進(jìn)行分析。

高級(jí)映射:(了解)

實(shí)現(xiàn)一對(duì)一查詢、一對(duì)多、多對(duì)多查詢。

延遲加載

查詢緩存

一級(jí)緩存

二級(jí)緩存(了解mybatis二級(jí)緩存使用場(chǎng)景)

mybatis和spirng整合(掌握)

逆向工程(會(huì)用)

訂單商品數(shù)據(jù)模型

數(shù)據(jù)模型分析思路

1、每張表記錄的數(shù)據(jù)內(nèi)容

分模塊對(duì)每張表記錄的內(nèi)容進(jìn)行熟悉,相當(dāng)于你學(xué)習(xí)系統(tǒng)需求(功能)的過程。

2、每張表重要的字段設(shè)置

非空字段、外鍵字段

3、數(shù)據(jù)庫級(jí)別表與表之間的關(guān)系

外鍵關(guān)系

4、表與表之間的業(yè)務(wù)關(guān)系

在分析表與表之間的業(yè)務(wù)關(guān)系時(shí)一定要建立在某個(gè)業(yè)務(wù)意義基礎(chǔ)上去分析。

數(shù)據(jù)模型分析

MyBatis高級(jí)映射和查詢緩存

用戶表user:

記錄了購買商品的用戶信息

訂單表:orders

記錄了用戶所創(chuàng)建的訂單(購買商品的訂單)

訂單明細(xì)表:orderdetail:

記錄了訂單的詳細(xì)信息即購買商品的信息

商品表:items

記錄了商品信息

表與表之間的業(yè)務(wù)關(guān)系:

在分析表與表之間的業(yè)務(wù)關(guān)系時(shí)需要建立在某個(gè)業(yè)務(wù)意義基礎(chǔ)上去分析。

先分析數(shù)據(jù)級(jí)別之間有關(guān)系的表之間的業(yè)務(wù)關(guān)系:

usre和orders:

user—->orders : 一個(gè)用戶可以創(chuàng)建多個(gè)訂單,一對(duì)多

orders—>user : 一個(gè)訂單只由一個(gè)用戶創(chuàng)建,一對(duì)一

orders和orderdetail:

orders –> orderdetail:一個(gè)訂單可以包括多個(gè)訂單明細(xì),因?yàn)橐粋€(gè)訂單可以購買多個(gè)商品,每個(gè)商品的購買信息在orderdetail記錄,一對(duì)多關(guān)系

orderdetail–> orders:一個(gè)訂單明細(xì)只能包括在一個(gè)訂單中,一對(duì)一

orderdetail和itesm:

orderdetail—> itesms:一個(gè)訂單明細(xì)只對(duì)應(yīng)一個(gè)商品信息,一對(duì)一

items–> orderdetail:一個(gè)商品可以包括在多個(gè)訂單明細(xì) ,一對(duì)多

再分析數(shù)據(jù)庫級(jí)別沒有關(guān)系的表之間是否有業(yè)務(wù)關(guān)系:

orders和items:

orders和items之間可以通過orderdetail表建立關(guān)系。

user 和 items : 通過其他表構(gòu)成了多對(duì)多關(guān)系

一對(duì)一查詢

需求 : 查詢訂單信息,關(guān)聯(lián)查詢創(chuàng)建訂單的用戶信息

使用resultType方式查詢

sql語句使用考慮

確定查詢的主表:訂單表

確定查詢的關(guān)聯(lián)表:用戶表

關(guān)聯(lián)查詢使用內(nèi)鏈接,還是外鏈接?

由于orders表中有一個(gè)外鍵(user_id),通過外鍵關(guān)聯(lián)查詢用戶表只能查詢出一條記錄,可以使用內(nèi)鏈接。

?
1
2
3
4
5
6
7
8
9
SELECT
orders.*,
USER.username,
USER.sex,
USER.address
FROM
orders,
USER
WHERE orders.user_id = user.id

創(chuàng)建pojo(OrdersCustom.java)

將上邊sql查詢的結(jié)果映射到pojo中,pojo中必須包括所有查詢列名。

原始的Orders.java不能映射全部字段,需要新創(chuàng)建的pojo。

創(chuàng)建 一個(gè)pojo繼承包括查詢字段較多的po類。

MyBatis高級(jí)映射和查詢緩存

OrdersMapperCustom.xml

MyBatis高級(jí)映射和查詢緩存

OrdersMapperCustom.java

MyBatis高級(jí)映射和查詢緩存

編寫測(cè)試類

選擇OrdersMapperCustom.java文件右鍵–>選擇New–>Others–> Junit Test Case–>選擇要測(cè)試的函數(shù)

在OrdersMapperCustomTest.java中編寫如下代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class OrdersMapperCustomTest {
private SqlSessionFactory sqlSessionFactory;
// 此方法是在執(zhí)行testFindUserById之前執(zhí)行
@Before
public void setUp() throws Exception {
// 創(chuàng)建sqlSessionFactory
// mybatis配置文件
String resource = "SqlMapConfig.xml";
// 得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 創(chuàng)建會(huì)話工廠,傳入mybatis的配置文件信息
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindOrdersUser() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 創(chuàng)建代理對(duì)象
OrdersMapperCustom ordersMapperCustom = sqlSession
.getMapper(OrdersMapperCustom.class);
// 調(diào)用maper的方法
List<OrdersCustom> list = ordersMapperCustom.findOrdersUser();
System.out.println(list);
sqlSession.close();
}

使用resultMap方式查詢

sql語句 : 同resultType實(shí)現(xiàn)的sql

使用resultMap映射的思路

使用resultMap將查詢結(jié)果中的訂單信息映射到Orders對(duì)象中,在orders類中添加User屬性,將關(guān)聯(lián)查詢出來的用戶信息映射到orders對(duì)象中的user屬性中。

Orders類中添加user屬性

MyBatis高級(jí)映射和查詢緩存

OrdersMapperCustom.xml

定義resultMap

tyep : 表示將整個(gè)查詢的結(jié)果映射到某個(gè)類中 eg:cn.itcast.mybatis.po.Orders

id:表示數(shù)據(jù)庫表中查詢列的唯一標(biāo)識(shí),訂單信息的中的唯一標(biāo)識(shí),如果有多個(gè)列組成唯一標(biāo)識(shí),配置多個(gè)id

column:數(shù)據(jù)庫表中訂單信息的唯一標(biāo)識(shí)列

property:訂單信息的唯一標(biāo)識(shí)列所映射到Orders中哪個(gè)屬性

association:用于映射關(guān)聯(lián)查詢單個(gè)對(duì)象的信息

property:要將關(guān)聯(lián)查詢的用戶信息映射到Orders中哪個(gè)屬性

javaType:映射到user的哪個(gè)屬性

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!-- 訂單查詢關(guān)聯(lián)用戶的resultMap
將整個(gè)查詢的結(jié)果映射到cn.itcast.mybatis.po.Orders中
-->
<resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersUserResultMap">
<!-- 配置映射的訂單信息 -->
<!-- id:指定查詢列中的唯 一標(biāo)識(shí),訂單信息的中的唯 一標(biāo)識(shí),如果有多個(gè)列組成唯一標(biāo)識(shí),配置多個(gè)id
column:訂單信息的唯 一標(biāo)識(shí) 列
property:訂單信息的唯 一標(biāo)識(shí) 列所映射到Orders中哪個(gè)屬性
-->
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
<result column="note" property=note/>
<!-- 配置映射的關(guān)聯(lián)的用戶信息 -->
<!-- association:用于映射關(guān)聯(lián)查詢單個(gè)對(duì)象的信息
property:要將關(guān)聯(lián)查詢的用戶信息映射到Orders中哪個(gè)屬性
-->
<association property="user" javaType="cn.itcast.mybatis.po.User">
<!-- id:關(guān)聯(lián)查詢用戶的唯一標(biāo)識(shí)
column:指定唯 一標(biāo)識(shí)用戶信息的列
javaType:映射到user的哪個(gè)屬性
-->
<id column="user_id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
</association>
</resultMap>

statement定義

MyBatis高級(jí)映射和查詢緩存

OrdersMapperCustom.java

MyBatis高級(jí)映射和查詢緩存

測(cè)試代碼

?
1
2
3
4
5
6
7
8
9
10
11
@Test
public void testFindOrdersUserResultMap() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 創(chuàng)建代理對(duì)象
OrdersMapperCustom ordersMapperCustom = sqlSession
.getMapper(OrdersMapperCustom.class);
// 調(diào)用maper的方法
List<Orders> list = ordersMapperCustom.findOrdersUserResultMap();
System.out.println(list);
sqlSession.close();
}

resultType和resultMap實(shí)現(xiàn)一對(duì)一查詢小結(jié)

resultType:使用resultType實(shí)現(xiàn)較為簡單,如果pojo中沒有包括查詢出來的列名,需要增加列名對(duì)應(yīng)的屬性,即可完成映射。
如果沒有查詢結(jié)果的特殊要求建議使用resultType。

resultMap:需要單獨(dú)定義resultMap,實(shí)現(xiàn)有點(diǎn)麻煩,如果對(duì)查詢結(jié)果有特殊的要求,使用resultMap可以完成將關(guān)聯(lián)查詢映射pojo的屬性中。

resultMap可以實(shí)現(xiàn)延遲加載,resultType無法實(shí)現(xiàn)延遲加載。

一對(duì)多查詢

需求 : 查詢訂單及訂單明細(xì)的信息。

sql語句

確定主查詢表:訂單表

確定關(guān)聯(lián)查詢表:訂單明細(xì)表

在一對(duì)一查詢基礎(chǔ)上添加訂單明細(xì)表關(guān)聯(lián)即可。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
SELECT
orders.*,
USER.username,
USER.sex,
USER.address,
orderdetail.id orderdetail_id,
orderdetail.items_id,
orderdetail.items_num,
orderdetail.orders_id
FROM
orders,
USER,
orderdetail
WHERE orders.user_id = user.id AND orderdetail.orders_id=orders.id

分析 : 使用resultType將上邊的 查詢結(jié)果映射到pojo中,訂單信息的就是重復(fù)。

MyBatis高級(jí)映射和查詢緩存

要求:對(duì)orders映射不能出現(xiàn)重復(fù)記錄。

在orders.java類中添加List<orderDetail> orderDetails屬性。

最終會(huì)將訂單信息映射到orders中,訂單所對(duì)應(yīng)的訂單明細(xì)映射到orders中的orderDetails屬性中。

映射成的orders記錄數(shù)為兩條(orders信息不重復(fù))

每個(gè)orders中的orderDetails屬性存儲(chǔ)了該訂單所對(duì)應(yīng)的訂單明細(xì)。

MyBatis高級(jí)映射和查詢緩存

在Orders.java中添加list訂單明細(xì)屬性

MyBatis高級(jí)映射和查詢緩存

OrdersMapperCustom.xml

MyBatis高級(jí)映射和查詢緩存

resultMap定義

使用extends繼承,不用在中配置訂單信息和用戶信息的映射

collection:對(duì)關(guān)聯(lián)查詢到多條記錄映射到集合對(duì)象中

property:將關(guān)聯(lián)查詢到多條記錄映射到cn.itcast.mybatis.po.Orders哪個(gè)屬性

ofType:指定映射到list集合屬性中pojo的類型

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- 訂單及訂單明細(xì)的resultMap
使用extends繼承,不用在中配置訂單信息和用戶信息的映射
-->
<resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersAndOrderDetailResultMap" extends="OrdersUserResultMap">
<!-- 訂單信息 -->
<!-- 用戶信息 -->
<!-- 使用extends繼承,不用在中配置訂單信息和用戶信息的映射 -->
<!-- 訂單明細(xì)信息
一個(gè)訂單關(guān)聯(lián)查詢出了多條明細(xì),要使用collection進(jìn)行映射
collection:對(duì)關(guān)聯(lián)查詢到多條記錄映射到集合對(duì)象中
property:將關(guān)聯(lián)查詢到多條記錄映射到cn.itcast.mybatis.po.Orders哪個(gè)屬性
ofType:指定映射到list集合屬性中pojo的類型
-->
<collection property="orderdetails" ofType="cn.itcast.mybatis.po.Orderdetail">
<!-- id:訂單明細(xì)唯 一標(biāo)識(shí)
property:要將訂單明細(xì)的唯一標(biāo)識(shí)映射到cn.itcast.mybatis.po.Orderdetail的哪個(gè)屬性
-->
<id column="orderdetail_id" property="id"/>
<result column="items_id" property="itemsId"/>
<result column="items_num" property="itemsNum"/>
<result column="orders_id" property="ordersId"/>
</collection>
</resultMap>

OrdersMapperCustom.java

MyBatis高級(jí)映射和查詢緩存

測(cè)試代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void testFindOrdersAndOrderDetailResultMap() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 創(chuàng)建代理對(duì)象
OrdersMapperCustom ordersMapperCustom = sqlSession
.getMapper(OrdersMapperCustom.class);
// 調(diào)用maper的方法
List<Orders> list = ordersMapperCustom
.findOrdersAndOrderDetailResultMap();
System.out.println(list);
sqlSession.close();
}

小結(jié)

mybatis使用resultMap的collection對(duì)關(guān)聯(lián)查詢的多條記錄映射到一個(gè)list集合屬性中。

使用resultType實(shí)現(xiàn):

將訂單明細(xì)映射到orders中的orderdetails中,需要自己處理,使用雙重循環(huán)遍歷,去掉重復(fù)記錄,將訂單明細(xì)放在orderdetails中。

多對(duì)多查詢

需求 : 查詢用戶及用戶購買商品信息。

sql語句

查詢主表是:用戶表

關(guān)聯(lián)表:由于用戶和商品沒有直接關(guān)聯(lián),通過訂單和訂單明細(xì)進(jìn)行關(guān)聯(lián),所以關(guān)聯(lián)表:orders、orderdetail、items

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
SELECT
orders.*,
USER.username,
USER.sex,
USER.address,
orderdetail.id orderdetail_id,
orderdetail.items_id,
orderdetail.items_num,
orderdetail.orders_id,
items.name items_name,
items.detail items_detail,
items.price items_price
FROM
orders,
USER,
orderdetail,
items
WHERE orders.user_id = user.id AND orderdetail.orders_id=orders.id AND orderdetail.items_id = items.id

映射思路

將用戶信息映射到user中。

在user類中添加訂單列表屬性List<Orders> orderslist,將用戶創(chuàng)建的訂單映射到orderslist

在Orders中添加訂單明細(xì)列表屬性List<OrderDetail>orderdetials,將訂單的明細(xì)映射到orderdetials

在OrderDetail中添加Items屬性,將訂單明細(xì)所對(duì)應(yīng)的商品映射到Items

OrdersMapperCustom.xml

resultMap定義

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!-- 查詢用戶及購買的商品 -->
<resultMap type="cn.itcast.mybatis.po.User" id="UserAndItemsResultMap">
<!-- 用戶信息 -->
<id column="user_id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
<!-- 訂單信息 一個(gè)用戶對(duì)應(yīng)多個(gè)訂單,使用collection映射-->
<collection property="ordersList" ofType="cn.itcast.mybatis.po.Orders">
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
<result column="note" property="note"/>
<!-- 訂單明細(xì) 一個(gè)訂單包括 多個(gè)明細(xì)-->
<collection property="orderdetails" ofType="cn.itcast.mybatis.po.Orderdetail">
<id column="orderdetail_id" property="id"/>
<result column="items_id" property="itemsId"/>
<result column="items_num" property="itemsNum"/>
<result column="orders_id" property="ordersId"/>
<!-- 商品信息一個(gè)訂單明細(xì)對(duì)應(yīng)一個(gè)商品-->
<association property="items" javaType="cn.itcast.mybatis.po.Items">
<id column="items_id" property="id"/>
<result column="items_name" property="name"/>
<result column="items_detail" property="detail"/>
<result column="items_price" property="price"/>
</association>
</collection>
</collection>
</resultMap>

OrdersMapperCustom.java

測(cè)試代碼:

?
1
2
3
4
5
6
7
8
9
10
11
@Test
public void testFindUserAndItemsResultMap() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 創(chuàng)建代理對(duì)象
OrdersMapperCustom ordersMapperCustom = sqlSession
.getMapper(OrdersMapperCustom.class);
// 調(diào)用maper的方法
List<User> list = ordersMapperCustom.findUserAndItemsResultMap();
System.out.println(list);
sqlSession.close();
}

多對(duì)多查詢總結(jié)

將查詢用戶購買的商品信息明細(xì)清單,(用戶名、用戶地址、購買商品名稱、購買商品時(shí)間、購買商品數(shù)量)

針對(duì)上邊的需求就使用resultType將查詢到的記錄映射到一個(gè)擴(kuò)展的pojo中,很簡單實(shí)現(xiàn)明細(xì)清單的功能。

一對(duì)多是多對(duì)多的特例,如下需求:

查詢用戶購買的商品信息,用戶和商品的關(guān)系是多對(duì)多關(guān)系。

需求1:

查詢字段:用戶賬號(hào)、用戶名稱、用戶性別、商品名稱、商品價(jià)格(最常見)

企業(yè)開發(fā)中常見明細(xì)列表,用戶購買商品明細(xì)列表,

使用resultType將上邊查詢列映射到pojo輸出。

需求2:

查詢字段:用戶賬號(hào)、用戶名稱、購買商品數(shù)量、商品明細(xì)(鼠標(biāo)移上顯示明細(xì))

使用resultMap將用戶購買的商品明細(xì)列表映射到user對(duì)象中。

總結(jié):

使用resultMap是針對(duì)那些對(duì)查詢結(jié)果映射有特殊要求的功能,比如特殊要求映射成list中包括多個(gè)list。

resultType與resultMap的總結(jié)

resultType:

作用:

將查詢結(jié)果按照sql列名pojo屬性名一致性映射到pojo中。

場(chǎng)合:

常見一些明細(xì)記錄的展示,比如用戶購買商品明細(xì),將關(guān)聯(lián)查詢信息全部展示在頁面時(shí),此時(shí)可直接使用resultType將每一條記錄映

射到pojo中,在前端頁面遍歷list(list中是pojo)即可。

resultMap:

使用association和collection完成一對(duì)一和一對(duì)多高級(jí)映射(對(duì)結(jié)果有特殊的映射要求)。

association:

作用:

將關(guān)聯(lián)查詢信息映射到一個(gè)pojo對(duì)象中。

場(chǎng)合:

為了方便查詢關(guān)聯(lián)信息可以使用association將關(guān)聯(lián)訂單信息映射為用戶對(duì)象的pojo屬性中,比如:查詢訂單及關(guān)聯(lián)用戶信息。

使用resultType無法將查詢結(jié)果映射到pojo對(duì)象的pojo屬性中,根據(jù)對(duì)結(jié)果集查詢遍歷的需要選擇使用resultType還是resultMap。

collection:

作用:

將關(guān)聯(lián)查詢信息映射到一個(gè)list集合中。

場(chǎng)合:
為了方便查詢遍歷關(guān)聯(lián)信息可以使用collection將關(guān)聯(lián)信息映射到list集合中,比如:查詢用戶權(quán)限范圍模塊及模塊下的菜單,可使用collection將模塊映射到模塊list中,將菜單列表映射到模塊對(duì)象的菜單list屬性中,這樣的作的目的也是方便對(duì)查詢結(jié)果集進(jìn)行遍歷查詢。

如果使用resultType無法將查詢結(jié)果映射到list集合中。

延遲加載

resultMap可以實(shí)現(xiàn)高級(jí)映射(使用association、collection實(shí)現(xiàn)一對(duì)一及一對(duì)多映射),association、collection具備延遲加載功能。

需求:

如果查詢訂單并且關(guān)聯(lián)查詢用戶信息。如果先查詢訂單信息即可滿足要求,當(dāng)我們需要查詢用戶信息時(shí)再查詢用戶信息。把對(duì)用戶信息的按需去查詢就是延遲加載。
延遲加載:先從單表查詢、需要時(shí)再從關(guān)聯(lián)表去關(guān)聯(lián)查詢,大大提高數(shù)據(jù)庫性能,因?yàn)椴樵儐伪硪汝P(guān)聯(lián)查詢多張表速度要快。

使用association實(shí)現(xiàn)延遲加載

需求 : 查詢訂單并且關(guān)聯(lián)查詢用戶信息

OrdresMapperCustom.xml

需要定義兩個(gè)mapper的方法對(duì)應(yīng)的statement。

1、只查詢訂單信息

?
1
SELECT * FROM orders

在查詢訂單的statement中使用association去延遲加載(執(zhí)行)下邊的satatement(關(guān)聯(lián)查詢用戶信息)

MyBatis高級(jí)映射和查詢緩存

2、關(guān)聯(lián)查詢用戶信息

通過上邊查詢到的訂單信息中user_id去關(guān)聯(lián)查詢用戶信息

MyBatis高級(jí)映射和查詢緩存

使用UserMapper.xml中的findUserById

上邊先去執(zhí)行findOrdersUserLazyLoading,當(dāng)需要去查詢用戶的時(shí)候再去執(zhí)行findUserById,通過resultMap的定義將延遲加載執(zhí)行配置起來。

延遲加載resultMap

使用association中的select指定延遲加載去執(zhí)行的statement的id。

?
1
2
3
4
5
6
7
8
9
<!-- 延遲加載的resultMap -->
<resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersUserLazyLoadingResultMap">
<!--對(duì)訂單信息進(jìn)行映射配置 -->
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
<result column="note" property="note"/>
<!-- 實(shí)現(xiàn)對(duì)用戶信息進(jìn)行延遲加載

select:指定延遲加載需要執(zhí)行的statement的id(是根據(jù)user_id查詢用戶信息的statement)
要使用userMapper.xml中findUserById完成根據(jù)用戶id(user_id)用戶信息的查詢,如果findUserById不在本mapper中需要前邊加namespace

column:訂單信息中關(guān)聯(lián)用戶信息查詢的列,是user_id

關(guān)聯(lián)查詢的sql理解為:

?
1
2
3
4
5
6
7
8
9
10
SELECT orders.*,
(SELECT username FROM USER WHERE orders.user_id = user.id)username,
(SELECT sex FROM USER WHERE orders.user_id = user.id)sex
FROM orders
-->
<association property="user" javaType="cn.itcast.mybatis.po.User"
select="cn.itcast.mybatis.mapper.UserMapper.findUserById" column="user_id">
<!-- 實(shí)現(xiàn)對(duì)用戶信息進(jìn)行延遲加載 -->
</association>
</resultMap>

OrderesMapperCustom.java

MyBatis高級(jí)映射和查詢緩存

測(cè)試思路:

1、執(zhí)行上邊mapper方法(findOrdersUserLazyLoading),內(nèi)部去調(diào)用cn.itcast.mybatis.mapper.OrdersMapperCustom中的findOrdersUserLazyLoading只查詢orders信息(單表)。

2、在程序中去遍歷上一步驟查詢出的List<Orders>,當(dāng)我們調(diào)用Orders中的getUser方法時(shí),開始進(jìn)行延遲加載。

3、延遲加載,去調(diào)用UserMapper.xml中findUserbyId這個(gè)方法獲取用戶信息。

延遲加載配置

mybatis默認(rèn)沒有開啟延遲加載,需要在SqlMapConfig.xml中setting配置。

在mybatis核心配置文件中配置:

設(shè)置項(xiàng) 描述 允許值 默認(rèn)值
lazyLoadingEnabled 全局性設(shè)置懶加載。如果設(shè)為‘false',則所有相關(guān)聯(lián)的都會(huì)被初始化加載。 true or false false
aggressiveLazyLoading 當(dāng)設(shè)置為‘true'的時(shí)候,懶加載的對(duì)象可能被任何懶屬性全部加載。否則,每個(gè)屬性都按需加載。 true or false true

在SqlMapConfig.xml中配置:

MyBatis高級(jí)映射和查詢緩存

測(cè)試代碼

MyBatis高級(jí)映射和查詢緩存

延遲加載思考

不使用mybatis提供的association及collection中的延遲加載功能,如何實(shí)現(xiàn)延遲加載?

實(shí)現(xiàn)方法如下:

定義兩個(gè)mapper方法:

1、查詢訂單列表

2、根據(jù)用戶id查詢用戶信息

實(shí)現(xiàn)思路:

先去查詢第一個(gè)mapper方法,獲取訂單信息列表

在程序中(service),按需去調(diào)用第二個(gè)mapper方法去查詢用戶信息。

總之:使用延遲加載方法,先去查詢簡單的sql(最好單表,也可以關(guān)聯(lián)查詢),再去按需要加載關(guān)聯(lián)查詢的其它信息。

查詢緩存

mybatis提供查詢緩存,用于減輕數(shù)據(jù)壓力,提高數(shù)據(jù)庫性能。

mybaits提供一級(jí)緩存,和二級(jí)緩存。

一級(jí)緩存是SqlSession級(jí)別的緩存。在操作數(shù)據(jù)庫時(shí)需要構(gòu)造 sqlSession對(duì)象,在對(duì)象中有一個(gè)數(shù)據(jù)結(jié)構(gòu)(HashMap)用于存儲(chǔ)緩存數(shù)據(jù)。不同的sqlSession之間的緩存數(shù)據(jù)區(qū)域(HashMap)是互相不影響的。

二級(jí)緩存是mapper級(jí)別的緩存,多個(gè)SqlSession去操作同一個(gè)Mapper的sql語句,多個(gè)SqlSession可以共用二級(jí)緩存,二級(jí)緩存是跨SqlSession的。

為什么要用緩存?

如果緩存中有數(shù)據(jù)就不用從數(shù)據(jù)庫中獲取,大大提高系統(tǒng)性能。

一級(jí)緩存

一級(jí)緩存工作原理

第一次發(fā)起查詢用戶id為1的用戶信息,先去找緩存中是否有id為1的用戶信息,如果沒有,從數(shù)據(jù)庫查詢用戶信息。

得到用戶信息,將用戶信息存儲(chǔ)到一級(jí)緩存中。

如果sqlSession去執(zhí)行commit操作(執(zhí)行插入、更新、刪除),清空SqlSession中的一級(jí)緩存,這樣做的目的為了讓緩存中存儲(chǔ)的是最新的信息,避免臟讀。

第二次發(fā)起查詢用戶id為1的用戶信息,先去找緩存中是否有id為1的用戶信息,緩存中有,直接從緩存中獲取用戶信息。

一級(jí)緩存測(cè)試

mybatis默認(rèn)支持一級(jí)緩存,不需要在配置文件去配置。

按照上邊一級(jí)緩存原理步驟去測(cè)試。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//OrdersMapperCusntomTest.java
@Test
public void testCache1() throws Exception{
SqlSession sqlSession = sqlSessionFactory.openSession();//創(chuàng)建代理對(duì)象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//下邊查詢使用一個(gè)SqlSession
//第一次發(fā)起請(qǐng)求,查詢id為1的用戶
User user1 = userMapper.findUserById(1);
System.out.println(user1);
// 如果sqlSession去執(zhí)行commit操作(執(zhí)行插入、更新、刪除),清空SqlSession中的一級(jí)緩存,這樣做的目的為了讓緩存中存儲(chǔ)的是最新的信息,避免臟讀。
//更新user1的信息
user1.setUsername("測(cè)試用戶22");
userMapper.updateUser(user1);
//執(zhí)行commit操作去清空緩存
sqlSession.commit();
//第二次發(fā)起請(qǐng)求,查詢id為1的用戶
User user2 = userMapper.findUserById(1);
System.out.println(user2);
sqlSession.close();
}

一級(jí)緩存應(yīng)用

正式開發(fā),是將mybatis和spring進(jìn)行整合開發(fā),事務(wù)控制在service中。

一個(gè)service方法中包括 很多mapper方法調(diào)用。

?
1
2
3
4
5
6
service{
//開始執(zhí)行時(shí),開啟事務(wù),創(chuàng)建SqlSession對(duì)象
//第一次調(diào)用mapper的方法findUserById(1)
//第二次調(diào)用mapper的方法findUserById(1),從一級(jí)緩存中取數(shù)據(jù)
//方法結(jié)束,sqlSession關(guān)閉
}

如果是執(zhí)行兩次service調(diào)用查詢相同 的用戶信息,不走一級(jí)緩存,因?yàn)閟ession方法結(jié)束,sqlSession就關(guān)閉,一級(jí)緩存就清空。

二級(jí)緩存

原理

首先開啟mybatis的二級(jí)緩存。

sqlSession1去查詢用戶id為1的用戶信息,查詢到用戶信息會(huì)將查詢數(shù)據(jù)存儲(chǔ)到二級(jí)緩存中。

如果SqlSession3去執(zhí)行相同 mapper下sql,執(zhí)行commit提交,清空該 mapper下的二級(jí)緩存區(qū)域的數(shù)據(jù)。

sqlSession2去查詢用戶id為1的用戶信息,去緩存中找是否存在數(shù)據(jù),如果存在直接從緩存中取出數(shù)據(jù)。

二級(jí)緩存與一級(jí)緩存區(qū)別,二級(jí)緩存的范圍更大,多個(gè)sqlSession可以共享一個(gè)UserMapper的二級(jí)緩存區(qū)域。

UserMapper有一個(gè)二級(jí)緩存區(qū)域(按namespace分) ,其它mapper也有自己的二級(jí)緩存區(qū)域(按namespace分)。

每一個(gè)namespace的mapper都有一個(gè)二緩存區(qū)域,兩個(gè)mapper的namespace如果相同,這兩個(gè)mapper執(zhí)行sql查詢到數(shù)據(jù)將存在相同的二級(jí)緩存區(qū)域中。

開啟二級(jí)緩存

mybaits的二級(jí)緩存是mapper范圍級(jí)別,除了在SqlMapConfig.xml設(shè)置二級(jí)緩存的總開關(guān),還要在具體的mapper.xml中開啟二級(jí)緩存。

在核心配置文件SqlMapConfig.xml中加入

?
1
<setting name="cacheEnabled" value="true"/>

描述 允許值 默認(rèn)值

cacheEnabled 對(duì)在此配置文件下的所有cache 進(jìn)行全局性開/關(guān)設(shè)置。 true or false

在UserMapper.xml中開啟二級(jí)緩存,UserMapper.xml下的sql執(zhí)行完成會(huì)存儲(chǔ)到它的緩存區(qū)域(HashMap)。

調(diào)用pojo類實(shí)現(xiàn)序列化接口

為了將緩存數(shù)據(jù)取出執(zhí)行反序列化操作,因?yàn)槎?jí)緩存數(shù)據(jù)存儲(chǔ)介質(zhì)多種多樣,不一樣在內(nèi)存。

二級(jí)緩存測(cè)試

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Test
public void testCache2() throws Exception {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
SqlSession sqlSession3 = sqlSessionFactory.openSession();
// 創(chuàng)建代理對(duì)象
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
// 第一次發(fā)起請(qǐng)求,查詢id為1的用戶
User user1 = userMapper1.findUserById(1);
System.out.println(user1);
//這里執(zhí)行關(guān)閉操作,將sqlsession中的數(shù)據(jù)寫到二級(jí)緩存區(qū)域
sqlSession1.close();
//使用sqlSession3執(zhí)行commit()操作
UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);
User user = userMapper3.findUserById(1);
user.setUsername("張明明");
userMapper3.updateUser(user);
//執(zhí)行提交,清空UserMapper下邊的二級(jí)緩存
sqlSession3.commit();
sqlSession3.close();
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
// 第二次發(fā)起請(qǐng)求,查詢id為1的用戶
User user2 = userMapper2.findUserById(1);
System.out.println(user2);
sqlSession2.close();
}

useCache配置

在statement中設(shè)置useCache=false可以禁用當(dāng)前select語句的二級(jí)緩存,即每次查詢都會(huì)發(fā)出sql去查詢,默認(rèn)情況是true,即該sql使用二級(jí)緩存。

?
1
<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">

總結(jié):針對(duì)每次查詢都需要最新的數(shù)據(jù)sql,要設(shè)置成useCache=false,禁用二級(jí)緩存。

刷新緩存

就是清空緩存

在mapper的同一個(gè)namespace中,如果有其它insert、update、delete操作數(shù)據(jù)后需要刷新緩存,如果不執(zhí)行刷新緩存會(huì)出現(xiàn)臟讀。

設(shè)置statement配置中的flushCache=”true” 屬性,默認(rèn)情況下為true即刷新緩存,如果改成false則不會(huì)刷新。使用緩存時(shí)如果手動(dòng)修改數(shù)據(jù)庫表中的查詢數(shù)據(jù)會(huì)出現(xiàn)臟讀。

?
1
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">

總結(jié):一般下執(zhí)行完commit操作都需要刷新緩存,flushCache=true表示刷新緩存,這樣可以避免數(shù)據(jù)庫臟讀。

mybatis整合ehcache

ehcache是一個(gè)分布式緩存框架。

分布緩存

我們系統(tǒng)為了提高系統(tǒng)并發(fā),性能、一般對(duì)系統(tǒng)進(jìn)行分布式部署(集群部署方式)
不使用分布緩存,緩存的數(shù)據(jù)在各各服務(wù)單獨(dú)存儲(chǔ),不方便系統(tǒng) 開發(fā)。所以要使用分布式緩存對(duì)緩存數(shù)據(jù)進(jìn)行集中管理。
mybatis無法實(shí)現(xiàn)分布式緩存,需要和其它分布式緩存框架進(jìn)行整合。

MyBatis高級(jí)映射和查詢緩存

整合ehcache方法(掌握)

mybatis提供了一個(gè)cache接口,如果要實(shí)現(xiàn)自己的緩存邏輯,實(shí)現(xiàn)cache接口開發(fā)即可。
mybatis和ehcache整合,mybatis和ehcache整合包中提供了一個(gè)cache接口的實(shí)現(xiàn)類。

mybatis默認(rèn)實(shí)現(xiàn)cache類是:

MyBatis高級(jí)映射和查詢緩存

加入ehcache包

整合ehcache

配置mapper中cache中的type為ehcache對(duì)cache接口的實(shí)現(xiàn)類型。

MyBatis高級(jí)映射和查詢緩存

加入ehcache的配置文件(在classpath下配置ehcache.xml)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<diskStore path="F:\develop\ehcache" />
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>

屬性說明:

diskStore:指定數(shù)據(jù)在磁盤中的存儲(chǔ)位置。
defaultCache:當(dāng)借助CacheManager.add(“demoCache”)創(chuàng)建Cache時(shí),EhCache便會(huì)采用<defalutCache/>指定的的管理策略

以下屬性是必須的:

maxElementsInMemory - 在內(nèi)存中緩存的element的最大數(shù)目
maxElementsOnDisk - 在磁盤上緩存的element的最大數(shù)目,若是0表示無窮大
eternal - 設(shè)定緩存的elements是否永遠(yuǎn)不過期。如果為true,則緩存的數(shù)據(jù)始終有效,如果為false那么還要根據(jù)timeToIdleSeconds,timeToLiveSeconds判斷
overflowToDisk - 設(shè)定當(dāng)內(nèi)存緩存溢出的時(shí)候是否將過期的element緩存到磁盤上

以下屬性是可選的:

timeToIdleSeconds - 當(dāng)緩存在EhCache中的數(shù)據(jù)前后兩次訪問的時(shí)間超過timeToIdleSeconds的屬性取值時(shí),這些數(shù)據(jù)便會(huì)刪除,默認(rèn)值是0,也就是可閑置時(shí)間無窮大
timeToLiveSeconds - 緩存element的有效生命期,默認(rèn)是0.,也就是element存活時(shí)間無窮大
diskSpoolBufferSizeMB 這個(gè)參數(shù)設(shè)置DiskStore(磁盤緩存)的緩存區(qū)大小.默認(rèn)是30MB.每個(gè)Cache都應(yīng)該有自己的一個(gè)緩沖區(qū).
diskPersistent - 在VM重啟的時(shí)候是否啟用磁盤保存EhCache中的數(shù)據(jù),默認(rèn)是false。
diskExpiryThreadIntervalSeconds - 磁盤緩存的清理線程運(yùn)行間隔,默認(rèn)是120秒。每個(gè)120s,相應(yīng)的線程會(huì)進(jìn)行一次EhCache中數(shù)據(jù)的清理工作
memoryStoreEvictionPolicy - 當(dāng)內(nèi)存緩存達(dá)到最大,有新的element加入的時(shí)候, 移除緩存中element的策略。默認(rèn)是LRU(最近最少使用),可選的有LFU(最不常使用)和FIFO(先進(jìn)先出)

二級(jí)應(yīng)用場(chǎng)景

對(duì)于訪問多的查詢請(qǐng)求且用戶對(duì)查詢結(jié)果實(shí)時(shí)性要求不高,此時(shí)可采用mybatis二級(jí)緩存技術(shù)降低數(shù)據(jù)庫訪問量,提高訪問速度,業(yè)務(wù)場(chǎng)景比如:耗時(shí)較高的統(tǒng)計(jì)分析sql、電話賬單查詢sql等。

實(shí)現(xiàn)方法如下:通過設(shè)置刷新間隔時(shí)間,由mybatis每隔一段時(shí)間自動(dòng)清空緩存,根據(jù)數(shù)據(jù)變化頻率設(shè)置緩存刷新間隔flushInterval,比如設(shè)置為30分鐘、60分鐘、24小時(shí)等,根據(jù)需求而定。

二級(jí)緩存局限性

mybatis二級(jí)緩存對(duì)細(xì)粒度的數(shù)據(jù)級(jí)別的緩存實(shí)現(xiàn)不好,比如如下需求:對(duì)商品信息進(jìn)行緩存,由于商品信息查詢?cè)L問量大,但是要求用戶每次都能查詢最新的商品信息,此時(shí)如果使用mybatis的二級(jí)緩存就無法實(shí)現(xiàn)當(dāng)一個(gè)商品變化時(shí)只刷新該商品的緩存信息而不刷新其它商品的信息,因?yàn)閙ybaits的二級(jí)緩存區(qū)域以mapper為單位劃分,當(dāng)一個(gè)商品信息變化會(huì)將所有商品信息的緩存數(shù)據(jù)全部清空。解決此類問題需要在業(yè)務(wù)層根據(jù)需求對(duì)數(shù)據(jù)有針對(duì)性緩存。

原文鏈接:http://blog.csdn.net/lutianfeiml/article/details/51781318

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 糖心视频在线观看 | 美女厕所尿尿擦逼 | 小草观看免费高清视频 | 免费在线观看a | 日不卡| ysav67| 超兴奋朋友的中文字幕下 | 全肉np巨肉一女np高h双龙 | 国产精品二区高清在线 | a级黄色网 | 国产精品国产色综合色 | xxx86日本人 xxnx日本免费护士 | 俄罗斯极品h在线 | 国产成人h视频在线播放网站 | 视频高清在线观看 | tube62hdxxxx日本 | 99久热只有精品视频免费观看17 | 狠狠做五月深爱婷婷天天综合 | 日女人免费视频 | 男人机机桶女人 | 亚洲精品丝袜在线一区波多野结衣 | 手机在线观看伦理片 | 亚洲欧美综合在线观看 | 国产玖玖在线观看 | 高中生放荡日记高h娜娜 | 网友自拍咪咪爱 | 欧美三级不卡在线观线看高清 | 国产一区二区三区在线观看视频 | 97精品国产自在现线免费 | 午夜无码片在线观看影院 | 色老大在线 | 喜爱夜蒲2三级做爰 | 亚洲国产精品无码中文字满 | 99久久99热久久精品免 | 好男人资源大全免费观看 | 精品久久久久久久国产潘金莲 | 国产免费资源高清小视频在线观看 | 免费看黄色片的网站 | 91午夜视频 | 69短视频| 欧美午夜寂寞影院安卓列表 |