點擊這裏 查看Mybatis動態SQL官方文檔
對於初學者來說查看文檔內容有好多細節不理解這裏我結合我自身學習動態SQL實際遇到的困惑以及細節標示做一個梳理
首先幾個常用的關鍵字:
- if 判斷,當條件符合則進入條件語句(#{id}代表傳入的值)
<!-- 如果條件都滿足 則sql爲 select * from test_table where id=? and last_name=?
如果id==null則sql爲 select * from test_table where and last_name=? sql就會報錯
兩種處理方案 1.
我們使用 select * from test_table where 1=1 後面所有的if 前面都加 and
select * from test_table where 1=1
<if test="id!=null">
and id=#{id}
</if>
<if test="lastName!=null">
and last_name=#{lastName},
</if>
2.使用where標籤 <where></where> 後面單獨講
-->
select * from test_table where
<if test="id!=null">
id=#{id}
</if>
<if test="lastName!=null">
and last_name=#{lastName},
</if>
- choose (when, otherwise):分支選擇;類似於我們的swtich-case break語句,只會進入一個選擇條件
<!-- public List<TestBean> getInfo(TestBean testbean); -->
<select id="getInfo" resultType="com.xiaoqiang.mybatis.bean.TestBean">
select * from test_table
<where>
<!-- 如果帶了id就用id查,如果帶了lastName就用lastName查;只會進入其中一個 -->
<choose>
<when test="id!=null">
id=#{id}
</when>
<when test="lastName!=null">
last_name like #{lastName}
</when>
<when test="email!=null">
email = #{email}
</when>
<otherwise>
1=1
</otherwise>
</choose>
</where>
</select>
- trim 字符串截取(where(封裝查詢條件), set(封裝修改條件))
<!-- 使用where標籤
如果拼接第一個條件的時候第一個條件不成立則sql就會報錯,
例如下面代碼的id==null則不會進入id=#{id} sql就變成:select * from table where and email=? 明顯sql報錯
使用where標籤就會把前面的and去掉,保證sql正常。
但是如果我們把and加到語句後面則where標籤就無法實現了只能使用 trim 標籤來處理,一般沒這麼寫的
<if test="id!=null">
id=#{id} and
</if>
-->
<where>
<if test="id!=null">
id=#{id}
</if>
<if test="email!=null">
and email=#{email}
</if>
</where>
<!-- 使用set 是爲了如果拼到最後的還有逗號,就會把最後的逗號去掉 我們仍然可以使用 trim 標籤來替代set標籤-->
<update id="updateBean">
<!-- Set標籤的使用 -->
update test_table
<set>
<if test="lastName!=null">
last_name=#{lastName},
</if>
<if test="email!=null">
email=#{email},
</if>
</set>
where id=#{id}
</update>
<!--我們使用trim標籤替代where標籤來定製where標籤功能-->
<select id="getBean" resultType="com.xiaoqiang.mybatis.bean.TestBean">
select * from test_table
<!-- 後面多出的and或者or where標籤不能解決的問題
prefix="":前綴:trim標籤體中是整個字符串拼串 後的結果。
prefix給拼串後的整個字符串加一個前綴
prefixOverrides="":
前綴覆蓋: 去掉整個字符串前面多餘的字符
suffix="":後綴
suffix給拼串後的整個字符串加一個後綴
suffixOverrides=""
後綴覆蓋:去掉整個字符串後面多餘的字符
-->
<!-- 自定義字符串的截取規則 suffixOverrides處理後綴and -->
<trim prefix="where" suffixOverrides="and">
<if test="id!=null">
id=#{id} and
</if>
<if test="lastName!=null">
last_name like #{lastName} and
</if>
<if test="email!=null">
email=#{email} and
</if>
</trim>
</select>
<!--我們使用trim標籤替代set標籤 suffixOverrides處理後綴逗號-->
update test_table
<trim prefix="set" suffixOverrides=",">
<if test="lastName!=null">
last_name=#{lastName},
</if>
<if test="email!=null">
email=#{email},
</if>
</trim>
where id=#{id}
- foreach 遍歷集合
<!--public List<TestBean> getBeans(List<Integer> ids); -->
<select id="getBeans" resultType="com.xiaoqiang.mybatis.bean.TestBean">
select * from test_table where id in
<!--
sql : select * from test_table where id in (1,2,3)
collection:指定要遍歷的集合
item:將當前遍歷出的元素賦值給指定的變量
separator:每個元素之間的分隔符
open:遍歷出所有結果拼接一個開始的字符
close:遍歷出所有結果拼接一個結束的字符
index:索引。遍歷list的時候是index就是索引,item就是當前值
遍歷map的時候index表示的就是map的key,item就是map的值
使用#{變量名}就能取出變量的值也就是當前遍歷出的元素
-->
<foreach collection="ids" item="item_id" separator=","
open="(" close=")">
#{item_id}
</foreach>
</select>
- 抽取重複片段使用:
<!--
抽取可重用的sql片段。方便後面引用
1、sql抽取:經常將要查詢的列名,或者插入用的列名抽取出來方便引用
2、include來引用已經抽取的sql
-->
<sql id="insertColumn">
last_name,email
</sql>
<!-- 使用include 重用抽取出來的sql片段 -->
insert into test_table (
<include refid="insertColumn"></include>
)
values('name','[email protected]')
增刪改查知識點記錄:
獲取自增主鍵只有設置useGeneratedKeys=“true” keyProperty="id"才能通過返回的bean拿到相應的id
<!--
獲取自增主鍵的值:
mysql支持自增主鍵,自增主鍵值的獲取,mybatis也是利用statement.getGenreatedKeys();
useGeneratedKeys="true";使用自增主鍵獲取主鍵值策略
keyProperty;指定對應的主鍵屬性,也就是mybatis獲取到主鍵值以後,將這個值封裝給javaBean的哪個屬性
-->
<insert id="addEmp" useGeneratedKeys="true" keyProperty="id" >
insert into test_table (last_name,email)
values(#{lastName},#{email})
</insert>
如果我們傳入多個參數 使用#{參數名}來取值是會報錯:
org.apache.ibatis.binding.BindingException: Parameter ‘insert_type’ not found. Available parameters are [a, b, param1, param2]
<!--
單個參數:
mybatis不會做特殊處理,
#{參數名/任意名}:可以取出參數值。
多個參數:
mybatis會做特殊處理。多個參數會被封裝成 一個map,
key:param1...paramN,或者參數的索引也可以
value:傳入的參數值
#{}就是從map中獲取指定的key的值;
-->
<!--傳入兩個參數不能使用#{insert_type} #{phoneNum}這種形式醬紫會報上面錯 需要使用param1...-->
<select id="getTypeTwo" resultType="com.example.demomybatis.bean.myTypeBean">
SELECT * FROM my_type
WHERE insert_type=#{insert_type} and phone_num=#{phone_num}
</select>
<!--正確可使用形式-->
<select id="getTypeTwo" resultType="com.example.demomybatis.bean.myTypeBean">
SELECT * FROM my_type
WHERE insert_type=#{param1} and phone_num=#{param2}
</select>
<!--Controller傳入兩個參數insertType,phoneNum調用Service的getTypeTwo最終映射到上面的Mapper的sql中使用param
返回正確查詢-->
@GetMapping(value = "/getTypeTwo")
public JSONObject getTypeTwo(@RequestParam("insertType") String insertType, @RequestParam("phoneNum") String phoneNum) {
List<myTypeBean> typeTwo = service.getTypeTwo(insertType, phoneNum);
JSONObject object = new JSONObject();
object.put("data", typeTwo);
object.put("code", "000");
return object;
}
或者使用第二種形式 -->命名參數(常用形式):在Mapper.java接口修改與xml相對應的的方法,給方法的參數加上@Param("insert_type")明確參數的key 使用#{insert_type} 就可以拿到相應的值
<!-- import org.apache.ibatis.annotations.Param;-->
List<myTypeBean> getTypeTwo(@Param("insert_type") String insert_type, @Param("phone_num") String phone_num);
mybatis一級、二級緩存描述
/**
* 兩級緩存:
* 一級緩存:(本地緩存):sqlSession級別的緩存。一級緩存是一直開啓的;SqlSession級別的一個Map
* 與數據庫同一次會話期間查詢到的數據會放在本地緩存中。
* 以後如果需要獲取相同的數據,直接從緩存中拿,沒必要再去查詢數據庫;
*
* 一級緩存失效情況(沒有使用到當前一級緩存的情況,效果就是,還需要再向數據庫發出查詢):
* 1、sqlSession不同。
* 2、sqlSession相同,查詢條件不同.(當前一級緩存中還沒有這個數據)
* 3、sqlSession相同,兩次查詢之間執行了增刪改操作(這次增刪改可能對當前數據有影響)
* 4、sqlSession相同,手動清除了一級緩存(緩存清空)
*
* 二級緩存:(全局緩存):基於namespace級別的緩存:一個namespace對應一個二級緩存:
* 工作機制:
* 1、一個會話,查詢一條數據,這個數據就會被放在當前會話的一級緩存中;
* 2、如果會話關閉;一級緩存中的數據會被保存到二級緩存中;新的會話查詢信息,就可以參照二級緩存中的內容;
* 3、sqlSession===EmployeeMapper==>Employee
* DepartmentMapper===>Department
* 不同namespace查出的數據會放在自己對應的緩存中(map)
* 效果:數據會從二級緩存中獲取
* 查出的數據都會被默認先放在一級緩存中。
* 只有會話提交或者關閉以後,一級緩存中的數據纔會轉移到二級緩存中
* 使用:
* 1)、開啓全局二級緩存配置:<setting name="cacheEnabled" value="true"/>
* 2)、去mapper.xml中配置使用二級緩存:
* <cache></cache>
* 使用一個空cache標籤就可以對這個Mapper開啓二級緩存
* cache有很多參數這裏一一列舉一下:
*
* <cache eviction="" blocking="" flushInterval="" readOnly="" size="" type="" ></cache>
*
* eviction:緩存的回收策略:
* • LRU – 最近最少使用的:移除最長時間不被使用的對象。
* • FIFO – 先進先出:按對象進入緩存的順序來移除它們。
* • SOFT – 軟引用:移除基於垃圾回收器狀態和軟引用規則的對象。
* • WEAK – 弱引用:更積極地移除基於垃圾收集器狀態和弱引用規則的對象。
* • 默認的是 LRU。
* flushInterval:緩存刷新間隔
* 緩存多長時間清空一次,默認不清空,設置一個毫秒值
* readOnly:是否只讀:
* true:只讀;mybatis認爲所有從緩存中獲取數據的操作都是隻讀操作,不會修改數據。
* mybatis爲了加快獲取速度,直接就會將數據在緩存中的引用交給用戶。不安全,速度快
* false:非只讀:mybatis覺得獲取的數據可能會被修改。
* mybatis會利用序列化&反序列的技術克隆一份新的數據給你。安全,速度慢
* size:緩存存放多少元素;
* type="":指定自定義緩存的全類名;
* 實現Cache接口即可;
* 3)、我們的POJO(Bean)需要實現序列化接口 implements Serializable
*
* 和緩存有關的設置/屬性:
* 1)、cacheEnabled=true:false:關閉緩存(二級緩存關閉)(一級緩存一直可用的)
* 2)、每個select標籤都有useCache="true":
* false:不使用緩存(一級緩存依然使用,二級緩存不使用)
* 3)、【每個增刪改標籤的:flushCache="true":(一級二級都會清除)】
* 增刪改執行完成後就會清楚緩存;
* 測試:flushCache="true":一級緩存就清空了;二級也會被清除;
* 查詢標籤:flushCache="false":
* 如果flushCache=true;每次查詢之後都會清空緩存;緩存是沒有被使用的;
* 4)、sqlSession.clearCache();只是清楚當前session的一級緩存;
* 5)、localCacheScope:本地緩存作用域:(一級緩存SESSION);當前會話的所有數據保存在會話緩存中;
* STATEMENT:可以禁用一級緩存;
*
*第三方緩存整合:
* 1)、導入第三方緩存包即可;
* 2)、導入與第三方緩存整合的適配包;官方有;
* 3)、mapper.xml中使用自定義緩存
* <cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
*
*
*/