Mybatis 動(dòng)態(tài)sql的編寫(xiě)與開(kāi)啟二級(jí)緩存
前言
上篇博文把表連接查詢和三種對(duì)應(yīng)關(guān)系的寫(xiě)法記錄總結(jié)了,本篇要把 mybatis 中的動(dòng)態(tài)sql 的使用以及緩存知識(shí)記錄下來(lái)。
動(dòng)態(tài)SQL
在解釋 where if
標(biāo)簽之前先進(jìn)行一個(gè)模糊查詢的操作。
模糊查詢
如下面一張表:
查詢所有 李 姓人員的信息:
在mapper
接口中定義方法:
List<Person> selectName(String name);
在 xml
中編寫(xiě) sql
語(yǔ)句:
<select id="selectName" resultMap="personMap"> select * from t_person where person_name like concat('%', #{name}, '%'); </select>
這里的
concat('%', #{name}, '%')
寫(xiě)法使用了字符串拼接的技巧,這樣在查詢語(yǔ)句里就是%name%
的模糊查詢了。
如果這樣寫(xiě):'%#{name}%'
是不行的,#{}
會(huì)失效。
編寫(xiě)測(cè)試類(lèi):
測(cè)試結(jié)果:
可以看到所有 李 姓的人信息被查詢到了。
where if 標(biāo)簽
姓李的太多,那么我們可以加一個(gè)年齡范圍,于是需要增加兩個(gè)參數(shù):
這里要注意,參數(shù)在兩個(gè)以上需要使用 注解 來(lái)綁定。
重點(diǎn)來(lái)看 xml
中的 sql 語(yǔ)句:
<select id="selectContent" resultMap="personMap"> select * from t_person <where> <if test="name != null and name !=''"> person_name like concat('%',#{name},'%') </if> <if test="ageMin > 0"> and age >= #{ageMin} </if> <if test="ageMax > ageMin"> and age <= #{ageMax} </if> </where> </select>
- 可以看到這里的 where 關(guān)鍵字變成了一個(gè)標(biāo)簽 <where>,這是因?yàn)椋?/li>
- 如果這三個(gè)參數(shù)都不填寫(xiě)的話,where 下的條件就不會(huì)起作用,
- 此條 sql 就變成了查詢所有。
- 顯然,查詢所有的語(yǔ)法里是沒(méi)有 where 關(guān)鍵字的,因此使用標(biāo)簽代替。
- 除了使用 <where> 標(biāo)簽之外,也可以使用類(lèi)似 1=1 加 and 的方法拼接。
- 比如: select * from t_person where 1=1 and ...
- 此外,where 標(biāo)簽還可以去除多余的 and 前綴。
- if 標(biāo)簽用來(lái)做判斷,test 里寫(xiě)判斷的條件,標(biāo)簽內(nèi)寫(xiě)判斷成功后的 sql 語(yǔ)句:
- 這里就是判斷名字是否為空以及年齡的取值范圍是否合理:
- test 里面的符號(hào)正常寫(xiě),and 和 or 代表并且和或者。
- sql 語(yǔ)句里,> 是大于的意思,< 是小于的意思。
編寫(xiě)測(cè)試類(lèi):
測(cè)試結(jié)果:
很明顯,年齡在 20~28
且姓李的只有 “李白” 自己。
update set 標(biāo)簽
以往的修改操作都是將對(duì)象的所有屬性都修改或者重寫(xiě)一遍,這樣是不合邏輯的,因此可以在修改的 sql 語(yǔ)句里使用 if
標(biāo)簽來(lái)優(yōu)化。
在 mapper
接口中寫(xiě)方法:
void update(Person person);
在 xml
中編寫(xiě) sql:
<update id="update"> update t_person <set> <if test="personName !=null and personName !=''"> person_name = #{personName}, </if> <if test="age !=null"> age = #{age}, </if> <if test="birthday != null and birthday!= ''"> birthday = #{birthday}, </if> <if test=" sex !=null and sex !=''"> sex = #{sex}, </if> <if test="mobile != null and mobile !=''"> mobile = #{mobile}, </if> <if test="address !=null and address!=''"> address = #{address} </if> </set> where person_id = #{personId} </update>
if
標(biāo)簽想必好理解,但是set
標(biāo)簽是做什么的呢?原因是:- 假如只修改名字,那么 sql 語(yǔ)句將變?yōu)椋?/li>
update t_person set person_name = ?, where ...
- 可以發(fā)現(xiàn)
?
占位符后面會(huì)有多余的逗號(hào)導(dǎo)致 sql 語(yǔ)法錯(cuò)誤 <set>
標(biāo)簽會(huì)自動(dòng)去除多余的逗號(hào)后綴。
值得注意的是:set 標(biāo)簽去除
,
后綴,where 標(biāo)簽去除and
前綴。
foreach 標(biāo)簽
相信大家都知道foreach
跟循環(huán)有關(guān)系,沒(méi)錯(cuò),我們可以利用此標(biāo)簽來(lái)完成 批量刪除 操作。
從 sql 的語(yǔ)句來(lái)看,批量刪除應(yīng)該這樣寫(xiě):
delete from t_person where person_id in (?,?,?,...)
那么 in
后的形式該怎么用 mybatis 表達(dá)出來(lái)呢,有括號(hào),不定數(shù)量的逗號(hào)…
不急,一步步來(lái),先寫(xiě) mapper
接口:
void deleteMany(@Param("myIds") int[] ids);
再編寫(xiě) sql 語(yǔ)句:
<delete id="deleteMany"> delete from t_person where person_id in <foreach collection="myIds" open="(" close=")" separator="," item="id"> #{id} </foreach> </delete>
利用
foreach
就可以將參數(shù)集合中的值依次放入到in
后的括號(hào)內(nèi):(id,id,id...)
foreach
標(biāo)簽相關(guān)解釋:
- collection:被循環(huán)的數(shù)組或者集合,注意如果是參數(shù)必須使用
@Param
起名 - open : 循環(huán)以什么開(kāi)始
- close :循環(huán)以什么結(jié)束
- separator: 循環(huán)以什么分割
- item : 每次循環(huán)的元素
編寫(xiě)測(cè)試類(lèi)(不要忘記手動(dòng)提交事務(wù)):
測(cè)試結(jié)果:
可以看到數(shù)組里的元素依次放入了括號(hào)內(nèi),并成功做到了批量刪除。
useGeneratedKeys 獲取插入數(shù)據(jù)的主鍵值
一般我們習(xí)慣將表中的主鍵設(shè)為自增長(zhǎng),那么在使用 insert
插入數(shù)據(jù)時(shí),主鍵是不用賦值的,而是用 null
代替。那怎么才能在插入后直接得到該數(shù)據(jù)的主鍵值呢?那就使用 useGeneratedKeys
。
來(lái)看具體的使用:
<insert id="insert" useGeneratedKeys="true" keyProperty="personId" keyColumn="person_id"> insert into t_person values (null, #{personName}, #{age}, #{sex}, #{birthday}, #{mobile}, #{address}) </insert>
將值設(shè)為
true
后,keyPropetry
的值填寫(xiě)屬性名,keyColumn
的值填寫(xiě)表的字段名。
編寫(xiě)測(cè)試類(lèi):
@Test public void insert(){ SqlSession sqlSession = MybatisUtil.getSqlSession(); PersonMapper mapper = sqlSession.getMapper(PersonMapper.class); Person person = new Person(null,"微涼",21,"1",new Date(),"1359356123","愛(ài)琴海"); mapper.insert(person); sqlSession.commit(); MybatisUtil.closeSqlSession(sqlSession); System.out.println(person); }
測(cè)試結(jié)果:
可以看到插入數(shù)據(jù)后的主鍵值為 240,這便是自動(dòng)獲取的結(jié)果。
Mybatis 緩存
有關(guān) IO
操作一般都會(huì)很耗時(shí),在一個(gè) javaweb
項(xiàng)目中,頁(yè)面到 tomcat 與 tomcat 到數(shù)據(jù)庫(kù)都屬于IO操作。因此 mybatis 在 tomcat 中創(chuàng)建了一塊叫做緩存的空間,在緩存中保存比如查詢操作的數(shù)據(jù),以后進(jìn)行重復(fù)操作時(shí),就不必到數(shù)據(jù)庫(kù)中獲取了,而是直接在 tomcat 內(nèi)部獲取。
如果對(duì)數(shù)據(jù)庫(kù)進(jìn)行修改,緩存中的數(shù)據(jù)跟數(shù)據(jù)庫(kù)中的對(duì)應(yīng)不上,那么此時(shí)緩存中的就變成了臟數(shù)據(jù)。
一級(jí)緩存
特點(diǎn):
- 默認(rèn)開(kāi)啟
- 作用在同一個(gè)
SqlSession
中 - 臟數(shù)據(jù)的處理: 一旦執(zhí)行增刪改,立刻清空緩存
但是一級(jí)緩存并沒(méi)有什么意義,因?yàn)樽饔梅秶木壒?,它只能在一個(gè) SqlSession
,也就是一個(gè)事務(wù)內(nèi),一旦提交事務(wù),緩存就會(huì)被清空,沒(méi)有實(shí)戰(zhàn)意義。
二級(jí)緩存
二級(jí)緩存的作用范圍大,符合實(shí)戰(zhàn)的需求,該如何開(kāi)啟:
- 實(shí)體類(lèi)需要實(shí)現(xiàn)可序列化接口:
implements Serializable
- 在
mybatis-config.xml
文件中添加<settings>
標(biāo)簽:
<!--開(kāi)啟二級(jí)緩存 settings 寫(xiě)在 properties 和 typeAliases 之間--> <settings> <setting name="cacheEnabled" value="true"/> </settings>
3.在對(duì)應(yīng) mapper
的 xml
文件中添加 <cache>
標(biāo)簽:
<cache size="1024" eviction="LRU" flushInterval="60000"/>
- size:定義二級(jí)緩存空間大小 (單位是 M)
- eviction:定義緩存到達(dá)上限時(shí)的淘汰策略,常使用
LRU
算法:- 叫做最近最久未使用算法,即清空最近使用次數(shù)最少的緩存
- flushInterval:定義清空緩存的間隔時(shí)間 (單位 ms)
作用范圍:
- 同一個(gè)
sqlSessionFactory
內(nèi),而且必須提交事務(wù)。
臟數(shù)據(jù)的處理:
- 一旦執(zhí)行增刪改,默認(rèn)清空同一個(gè)
namespace
下的二級(jí)緩存。 - 自定義清空緩存的策略:
flushCache
屬性,值為true
時(shí)執(zhí)行清空緩存,為false
則不清空。- 在
insert
、delete
、update
標(biāo)簽里默認(rèn)為true
- 在
select
標(biāo)簽里默認(rèn)為false
臟數(shù)據(jù)并不都是一定要清空,因此在增刪改查標(biāo)簽內(nèi)可以自由的設(shè)定緩存清空的策略。
mybatis 框架的記錄到此結(jié)束,一共三篇,感興趣的小伙伴可以訂閱此專欄。
到此這篇關(guān)于Mybatis 動(dòng)態(tài)sql的編寫(xiě)|開(kāi)啟二級(jí)緩存的文章就介紹到這了,更多相關(guān)Mybatis開(kāi)啟二級(jí)緩存內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在Spring應(yīng)用中進(jìn)行單元測(cè)試的解析和代碼演示
在Spring應(yīng)用中進(jìn)行單元測(cè)試通常涉及到Spring TestContext Framework,它提供了豐富的注解和工具來(lái)支持單元測(cè)試和集成測(cè)試,以下是如何在Spring應(yīng)用中進(jìn)行單元測(cè)試的詳細(xì)解析和代碼演示,需要的朋友可以參考下2024-06-06基于Beanutils.copyProperties()的用法及重寫(xiě)提高效率
這篇文章主要介紹了Beanutils.copyProperties( )的用法及重寫(xiě)提高效率的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09SpringBoot連接PostgreSQL+MybatisPlus入門(mén)案例(代碼詳解)
這篇文章主要介紹了SpringBoot連接PostgreSQL+MybatisPlus入門(mén)案例,本文通過(guò)實(shí)例代碼圖文相結(jié)合給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-07-07idea中如何創(chuàng)建scala項(xiàng)目
idea中創(chuàng)建scala項(xiàng)目有三種方式1.通過(guò)maven;2.通過(guò)idea;3.通過(guò)sbt的方式;本文就每種方法通過(guò)圖文并茂的形式給大家詳細(xì)介紹,需要的朋友參考下吧2021-07-07java9新特性Reactive?Stream響應(yīng)式編程?API
這篇文章主要為大家介紹了java9新特性響應(yīng)式編程API的特點(diǎn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03SpringBoot使用Netty實(shí)現(xiàn)遠(yuǎn)程調(diào)用的示例
這篇文章主要介紹了SpringBoot使用Netty實(shí)現(xiàn)遠(yuǎn)程調(diào)用的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10基于Java8并行流(parallelStream)的注意點(diǎn)
這篇文章主要介紹了Java8并行流(parallelStream)的注意點(diǎn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07java中如何實(shí)現(xiàn)對(duì)類(lèi)的對(duì)象進(jìn)行排序
在本篇文章里小編給各位整理一篇關(guān)于java中如何實(shí)現(xiàn)對(duì)類(lèi)的對(duì)象進(jìn)行排序知識(shí)點(diǎn)內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。2020-02-02