MyBatis 作為一款 ORM 框架,在行業內有廣泛的應用。mApper xml 的配置有一些技巧,本文整理一下,方便查閱。
模糊查詢
MySQL 模糊查詢一般是使用 like 條件,我們經常使用傳入的變量作為 like 的條件。在 MyBatis 里面,like 使用變量需要用到 ${} 或者 concat。建議使用 concat,#{} 可以防止 SQL 注入。
like '%${value}%'
like concat('%',#{value},'%')
自動創建表
不建議在 MyBatis 里面建表,原則上數據表要由數據庫管理員創建。但是對于一些小應用,可能開發者集多個角色于一身,自動建表反而利大于弊。如下的語句在 <select> 標簽內使用了 CREATE TABLE IF NOT EXISTS 語法,可以在無表時自動建表,有表時會跳過執行。
<select id="createTable">
CREATE TABLE IF NOT EXISTS `demo` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`path` varchar(128) NOT NULL COMMENT '路徑'
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
</select>
自動判斷更新或插入
數據不存在則插入,數據已存在則更新,可以使用 MySQL on duplicate key update 來實現。當 primary key 或者 unique key 重復時會自動執行 update。
insert into `webVisit`(`date`,`ip`, uri, `count`)
values(#{date},#{ip},#{uri}, 1)
ON DUPLICATE KEY
update `count` = `count` + 1
自動忽略重復插入
數據不存在則插入,數據已存在則忽略,可以使用 MySQL ignore 來實現。當 primary key 或者 unique key 重復時會自動忽略本次插入操作。
insert ignore into `webVisit`(`ip`) values(#{ip})
自動替換重復數據
數據不存在則插入,數據已存在則替換,可以使用 MySQL replace into 來實現。當 primary key 或者 unique key 重復時會自動替換已存在的數據。實際上是先刪除原有數據,然后插入新數據。
replace into `webVisit`(`date`,`ip`, uri, `count`)
values(#{date},#{ip},#{uri}, 1)
使用緩存
使用緩存能夠極大提升應用的性能。二級緩存的開啟方式是
<cache flushInterval="60000"></cache>
新增、更新數據不刷新緩存
緩存在新增、更新數據時會自動失效,對于部分影響不大的操作可以設置不刷新緩存,方法是在語句 xml 上設置 flushCache=false。
<update id="demo" flushCache="false"></update>
獲取生成的自增id
使用自增 id 有很多好處,可以通過配置 selectKey 實現 insert 執行后返回生成的自增 id,以用于后續流程。
<insert id="insert" parameterType="demo">
<selectKey keyProperty="id" order="AFTER" resultType="JAVA.lang.Long">
SELECT LAST_INSERT_ID()
</selectKey>
insert into `demo`(demo) values(#{demo})
</insert>
只更新部分字段
使用 <if> <set> 標簽配合,可以實現只更新部分數據。一般是傳入 null 不更新,非 null 則更新。
<if> 標簽支持 test 配置一個表達式,表達式返回 true 時 <if> 內部的 SQL 片段會生效,否則不會生效。<set> 標簽能夠自動生成 set 片段,并處理去除首尾多余的字符。
<update id="updateById" parameterType="UserDO">
update `user`
<set>
<if test="nick != null">
nick = #{nick},
</if>
<if test="avatar != null">
avatar = #{avatar},
</if>
</set>
where userId = #{userId}
</update>
動態查詢條件
使用 <if> <where> 標簽配合,可以實現動態查詢條件。<if> 標簽能夠實現條件判斷。<where> 標簽能夠自動組裝 where 片段,去除首尾的非法字符。
<select id="select" resultMap="resultMap">
SELECT * FROM demo
<where>
<if test="userId != null">
userId = #{userId}
</if>
<if test="nick != null">
and nick = #{nick}
</if>
</where>
</select>
設置 SQL 超時時間
通過 timeout 屬性可以設置超時時間,也就是在拋出異常之前,驅動程序等待數據庫返回請求結果的秒數。
<update id="demo" timeout="100"></update>
復用 SQL 片段
用 sql 標簽可以定義 SQL 片段,用于 SQL 語句復用。
<sql id="Base_Column_List">
userId, email
</sql>
<select id="selectById" parameterType="java.lang.Long" resultMap="ResultMap">
select
<include refid="Base_Column_List" />
from `user`
where userId = #{userId}
</select>
批量插入數據
批量插入數據能夠極大提升性能,曾經測試過多條數據插入時間從分鐘級降低到秒級完成。批量插入主要用到 forEach 標簽,把批量數據轉換成 values 語句。
foreach 標簽的屬性主要有 item,index,collection,open,separator,close。
- item:集合中元素迭代時的別名;
- index:集合中元素迭代時的索引;
- open:常用語where語句中,表示以什么開始,比如以'('開始;
- separator:表示在每次進行迭代時的分隔符;
- close 常用語where語句中,表示以什么結束;
- collection:集合值;
<insert id="batchInsert" parameterType="java.util.List">
insert into `demo`(userId,`url`)
values
<foreach collection="list" item="item" separator=",">
(#{item.userId}, #{item.url})
</foreach>
</insert>
匹配多個值
使用 forEach 構建查詢條件集合,where 語句使用 in 即可實現匹配多個值。
<select id="queryById" resultMap="BaseReslutMap" >
select * FROM entity
where id in
<foreach collection="userids" item="userid" index="index" open="(" separator="," close=")">
#{userid}
</foreach>
</select>
條件語句
java 可以很方便地使用 if 或 switch 實現分支功能。MyBatis 的 choose 標簽可以實現條件分支。如下的配置中,傳入 id 時使用 id,不傳則使用其他條件。
choose 標簽是按順序判斷其內部when標簽中的test條件出否成立,如果有一個成立,則 choose 結束。當 choose 中所有 when 的條件都不滿則時,則執行 otherwise 中的sql。類似于Java 的 switch 語句,choose 為 switch,when 為 case,otherwise 則為 default。
<update id="update" parameterType="Config">
update `config` set `content` = #{content}
<where>
<choose>
<when test="id != null">
id = #{id}
</when>
<otherwise>
appName = #{appName} and t = #{t} and x = #{x}
</otherwise>
</choose>
</where>
</update>
你的工資被倒掛了嗎
終于知道 Java agent 怎么重寫字節碼了
每天的工作,你膩了嗎?
10 分鐘輕松學會 Jackson 反序列化自動適配子類
SpringMVC異步處理的 5 種方式