速覽 MyBatis:關鍵功能與實踐技巧
前言
MyBatis
是一款功能強大的ORM
框架,幫助開發(fā)者在Java
程序中高效地與數(shù)據(jù)庫進行交互。
功能特點
SQL
映射靈活:MyBatis
允許開發(fā)人員通過XML
或注解的方式來配置SQL
語句,將SQL
語句與Java
代碼分離,使得SQL
的維護更加方便。同時,它提供了強大的動態(tài)SQL
功能,能夠根據(jù)不同的條件動態(tài)生成SQL
語句,滿足各種復雜的查詢需求。- 支持多種數(shù)據(jù)庫:
MyBatis
支持多種關系型數(shù)據(jù)庫,如MySQL、Oracle、SQL Server
等。開發(fā)人員可以使用相同的API
來操作不同的數(shù)據(jù)庫,只需要更換相應的數(shù)據(jù)庫驅動和配置即可,具有很高的數(shù)據(jù)庫兼容性和可移植性。 - 對象關系映射(
ORM
):MyBatis
實現(xiàn)了對象關系映射,能夠將數(shù)據(jù)庫中的表記錄映射為Java
對象,方便在Java
程序中進行操作。它提供了靈活的映射配置方式,可以自定義對象與表之間的映射關系,包括字段的映射、關聯(lián)關系的處理等。 - 性能優(yōu)化:
MyBatis
具有良好的性能表現(xiàn),它對SQL
執(zhí)行進行了優(yōu)化,例如緩存機制。MyBatis
提供了一級緩存和二級緩存,一級緩存基于SqlSession
級別,二級緩存可以在多個SqlSession
之間共享,能夠有效減少數(shù)據(jù)庫的查詢次數(shù),提高系統(tǒng)性能。
使用方式
基本使用
動態(tài)SQL
允許根據(jù)傳入的參數(shù)生成不同的SQL
語句,避免了復雜條件下的SQL
拼接問題。
<select id="selectUsersByCondition" resultType="User">
SELECT * FROM users WHERE 1=1
<if test="username != null">AND username = #{username}</if>
<if test="age != null">AND age = #{age}</if>
</select>
使用 foreach 實現(xiàn)批量操作
<foreach>
循環(huán)容器:用于在SQL
中循環(huán)處理集合或數(shù)組數(shù)據(jù),常用于IN
條件。主要屬性包括:
item
:集合元素迭代別名。index
:元素迭代索引。collection
:指定集合或數(shù)組,單參數(shù)List
時為list
,單參數(shù)數(shù)組時為array
,多參數(shù)或單參數(shù)封裝為Map
時,是對應List
或數(shù)組在Map
中的鍵。open、separator、close
:定義循環(huán)內容的起始、分隔和結束符號。
<select id="selectUsersByIds" resultType="User">
select * FROM users
where id in
<foreach collection="ids" item="userid" index="index" open="(" separator="," close=")">
#{userid}
</foreach>
</select>
<insert id="insertUsersBatch" parameterType="java.util.List">
INSERT INTO users (username, age, email)
VALUES
<foreach collection="userList" item="user" index="index" open="(" separator="),(" close=")">
#{user.username}, #{user.age}, #{user.email}
</foreach>
</insert>
?
實際使用中,避免集合超過1000,否則會提示
java.sql.SQLSyntaxErrorException: ORA-01795: maximum number of expressions in a list is 1000
<select id="selectUsersByIds" resultType="User">
select * FROM users
where id in (
<foreach collection="ids" item="userid" index="index">
<!-- 解決 list中數(shù)據(jù)大于1K條的問題 -->
<iftest="index != 0">
<choose>
<when test="index % 1000 == 999">
) or id in (
</when>
<otherwise>,</otherwise>
</choose>
</if>
#{userid}
</foreach>
)
</select>
choose、when、otherwise條件判斷
類似Java
的switch
語句,按順序判斷<when>
標簽的test
條件,滿足則執(zhí)行對應SQL
,都不滿足則執(zhí)行<otherwise>
中的SQL
。
<select id="getUserList_choose" resultType="User" parameterType="User">
SELECT *
FROM users u
<where>
<choose>
<when test="username!=null and username!= ''">
u.username LIKE CONCAT(CONCAT('%', #{username, jdbcType=VARCHAR}),'%')
</when>
<when test="age!= null">
AND u.age = #{age, jdbcType=INTEGER}
</when>
<when test="email!= null and email!= ''">
AND u.email = #{email, jdbcType=VARCHAR}
</when>
<otherwise>
</otherwise>
</choose>
</where>
</select>
concat模糊查詢
通過concat
函數(shù)實現(xiàn)模糊查詢,并結合<if>
標簽動態(tài)拼接SQL
條件
<select id="queryById" resultType="User" parameterType="User">
SELECT * from users
<where>
<if test="username!=null">
username like concat('%',concat(#{username},'%'))
</if>
</where>
</select>
if標簽
根據(jù)條件動態(tài)拼接SQL
語句,常用于查詢
<select id="selectUsersByCondition" resultType="User" parameterType="User">
SELECT * FROM users
WHERE 1=1
<iftest="username != null and username != ''">
AND username = #{username}
</if>
<iftest="age != null">
AND age = #{age}
</if>
<iftest="email != null and email != ''">
AND email = #{email}
</if>
</select>
但多個<if>
在WHERE
中可能導致關鍵字多余錯誤。
if + where條件判斷
<where>
標簽可解決多個<if>
在WHERE
中導致的關鍵字多余問題,自動添加或剔除WHERE
及多余的AND、OR
,避免手動添加 WHERE 1=1
<select id="selectUsersByCondition" resultType="User" parameterType="User">
SELECT * FROM users
<where>
<iftest="username != null and username != ''">
username = #{username}
</if>
<iftest="age != null">
AND age = #{age}
</if>
<iftest="email != null and email != ''">
AND email = #{email}
</if>
</where>
</select>
if + set條件更新
在UPDATE
語句中,<set>
標簽可動態(tài)配置SET
關鍵字,剔除末尾多余逗號,避免因參數(shù)null
導致的錯誤。
<update id="updateUserById">
UPDATE users
<set>
<iftest="username != null and username != ''">
username = #{username},
</if>
<iftest="age != null">
age = #{age},
</if>
<iftest="email != null and email != ''">
email = #{email},
</if>
<iftest="updateTime != null">
update_time = #{updateTime},
</if>
<!-- 可根據(jù)需要添加更多字段 -->
</set>
WHERE userid = #{userid}
</update>
CASE WHEN
<select id="selectUserList" resultType="User">
SELECT
userid,
username,
age,
status,
CASE status
WHEN 'ACTIVE' THEN '活躍'
WHEN 'INACTIVE' THEN '非活躍'
WHEN 'BLOCKED' THEN '已封禁'
ELSE '未知狀態(tài)'
END AS status_text
FROM users
</select>
使用 resultMap 映射復雜結果
當查詢返回的列與實體類的字段名稱不一致時,resultMap
可以幫忙進行映射。
<resultMap id="userResultMap" type="User">
<id property="id" column="userid" />
<result property="username" column="username" />
<result property="age" column="age" />
</resultMap>
<select id="selectUsersByCondition" resultMap="userResultMap">
SELECT * FROM users WHERE 1=1
<if test="username != null">AND username = #{username}</if>
<if test="age != null">AND age = #{age}</if>
</select>
處理一對多關系
<resultMap id="userWithOrders" type="User">
<id property="id" column="userid" />
<result property="username" column="username" />
<collection property="orders" ofType="Order">
<id property="id" column="order_id" />
<result property="amount" column="order_amount" />
</collection>
</resultMap>
<select id="selectUserWithOrders" resultMap="userWithOrders">
SELECT u.userid, u.username, o.order_id, o.order_amount FROM users
u LEFT JOIN orders o ON u.userid = o.user_id
</select>
使用 bind 處理復雜表達式
<bind name="pattern" value="'%' + keyword + '%'" />
<select id="selectUsersByKeyword" resultType="User">
SELECT * FROM users WHERE username LIKE #{pattern}
</select>
復用 SQL 片段
<sql id="baseUserSql"> SELECT userid, username, age, email FROM users</sql>
<select id="selectUsers" resultType="User">
<include refid="baseUserSql"/>
</select>