文檔版本 | 開發(fā)工具 | 測(cè)試平臺(tái) | 工程名字 | 日期 | 作者 | 備注 |
---|---|---|---|---|---|---|
V1.0 | 2016.06.28 | lutianfei | none |
mybatis框架履行進(jìn)程:
mapper代理開發(fā)方法(建議使用)
本文內(nèi)容:
商品表: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:
orders和orderdetail:
orderdetail和itesm:
再分析數(shù)據(jù)庫級(jí)別沒有關(guān)系的表之間是不是有業(yè)務(wù)關(guān)系:
SELECT
orders.*,
USER.username,
USER.sex,
USER.address
FROM
orders,
USER
WHERE orders.user_id = user.id
OrdersMapperCustom.java
編寫測(cè)試類
public class OrdersMapperCustomTest {
private SqlSessionFactory sqlSessionFactory;
// 此方法是在履行testFindUserById之前履行
@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();
}
sql語句 : 同resultType實(shí)現(xiàn)的sql
使用resultMap映照的思路
Orders類中添加user屬性
OrdersMapperCustom.xml
<!-- 定單查詢關(guān)聯(lián)用戶的resultMap
將全部查詢的結(jié)果映照到cn.itcast.mybatis.po.Orders中
-->
<resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersUserResultMap">
<!-- 配置映照的定單信息 -->
<!-- id:指定查詢列中的唯 1標(biāo)識(shí),定單信息的中的唯 1標(biāo)識(shí),如果有多個(gè)列組成唯1標(biāo)識(shí),配置多個(gè)id
column:定單信息的唯 1標(biāo)識(shí) 列
property:定單信息的唯 1標(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)查詢用戶的唯1標(biāo)識(shí)
column:指定唯 1標(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>
OrdersMapperCustom.java
測(cè)試代碼
@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();
}
如果沒有查詢結(jié)果的特殊要求建議使用resultType。
resultMap:需要單獨(dú)定義resultMap,實(shí)現(xiàn)有點(diǎn)麻煩,如果對(duì)查詢結(jié)果有特殊的要求,使用resultMap可以完成將關(guān)聯(lián)查詢映照pojo的屬性中。
需求 : 查詢定單及定單明細(xì)的信息。
sql語句
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ù)。
要求:對(duì)orders映照不能出現(xiàn)重復(fù)記錄。
List<orderDetail>
orderDetails屬性。在Orders.java中添加list定單明細(xì)屬性
OrdersMapperCustom.xml
<!-- 定單及定單明細(xì)的resultMap
使用extends繼承,不用在中配置定單信息和用戶信息的映照
-->
<resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersAndOrderDetailResultMap" extends="OrdersUserResultMap">
<!-- 定單信息 -->
<!-- 用戶信息 -->
<!-- 使用extends繼承,不用在中配置定單信息和用戶信息的映照 -->
<!-- 定單明細(xì)信息
1個(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ì)唯 1標(biāo)識(shí)
property:要將定單明細(xì)的唯1標(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
測(cè)試代碼:
@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();
}
需求 : 查詢用戶及用戶購買商品信息。
sql語句
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
映照思路
List<Orders>
orderslist,將用戶創(chuàng)建的定單映照到orderslistList<OrderDetail>
orderdetials,將定單的明細(xì)映照到orderdetialsOrdersMapperCustom.xml
<!-- 查詢用戶及購買的商品 -->
<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"/>
<!-- 定單信息 1個(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ì) 1個(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"/>
<!-- 商品信息1個(gè)定單明細(xì)對(duì)應(yīng)1個(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è)試代碼:
@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();
}
1對(duì)多是多對(duì)多的特例,以下需求:
總結(jié):
場(chǎng)合:
resultMap:
association:
場(chǎng)合:
collection:
resultMap可以實(shí)現(xiàn)高級(jí)映照(使用association、collection實(shí)現(xiàn)1對(duì)1及1對(duì)多映照),association、collection具有延遲加載功能。
需求:
延遲加載:先從單表查詢、需要時(shí)再從關(guān)聯(lián)表去關(guān)聯(lián)查詢,大大提高數(shù)據(jù)庫性能,由于查詢單表要比關(guān)聯(lián)查詢多張表速度要快。
需求 : 查詢定單并且關(guān)聯(lián)查詢用戶信息
OrdresMapperCustom.xml
需要定義兩個(gè)mapper的方法對(duì)應(yīng)的statement。
1、只查詢定單信息
SELECT * FROM orders
在查詢定單的statement中使用association去延遲加載(履行)下邊的satatement(關(guān)聯(lián)查詢用戶信息)
2、關(guān)聯(lián)查詢用戶信息
上邊先去履行findOrdersUserLazyLoading,當(dāng)需要去查詢用戶的時(shí)候再去履行findUserById,通過resultMap的定義將延遲加載履行配置起來。
延遲加載resultMap
<!-- 延遲加載的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:指定延遲加載需要履行的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理解為:
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
測(cè)試思路:
List<Orders>
,當(dāng)我們調(diào)用Orders中的getUser方法時(shí),開始進(jìn)行延遲加載。mybatis默許沒有開啟延遲加載,需要在SqlMapConfig.xml中setting
配置。
在mybatis核心配置文件中配置:
設(shè)置項(xiàng) | 描寫 | 允許值 | 默許值 |
---|---|---|---|
lazyLoadingEnabled | 全局性設(shè)置懶加載。如果設(shè)為‘false’,則所有相干聯(lián)的都會(huì)被初始化加載。 | true or false | false |
aggressiveLazyLoading | 當(dāng)設(shè)置為‘true’的時(shí)候,懶加載的對(duì)象可能被任何懶屬性全部加載。否則,每一個(gè)屬性都按需加載。 | true or false | true |
在SqlMapConfig.xml中配置:
測(cè)試代碼
延遲加載思考
實(shí)現(xiàn)方法以下:
總之:使用延遲加載方法,先去查詢簡(jiǎn)單的sql(最好單表,也能夠關(guān)聯(lián)查詢),再去按需要加載關(guān)聯(lián)查詢的其它信息。
1級(jí)緩存是SqlSession級(jí)別的緩存。在操作數(shù)據(jù)庫時(shí)需要構(gòu)造 sqlSession對(duì)象,在對(duì)象中有1個(gè)數(shù)據(jù)結(jié)構(gòu)(HashMap)用于存儲(chǔ)緩存數(shù)據(jù)。不同的sqlSession之間的緩存數(shù)據(jù)區(qū)域(HashMap)是相互不影響的。
2級(jí)緩存是mapper級(jí)別的緩存,多個(gè)SqlSession去操作同1個(gè)Mapper的sql語句,多個(gè)SqlSession可以共用2級(jí)緩存,2級(jí)緩存是跨SqlSession的。
為何要用緩存?
1級(jí)緩存工作原理
第1次發(fā)起查詢用戶id為1的用戶信息,先去找緩存中是不是有id為1的用戶信息,如果沒有,從數(shù)據(jù)庫查詢用戶信息。
//OrdersMapperCusntomTest.java
@Test
public void testCache1() throws Exception{
SqlSession sqlSession = sqlSessionFactory.openSession();//創(chuàng)建代理對(duì)象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//下邊查詢使用1個(gè)SqlSession
//第1次發(fā)起要求,查詢id為1的用戶
User user1 = userMapper.findUserById(1);
System.out.println(user1);
// 如果sqlSession去履行commit操作(履行插入、更新、刪除),清空SqlSession中的1級(jí)緩存,這樣做的目的為了讓緩存中存儲(chǔ)的是最新的信息,避免臟讀。
//更新user1的信息
user1.setUsername("測(cè)試用戶22");
userMapper.updateUser(user1);
//履行commit操作去清空緩存
sqlSession.commit();
//第2次發(fā)起要求,查詢id為1的用戶
User user2 = userMapper.findUserById(1);
System.out.println(user2);
sqlSession.close();
}
service{
//開始履行時(shí),開啟事務(wù),創(chuàng)建SqlSession對(duì)象
//第1次調(diào)用mapper的方法findUserById(1)
//第2次調(diào)用mapper的方法findUserById(1),從1級(jí)緩存中取數(shù)據(jù)
//方法結(jié)束,sqlSession關(guān)閉
}
首先開啟mybatis的2級(jí)緩存。
sqlSession1去查詢用戶id為1的用戶信息,查詢到用戶信息會(huì)將查詢數(shù)據(jù)存儲(chǔ)到2級(jí)緩存中。
如果SqlSession3去履行相同 mapper下sql,履行commit提交,清空該 mapper下的2級(jí)緩存區(qū)域的數(shù)據(jù)。
sqlSession2去查詢用戶id為1的用戶信息,去緩存中找是不是存在數(shù)據(jù),如果存在直接從緩存中取出數(shù)據(jù)。
2級(jí)緩存與1級(jí)緩存區(qū)分,2級(jí)緩存的范圍更大,多個(gè)sqlSession可以同享1個(gè)UserMapper的2級(jí)緩存區(qū)域。
<setting name="cacheEnabled" value="true"/>
描寫 | 允許值 | 默許值 |
---|---|---|
cacheEnabled | 對(duì)在此配置文件下的所有cache 進(jìn)行全局性開/關(guān)設(shè)置。 | true or false |
調(diào)用pojo類實(shí)現(xiàn)序列化接口
2級(jí)緩存測(cè)試
@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);
// 第1次發(fā)起要求,查詢id為1的用戶
User user1 = userMapper1.findUserById(1);
System.out.println(user1);
//這里履行關(guān)閉操作,將sqlsession中的數(shù)據(jù)寫到2級(jí)緩存區(qū)域
sqlSession1.close();
//使用sqlSession3履行commit()操作
UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);
User user = userMapper3.findUserById(1);
user.setUsername("張明明");
userMapper3.updateUser(user);
//履行提交,清空UserMapper下邊的2級(jí)緩存
sqlSession3.commit();
sqlSession3.close();
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
// 第2次發(fā)起要求,查詢id為1的用戶
User user2 = userMapper2.findUserById(1);
System.out.println(user2);
sqlSession2.close();
}
<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">
ehcache是1個(gè)散布式緩存框架。
散布緩存
mybatis和ehcache整合,mybatis和ehcache整合包中提供了1個(gè)cache接口的實(shí)現(xiàn)類。
mybatis默許實(shí)現(xiàn)cache類是:
加入ehcache包
整合ehcache
加入ehcache的配置文件(在classpath下配置ehcache.xml)
<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>
<defalutCache/>
指定的的管理策略