1.Mybatis 延遲加載策略
問(wèn)題:在一對(duì)多中航缀,當(dāng)我們有一個(gè)用戶序调,該用戶有100個(gè)賬戶芳誓,
①在查詢用戶的時(shí)候余舶,要不要把關(guān)聯(lián)的賬戶查詢出來(lái)?
②在查詢賬戶的時(shí)候锹淌,要不要把關(guān)聯(lián)的用戶信息查詢出來(lái)匿值?
解決方案是:
①在查詢用戶的時(shí)候,用戶下的賬戶信息應(yīng)該是什么時(shí)候使用赂摆,什么時(shí)候查詢挟憔。(延遲加載)
②在查詢賬戶的時(shí)候,賬戶下的所屬用戶信息應(yīng)該是隨賬戶一起查詢出來(lái)烟号。(立即加載)
1.1什么為延遲加載:
延遲加載:就是在需要用到數(shù)據(jù)時(shí)才進(jìn)行加載绊谭,不需要用到數(shù)據(jù)時(shí)就不加載數(shù)據(jù)。按需加載汪拥,延遲加載也稱懶加載.
好處:先從單表查詢达传,需要時(shí)再?gòu)年P(guān)聯(lián)表去關(guān)聯(lián)查詢,大大提高數(shù)據(jù)庫(kù)性能迫筑,因?yàn)椴樵儐伪硪汝P(guān)聯(lián)查詢多張表速度要快宪赶。
缺點(diǎn):因?yàn)橹挥挟?dāng)需要用到數(shù)據(jù)時(shí),才會(huì)進(jìn)行數(shù)據(jù)庫(kù)查詢脯燃,這樣在大批量數(shù)據(jù)查詢時(shí)搂妻,因?yàn)椴樵児ぷ饕惨?/p>
時(shí)間,所以可能造成用戶等待時(shí)間變長(zhǎng)辕棚,造成用戶體驗(yàn)下降欲主。
*注意:
一對(duì)一追他、多對(duì)一通常情況下采用立即加載
多對(duì)多、一對(duì)多通常情況下采用延遲加載
1.2用延遲加載實(shí)現(xiàn)需求:
需求:
查詢賬戶(Account)信息并且關(guān)聯(lián)查詢用戶(User)信息岛蚤。如果先查詢賬戶(Account)信息即可滿足要求,當(dāng)我們需要查詢用戶(User)信息時(shí)再查詢用戶(User)信息懈糯。把對(duì)用戶(User)信息的按需去查詢就是延遲加載涤妒。
mybatis第三天實(shí)現(xiàn)多表操作時(shí),使用了resultMap來(lái)實(shí)現(xiàn)一對(duì)一赚哗,一對(duì)多她紫,多對(duì)多關(guān)系的操作。主要是通過(guò) association屿储、collection 實(shí)現(xiàn)一對(duì)一及一對(duì)多映射贿讹。association、collection 具備延遲加載功能够掠。
在全局的xml文件SqlMapConfig文件中配置:
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
①使用association完成延遲加載:
需求:
查詢賬戶信息同時(shí)查詢用戶信息(在多對(duì)一即mybatis中的一對(duì)一的情況下完成延遲加載)民褂。
IAccountDao接口中的方法:
public interface IAccountDao {
/*** 查詢所有賬戶,同時(shí)獲取賬戶的所屬用戶名稱以及它的地址信息
* @return
*/
List<Account> findAll( );
}
IAccoutDao.xml映射文件的配置:
<!-- 建立對(duì)應(yīng)關(guān)系 -->
<mapper? namespace = "com.itheima.dao.IAccountDao">
<resultMap type="account" id="accountMap">
<id column="aid" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
<!-- 它是用于指定從表方的引用實(shí)體屬性的 -->
<association property="user"? javaType="user"
select="com.itheima.dao.IUserDao.findById"? column="uid">
</association>
</resultMap>
<select id="findAll" resultMap="accountMap">
????select * from account
</select>
</mapper>
select : 填寫(xiě)我們要調(diào)用的 select 映射的 id疯潭,即在IUserDao接口中的findById的方法
column : 填寫(xiě)我們要傳遞給 select 映射的參數(shù)赊堪,傳給findById方法的參數(shù),在這里肯定為account表中的uid
IUserDao接口中的方法:
public interface IUserDao {
/**
* 根據(jù) id 查詢
* @param userId*
@return
*/
User findById(Integer id);
}? ?
IUserDao.xml映射文件的配置:
<mapper namespace="com.itheima.dao.IUserDao">
<!-- 根據(jù) id 查詢 -->
<select id="findById" resultType="user" parameterType="int" >
select * from user where id = #{uid}
</select>
</mapper>
②使用collection完成延遲加載:
需求:
完成加載用戶對(duì)象時(shí)竖哩,查詢?cè)撚脩羲鶕碛械馁~戶信息(在一對(duì)多的情況下完成延遲加載)哭廉。
IUserDao接口中的方法:
/**
*查詢所有用戶,同時(shí)獲取出每個(gè)用戶下的所有賬戶信息
* @return
*/
List<User> findAll(? );
IUserDao.xml文件的配置:
<resultMap type="user" id="userMap">
?????<id column="id" property="id"></id>
????<result column="username" property="username"/>
????<result column="address" property="address"/>
????<result column="sex" property="sex"/>
????<result column="birthday" property="birthday"/>
<!-- collection 是用于建立一對(duì)多中集合屬性的對(duì)應(yīng)關(guān)系
ofType 用于指定集合元素的數(shù)據(jù)類型
select 是用于指定查詢賬戶的唯一標(biāo)識(shí)(賬戶的 dao 全限定類名加上方法名稱)
column 是用于指定使用哪個(gè)字段的值作為條件查詢 -->
<collection property="accounts"? ? ofType="account"? ?
select="com.itheima.dao.IAccountDao.findByUid"? ?column="id">
</collection>
</resultMap>
<!-- 配置查詢所有操作 -->
<select id="findAll" resultMap="userMap">
select * from user
</select>
*注意:
<collection> 標(biāo)簽 :
主要用于加載關(guān)聯(lián)的集合對(duì)象
select 屬性 :
用于指定查詢 account 列表的 sql 語(yǔ)句相叁,所以填寫(xiě)的是該 sql 映射的 id
column 屬性 :
用于指定 select 屬性的 sql 語(yǔ)句的參數(shù)來(lái)源遵绰,上面的參數(shù)來(lái)自于 user 的 id 列,所以就寫(xiě)成 id 這一個(gè)字段名了
IAccountDao接口中的方法:
/**
* 根據(jù)用戶 id 查詢賬戶信息
* @param uid
* @return
*/
List<Account>? ?findByUid(Integer uid);?
IAccountDao.xml配置文件:
<!-- 根據(jù)用戶 id 查詢賬戶信息 -->
<select id="findByUid"? resultType="account"? ?parameterType="int">
????????select * from account where uid = #{uid}
</select>
2.Mybatis中的緩存機(jī)制
? ? ? ?像大多數(shù)的持久化框架一樣增淹,Mybatis 也提供了緩存策略椿访,通過(guò)緩存策略來(lái)減少數(shù)據(jù)庫(kù)的查詢次數(shù),從而提
高性能埠通。
????????Mybatis 中緩存分為一級(jí)緩存赎离,二級(jí)緩存。
什么是緩存:存在于內(nèi)存中的臨時(shí)數(shù)據(jù)端辱;
為什么使用緩存:減少和數(shù)據(jù)庫(kù)交換的次數(shù)梁剔,提高執(zhí)行效率;
適用于緩存的數(shù)據(jù):經(jīng)常查詢的數(shù)據(jù)并且不經(jīng)常改變舞蔽,數(shù)據(jù)的正確與否對(duì)最終的結(jié)果影響不大的荣病;
不適用于緩存的數(shù)據(jù):經(jīng)常改變的數(shù)據(jù),數(shù)據(jù)的正確與否對(duì)最終的結(jié)果影響很大的渗柿;
2.1Mybatis中的一級(jí)緩存:
一級(jí)緩存是 SqlSession對(duì)象級(jí)別的緩存个盆,只要 SqlSession對(duì)象沒(méi)有 flush 或 close脖岛,它就存在。
原理:當(dāng)我們執(zhí)行查詢之后颊亮,查詢結(jié)果會(huì)存入到SqlSession對(duì)象為我們提供的一塊區(qū)域中柴梆。該區(qū)域的結(jié)構(gòu)是一個(gè)Map,當(dāng)我們?cè)俅尾樵兿嗤臄?shù)據(jù)時(shí)终惑,mybatis會(huì)先去SqlSession中查詢是否有绍在,有的話直接拿出來(lái)使用。當(dāng)SqlSession對(duì)象消失時(shí)雹有,mybatis的一級(jí)緩存也就消失了偿渡。
一級(jí)緩存的分析:
一級(jí)緩存是 SqlSession 范圍的緩存,當(dāng)調(diào)用 SqlSession 的修改霸奕,添加溜宽,刪除,commit( )质帅,close( )等方法時(shí)适揉,就會(huì)清空一級(jí)緩存。
????????第一次發(fā)起查詢用戶 id 為 1 的用戶信息煤惩,先去找緩存中是否有 id 為 1 的用戶信息涡扼,如果沒(méi)有,從數(shù)據(jù)庫(kù)查
詢用戶信息盟庞。
????????得到用戶信息吃沪,將用戶信息存儲(chǔ)到一級(jí)緩存中。
????????如果 sqlSession 去執(zhí)行 commit 操作(執(zhí)行插入什猖、更新票彪、刪除),清空 SqlSession 中的一級(jí)緩存不狮,這樣
做的目的為了讓緩存中存儲(chǔ)的是最新的信息降铸,避免臟讀。
????????第二次發(fā)起查詢用戶 id 為 1 的用戶信息摇零,先去找緩存中是否有 id 為 1 的用戶信息推掸,緩存中有,直接從緩存
中獲取用戶信息驻仅。
2.2Mybatis中的二級(jí)緩存:
? ? ?二級(jí)緩存:存放的內(nèi)容是數(shù)據(jù)(JSON格式)谅畅,而不是對(duì)象,會(huì)創(chuàng)建新對(duì)象噪服,進(jìn)行存改毡泻;? ??
?????二級(jí)緩存是 mapper 映射級(jí)別的緩存,多個(gè) SqlSession 去操作同一個(gè) Mapper 映射的 sql 語(yǔ)句粘优,多個(gè)SqlSession 可以共用二級(jí)緩存仇味,二級(jí)緩存是跨 SqlSession 的呻顽。指的是mybatis中SqlSessionFactory對(duì)象的緩存。由同一個(gè)SqlSessionFactory對(duì)象創(chuàng)建的SqlSession共享其緩存丹墨。
????????首先開(kāi)啟 mybatis 的二級(jí)緩存廊遍。
????????sqlSession1 去查詢用戶信息,查詢到用戶信息會(huì)將查詢數(shù)據(jù)存儲(chǔ)到二級(jí)緩存中贩挣。
????????如果 SqlSession3 去執(zhí)行相同 mapper 映射下 sql昧碉,執(zhí)行 commit 提交,將會(huì)清空該 mapper 映射下的二級(jí)緩存區(qū)域的數(shù)據(jù)揽惹。
????????sqlSession2 去查詢與 sqlSession1 相同的用戶信息,首先會(huì)去緩存中找是否存在數(shù)據(jù)四康,如果存在直接從
緩存中取出數(shù)據(jù)搪搏。
? ? ? ? 使用步驟:
? ? ? ? ?①讓mybatis框架支持二級(jí)緩存,在全局配置文件中配置:
<settings>
<setting name = "cacheEnable"? value ="true"/>
</settings>
????????②讓當(dāng)前映射文件支持二級(jí)緩存闪金,配置:
??<mapper namespace="com.itheima.dao.IUserDao">
<!-- 開(kāi)啟二級(jí)緩存的支持 -->
<cache></cache>
</mapper>
? ? ? ③讓當(dāng)前的操作支持二級(jí)緩存疯溺,在select標(biāo)簽中配置:
<!-- 根據(jù) id 查詢 -->
<select id="findById"? resultType="user"? parameterType="int"? useCache="true">
select * from user where id = #{uid}
</select>
將 UserDao.xml 映射文件中的<select>標(biāo)簽中設(shè)置 useCache=”true”代表當(dāng)前這個(gè) statement 要使用 二級(jí)緩存,如果不使用二級(jí)緩存可以設(shè)置為 false哎垦。
*注意:針對(duì)每次查詢都需要最新的數(shù)據(jù) sql囱嫩,要設(shè)置成 useCache=false,禁用二級(jí)緩存漏设。
二級(jí)緩存注意事項(xiàng):當(dāng)我們?cè)谑褂枚?jí)緩存時(shí)墨闲,所緩存的類一定要實(shí)現(xiàn) java.io.Serializable 接口,這種就可以使用序列化方式來(lái)保存對(duì)象郑口。
3.Mybatis中的注解開(kāi)發(fā):
3.1 mybatis 的常用注解說(shuō)明:
@Insert:實(shí)現(xiàn)新增
@Update:實(shí)現(xiàn)更新
@Delete:實(shí)現(xiàn)刪除
@Select:實(shí)現(xiàn)查詢
@Result:實(shí)現(xiàn)結(jié)果集封裝
@Results:可以與@Result 一起使用鸳碧,封裝多個(gè)結(jié)果集
@ResultMap:實(shí)現(xiàn)引用@Results 定義的封裝
@One:實(shí)現(xiàn)一對(duì)一結(jié)果集封裝
@Many:實(shí)現(xiàn)一對(duì)多結(jié)果集封裝
@SelectProvider: 實(shí)現(xiàn)動(dòng)態(tài) SQL 映射
@CacheNamespace:實(shí)現(xiàn)注解二級(jí)緩存的使用
注解開(kāi)發(fā)測(cè)試使用的注意事項(xiàng):
采用注解開(kāi)發(fā)時(shí),在全局配置文件中配置:
<mappers>
<mapper class = "com.itheima.dao.IUserDao"/>
</mappers>
或者直接配置:
<mappers>
????????<package name="com.itheima.dao"/>
</mappers>
*注意:采用注解開(kāi)發(fā)時(shí)犬性,不能在同一個(gè)文件名稱下dao進(jìn)行xml開(kāi)發(fā)瞻离,即使使用resource屬性也不能。
如:dao接口在com.itheima.dao下乒裆,而對(duì)應(yīng)接口的映射配置文件xml也在resources的com.itehima.dao目錄下套利,此時(shí)就會(huì)報(bào)錯(cuò),要么把xml移到別的目錄鹤耍,然后刪除整個(gè)目錄文件肉迫,要么直接刪除文件和文件目錄。
3.2使用注解實(shí)現(xiàn)復(fù)雜關(guān)系映射開(kāi)發(fā):
????????實(shí)現(xiàn)復(fù)雜關(guān)系映射之前我們可以在映射文件中通過(guò)配置<resultMap>來(lái)實(shí)現(xiàn)稿黄,在使用注解開(kāi)發(fā)時(shí)我們需要借
助@Results 注解昂拂,@Result 注解,@One 注解抛猖,@Many 注解格侯。
????????復(fù)雜關(guān)系映射的注解說(shuō)明:
@Results 注解? ?代替的是標(biāo)簽<resultMap>
@Resutl 注解? ? 代替了 <id> 標(biāo)簽和<result> 標(biāo)簽
@Result 中 屬性介紹:
????????id 是否是主鍵字段
????????column 數(shù)據(jù)庫(kù)的列名
????????property 需要裝配的屬性名
????????one 需要使用的@One 注解(@Result(one=@One)()))
????????many 需要使用的@Many 注解(@Result(many=@many)()))
@one中的屬性介紹:??
? ? ? ?@One 注解(一對(duì)一) 代替了<assocation> 標(biāo)簽鼻听,是多表查詢的關(guān)鍵,在注解中用來(lái)指定子查詢返回單一對(duì)象联四。
????????select? ?指定用來(lái)多表查詢的 sqlmapper
????????fetchType 會(huì)覆蓋全局的配置參數(shù) FetchType.LAZY(延遲加載)或者FetchType.EAGER(立即加載)
例如:
*注意:
此時(shí)最后一個(gè)@Result注解中撑碴,column屬性指定用來(lái)多表查詢的sqlmapper的參數(shù)? ,
@Many 注解(多對(duì)一)
????????代替了<Collection> 標(biāo)簽, 是是多表查詢的關(guān)鍵朝墩,在注解中用來(lái)指定子查詢返回對(duì)象集合醉拓。
注意:聚集元素用來(lái)處理“一對(duì)多”的關(guān)系。需要指定映射的 Java 實(shí)體類的屬性收苏,屬性的 javaType(一般為 ArrayList)但是注解中可以不定義亿卤;
例如:
3.3 mybatis 基于注解的二級(jí)緩存:
①.在全局配置文件SqlMapConfig.xml中配置開(kāi)啟二級(jí)緩存:
<!-- 配置二級(jí)緩存 -->
<settings>
????<!-- 開(kāi)啟二級(jí)緩存的支持 -->
????<setting name="cacheEnabled" value="true"/>
</settings>
②. 在持久層接口中使用注解配置二級(jí)緩存:
@CacheNamespace(blocking=true)//mybatis 基于注解方式實(shí)現(xiàn)配置二級(jí)緩存