深入淺出MyBatis映射器
映射器是MyBatis最復(fù)雜也最重要的組件,也是基于MyBatis應(yīng)用程序開發(fā)中,占工作量比較大的工作,甚至能達(dá)到8成;映射器由Mapper接口和XML或者注解組成,在映射器中可以配置參數(shù),各類SQL語(yǔ)句,存儲(chǔ)過程、緩存、級(jí)聯(lián)等復(fù)雜處理,并通過簡(jiǎn)易的映射規(guī)則將數(shù)據(jù)映射到指定的POJO或其對(duì)象上,這也是MyBatis核心運(yùn)轉(zhuǎn)邏輯
在XML和注解之間的選擇其實(shí)很明顯,其一面對(duì)復(fù)雜SQL,尤其比較長(zhǎng)的SQL,注解會(huì)顯得很無(wú)力;其二注解的可讀性較差,尤其是對(duì)于那些需要復(fù)雜配置的SQL;其三注解沒有XML上下文相互引用的優(yōu)勢(shì)
MyBatis映射器可配置元素
MyBatis映射器配置文件中可以包含以下主要元素,這些元素用于定義與數(shù)據(jù)庫(kù)交互的各種操作和相關(guān)配置:
<select>
:代表SQL的SELECT
語(yǔ)句,用于從數(shù)據(jù)庫(kù)中查詢數(shù)據(jù),可以設(shè)置屬性如id
(唯一標(biāo)識(shí)該查詢)、parameterType
(傳入?yún)?shù)的全限定類名或別名)、resultType
或resultMap
(指定查詢結(jié)果的映射類型或引用的結(jié)果映射)??梢酝ㄟ^fetchSize
、timeout
等屬性控制查詢行為,以及使用flushCache
、useCache
等屬性管理緩存。<insert>
:用于執(zhí)行INSERT
語(yǔ)句向數(shù)據(jù)庫(kù)中插入數(shù)據(jù)。配置屬性包括id
、parameterType
(插入數(shù)據(jù)對(duì)象的類型)??梢栽O(shè)置useGeneratedKeys
和keyProperty
(或keyColumn
)來(lái)啟用自動(dòng)增長(zhǎng)主鍵并將其值映射到指定的Java屬性上。statementType
屬性可以指定語(yǔ)句類型,如STATEMENT
、PREPARED
或CALLABLE
。<update>
:定義UPDATE
語(yǔ)句,用于更新數(shù)據(jù)庫(kù)中的記錄。同樣具有id
、parameterType
屬性,指定更新操作的唯一標(biāo)識(shí)和傳入?yún)?shù)類型。可以設(shè)置flushCache
屬性決定是否刷新二級(jí)緩存。<delete>
:定義DELETE
語(yǔ)句,刪除數(shù)據(jù)庫(kù)中的數(shù)據(jù)。包含id
、parameterType
屬性,分別表示操作標(biāo)識(shí)和刪除條件所對(duì)應(yīng)的參數(shù)類型。通常也支持flushCache
屬性以控制緩存刷新。<sql>
:定義可重用的SQL片段,其中的SQL語(yǔ)句可以被其他元素(如<select>
、<insert>
等)通過include
屬性引用。有助于減少重復(fù)編寫相同的SQL子句,提高代碼復(fù)用性。<resultMap>
:定義結(jié)果集映射規(guī)則,將查詢結(jié)果與Java對(duì)象的屬性進(jìn)行關(guān)聯(lián)。包括id
(唯一標(biāo)識(shí)該結(jié)果映射)、type
(結(jié)果對(duì)象的全限定類名或別名)??梢酝ㄟ^<id>
、<result>
、<association>
、<collection>
等子元素詳細(xì)描述如何將查詢結(jié)果的列映射到對(duì)象的屬性、嵌套對(duì)象或集合屬性上。<parameterMap>
:注意: 在較新版本的MyBatis中,已不再推薦使用<parameterMap>
,而是直接使用parameterType
屬性。老版本中用于定義輸入?yún)?shù)的映射規(guī)則,與<resultMap>
類似,但主要用于處理復(fù)雜的參數(shù)結(jié)構(gòu)。新版本中通常直接使用parameterType
屬性指定參數(shù)類型。<cache>
:定義二級(jí)緩存配置,可以設(shè)置緩存的類型、大小、超時(shí)策略、清除策略等屬性。適用于那些查詢結(jié)果相對(duì)穩(wěn)定且希望在多次請(qǐng)求之間共享結(jié)果的場(chǎng)景。<cache-ref>
:引用其他命名空間中定義的緩存配置,避免重復(fù)定義。通過namespace
屬性指定要引用的緩存配置所在的命名空間。這些元素構(gòu)成了MyBatis映射器的基本構(gòu)建塊,通過它們可以靈活地配置各種數(shù)據(jù)庫(kù)操作,并精確地控制SQL語(yǔ)句的執(zhí)行、參數(shù)傳遞、結(jié)果映射以及緩存策略等細(xì)節(jié)。在實(shí)際使用中,可以根據(jù)業(yè)務(wù)需求選擇合適的元素組合來(lái)實(shí)現(xiàn)高效的數(shù)據(jù)庫(kù)訪問
Select元素
<select>
元素在 MyBatis 映射器配置文件中用于定義 SQL SELECT 查詢語(yǔ)句及其相關(guān)屬性。以下是<select>
元素常見的屬性及其詳細(xì)解釋:
id
:必填屬性,它和Mapper的命名空間組合起來(lái)是唯一的,形成唯一標(biāo)識(shí)符,供MyBatis調(diào)用,比如:id="getUserById"
parameterType
:可選屬性,用于指定傳入查詢語(yǔ)句的參數(shù)類型,可以是全限定類名或也可以是類型別名,但必須是MyBatis的內(nèi)置別名或者自定義別名,當(dāng)查詢需要接受參數(shù)時(shí),使用此屬性聲明參數(shù)類型,參數(shù)可以是簡(jiǎn)單類型(如 int、String),復(fù)雜類型(如自定義 Java Bean),或者 Map 類型。若使用類型別名,需在全局配置文件或當(dāng)前映射文件中提前定義。resultType
:可選屬性,用于指定查詢結(jié)果的預(yù)期類型。
格式:全限定類名或類型別名,在允許自動(dòng)匹配的情況下,結(jié)果集將通過Java Bean的規(guī)范映射,或者定義為int、double、float、map等參數(shù);當(dāng)查詢結(jié)果是一條記錄映射到單個(gè)對(duì)象時(shí),使用此屬性指定對(duì)象類型。MyBatis 會(huì)自動(dòng)將查詢結(jié)果的每一行數(shù)據(jù)映射到指定類型的對(duì)象實(shí)例。若使用類型別名,需在全局配置文件或當(dāng)前映射文件中提前定義(不能和resultMap
同時(shí)使用)resultMap
:可選屬性,其作用是引用已定義的<resultMap>
,用于定制更復(fù)雜的查詢結(jié)果映射規(guī)則,應(yīng)與<resultMap>
元素的id
屬性值匹配;當(dāng)查詢結(jié)果需要進(jìn)行精細(xì)的列到屬性映射,或者涉及嵌套結(jié)果集、聯(lián)合查詢、自動(dòng)關(guān)聯(lián)等復(fù)雜情況時(shí),使用此屬性替代 resultType,指定的 必須在同一映射文件中預(yù)先定義。flushCache
:可選屬性,其作用是控制是否在調(diào)用SQL后要求MyBatis清空之前查詢的本地緩存和二級(jí)緩存,默認(rèn)值:false(默認(rèn)情況下,查詢不會(huì)刷新緩存)useCache
:可選屬性,指示是否對(duì)查詢結(jié)果啟用二級(jí)緩存。默認(rèn)值:true(默認(rèn)情況下,查詢結(jié)果會(huì)被緩存)timeout
:可選屬性,設(shè)置查詢語(yǔ)句的超時(shí)時(shí)間(單位:秒),默認(rèn)值由JDBC驅(qū)動(dòng)或全局配置中的 defaultStatementTimeout 決定。fetchSize
:可選屬性,為 JDBC Statement 設(shè)置預(yù)取結(jié)果集的大小,默認(rèn)值由JDBC 驅(qū)動(dòng)決定。statementType
:較少使用,用來(lái)指定執(zhí)行 SQL 語(yǔ)句的方式,默認(rèn)值:PREPARED(預(yù)編譯語(yǔ)句)有3個(gè)選項(xiàng):STATEMENT:靜態(tài) SQL(非預(yù)編譯)、PREPARED:預(yù)編譯語(yǔ)句(推薦)、CALLABLE:存儲(chǔ)過程調(diào)用resultOrdered
:較少使用,其作用是指示 MyBatis 是否應(yīng)該保持結(jié)果集的順序與 SQL 中 ORDER BY 子句指定的順序一致。默認(rèn)值:false(默認(rèn)情況下,MyBatis 不保證結(jié)果集順序與 ORDER BY 完全一致)resultSetType
:較少使用其作用是指定 ResultSet 的類型(僅在使用 STATEMENT 語(yǔ)句類型時(shí)有意義)默認(rèn)值:FORWARD_ONLY(默認(rèn)情況下,使用只進(jìn)游標(biāo)),選項(xiàng)包括:FORWARD_ONLY:只進(jìn)游標(biāo)(不可回滾)、SCROLL_SENSITIVE:敏感滾動(dòng)游標(biāo)(可回滾,但可能無(wú)法看到其他事務(wù)的最新更改)、SCROLL_INSENSITIVE:不敏感滾動(dòng)游標(biāo)(可回滾,且不受其他事務(wù)更改影響)resultSets
::極少使用,其作用是當(dāng)查詢語(yǔ)句返回多個(gè)結(jié)果集或光標(biāo)時(shí),使用此屬性指定結(jié)果集的名稱或索引。
總結(jié)起來(lái),<select>
元素的主要屬性用于定義查詢語(yǔ)句的身份標(biāo)識(shí)、輸入?yún)?shù)類型、輸出結(jié)果映射方式、緩存策略、查詢超時(shí)、預(yù)取大小等執(zhí)行特性。這些屬性幫助開發(fā)者精細(xì)控制查詢行為,確保與數(shù)據(jù)庫(kù)交互的高效性和靈活性。在實(shí)際應(yīng)用中,最常用的屬性通常是id
、parameterType
、resultType
或 resultMap
、flushCache
和 useCache
其他屬性在特定場(chǎng)景下可能會(huì)發(fā)揮作用,但并不常用。
Select元素實(shí)例 單個(gè)參數(shù)
<select id="countUserByFirstName" parameterType="string" resultType="int"> select count(*) total from t_user where user_name like concat ('%',#{firstName, jdbcType=VARCHAR, javaType=String},'%') </select>
SQL很容易懂,里邊的元素可以參考對(duì)應(yīng)上邊每一項(xiàng)的解釋理解,有了SQL,就需要對(duì)應(yīng)的Mapper接口和方法(也就是Dao Data Access Object)public Integer countUserByFirstName(String firstName)
在MyBatis的配置文件的settings元素中,有autoMappingBehavior和mapUnderscoreToCamelCase兩個(gè)可配置的選項(xiàng),他們是控制自動(dòng)映射和駝峰映射的開關(guān),一般來(lái)說自動(dòng)映射會(huì)用的多一些,這樣可以使用SQL的別名機(jī)制,更加靈活,而駝峰映射要求比較嚴(yán)格;autoMappingBehavior配置項(xiàng)有3個(gè)選擇,NONE表示不自動(dòng)映射,PARTIAL是默認(rèn)值,表示只對(duì)沒有嵌套的結(jié)果集自動(dòng)映射,F(xiàn)ULL表示對(duì)所有的結(jié)果集自動(dòng)映射包括嵌套結(jié)果集,通常默認(rèn)即可
假設(shè)我們有如下這么一個(gè)POJO
package com.ssm.pojo; import org.apache.ibatis.type.Alias; @Alias("role") public class Role{ private int id; private String roleName; private String note; /** setters and getters */ }
在這個(gè)POJO里有三個(gè)屬性id、roleName、note,如果在Mapper里編寫SQL列名和屬性名保持一致,它就會(huì)形成自動(dòng)映射,例如
<select id="getRole" parameterType="int" resultType="role"> select id, role_name as roleName, note from t_role where id = #{id} </select>
列名role_name被別名roleName代替了,和POJO上的屬性名保持一致,如此MyBatis就能將查詢結(jié)果集和POJO的屬性一一對(duì)應(yīng),自動(dòng)完成映射無(wú)需再進(jìn)行任何配置
如果嚴(yán)格按照駝峰命名法,比如數(shù)據(jù)庫(kù)字段為role_name,POJO屬性名為roleName,數(shù)據(jù)庫(kù)字段名為user_name,POJO屬性名為userName,那么只要在配置項(xiàng)把mapUnderscoreToCamelCase設(shè)置為true即可,如果這樣,那么SQL就可以寫成
select id, role_name, note from t_role where id = #{id}
MyBatis會(huì)嚴(yán)格按照駝峰命名的方式自動(dòng)映射,只是這樣要求數(shù)據(jù)字段和POJO的屬性名嚴(yán)格對(duì)應(yīng)
自動(dòng)映射和駝峰映射都建立在SQL列名和POJO屬性名的映射關(guān)系上,在實(shí)際使用中會(huì)更復(fù)雜,比如可能有些字段有主表和從表關(guān)聯(lián)的級(jí)聯(lián)關(guān)系,又比如typeHandler的轉(zhuǎn)換規(guī)則復(fù)雜,此時(shí)resultType元素?zé)o法滿足這些需求需要更強(qiáng)大的映射規(guī)則需要考慮使用resultMap等等
Select元素實(shí)例 使用Map傳遞多個(gè)參數(shù)
假設(shè)有這樣一個(gè)Mapper接口定義,它通過鍵值對(duì)傳遞多個(gè)參數(shù)
public List<Role> findRolesByMap(Map<String, Object>parameterMap);
此時(shí)傳遞給映射器的一個(gè)Map對(duì)象,使用它在SQL中設(shè)置對(duì)應(yīng)的參數(shù),如下所示
<select id="findRoleByMap" parameterType="map" resultType="role"> select id, role_name as roleName, note from t_role where role_name like concat('%', #{roleName}, '%') and note like concat('%', #{note},'%') </select>
這里使用兩個(gè)數(shù)據(jù)庫(kù)字段進(jìn)行了一個(gè)模糊查詢,傳參方式是使用map,執(zhí)行代碼如下所示
RoleDao roleDao = sqlSession.getMapper(RoleDao.class); Map<String, Object>parameterMap = new HashMap<>(); parameterMap.put("roleName", "1"); parameterMap.put("note","1"); List<Role> roleList = roleDao.findRolesByMap(parameterMap);
嚴(yán)格來(lái)說Map幾乎適用于所有場(chǎng)景,但其可讀性比較差,且不能限定其傳遞的數(shù)據(jù)類型
Select元素實(shí)例 使用注解傳遞多個(gè)參數(shù)
MyBatis提供了@Param(org.apache.ibatis.annotations.Param),可以通過它定義映射器的參數(shù)名稱,如下代碼所示
public List<Role> findRolesByAnnotation(@Param("roleName") String roleName, @Param("note") String note);
Mapper文件如下所示
<select id="findRolesByAnnotation" "resultType="role"> select id, role_name as roleName, note from t_role where role_name like concat('%', #{roleName}, '%') and note like concat('%', #{note},'%') </select>
Select元素實(shí)例 使用JavaBean傳遞多個(gè)參數(shù)
先定義一個(gè)POJO
package com.ssm.pojo.parameter; public class RoleParams{ private String roleName; private String note; /** setter and getter */ }
把Mapper接口定義為
public List<Role> findRolesByBean(RoleParams roleParam);
Mapper文件如下所示
<select id="findRolesByBean" "resultType="role" parameterType="com.ssm.pojo.parameter.RoleParams"> select id, role_name as roleName, note from t_role where role_name like concat('%', #{roleName}, '%') and note like concat('%', #{note},'%') </select>
執(zhí)行代碼如下
sqlSession = SqlSessionFactoryUtils.openSqlSession(); RoleDao roleDao = sqlSession.getMapper(RoleDao.class); RoleParams roleParams = new RoleParams(); roleParams.setNote("1"); roleParams.setRoleName("1"); List<Role>roleList = roleDao.findRolesByBean(roleParams);
在某些場(chǎng)景下也會(huì)混合使用,例如通過角色名稱和備注查詢角色,同時(shí)需要支持分頁(yè)
分頁(yè)的POJO如下定義
package com.ssm.pojo.parameter; public class PageParams{ private int start; private int limit; /** setters and getters */ }
Mapper接口如下
public List<Role> findByMix(@Param("params") RoleParams roleParams, @Param("page") PageParams PageParam);
Mapper文件如下寫法
<select id="findByMix" "resultType="role"> select id, role_name as roleName, note from t_role where role_name like concat('%', #{params.roleName}, '%') and note like concat('%', #{params.note},'%') limit #{page.start}, #{page.limit} </select>
MyBatis對(duì)params和page這類JavaBean參數(shù)提供EL(中間語(yǔ)言)支持,為編程帶來(lái)了很多便利
結(jié)果集映射resultMap
自動(dòng)映射和駝峰映射規(guī)則比較簡(jiǎn)單,無(wú)法定義更多的屬性和滿足復(fù)雜的場(chǎng)景,例如枚舉需要typeHandler,還有數(shù)據(jù)級(jí)聯(lián)等等,因此select元素提供了resultMap屬性,用于指定具體的resultMap作為映射規(guī)則,如下定義所示
<result Map id="roleMap" type="role"> <id property="id" column="id"/> <result property="roleName" column="role_name"/> <result property="note" column="ntoe"/> </resultMap> <select id="getRoleUserResultMap" parameterType="int" resultMap="roleMap"> select id, role_name, note from t_role where id = #{id} </select>
<!-- 定義結(jié)果映射,用于將數(shù)據(jù)庫(kù)中的數(shù)據(jù)映射成Role對(duì)象 --> <resultMap id="userMap" type="com.ssm.pojo.User"> <id property="userid" column="userid"/> <!-- 主鍵映射 --> <result property="username" column="username"/> <!-- 角色名映射 --> <result property="password" column="password"/> <!-- 備注映射 --> <result property="sex" column="sex"/> <result property="phone" column="phone"/> <result property="email" column="email"/> <result property="phonenumber" column="phonenumber"/> <result property="comment" column="comment"/> </resultMap>
<!-- 定義結(jié)果映射,用于將數(shù)據(jù)庫(kù)中的數(shù)據(jù)映射成Role對(duì)象 --> <resultMap id="roleMap" type="com.ssm.pojo.Role"> <id property="id" column="id"/> <!-- 主鍵映射 --> <result property="roleName" column="roleName"/> <!-- 角色名映射 --> <result property="note" column="note" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/> <!-- 備注映射 --> </resultMap>
分頁(yè)參數(shù)RowBounds
MyBatis不僅支持分頁(yè),還內(nèi)置了一個(gè)專門處理分頁(yè)的類RowBounds,如下代碼所示
/** * RowBounds類用于設(shè)置SQL查詢的偏移量和限制結(jié)果集的大小。 */ package org.apache.ibatis.session; public class RowBounds { // 無(wú)偏移量,無(wú)限制的行數(shù) public static final int NO_ROW_OFFSET = 0; // 最大整數(shù)2147483647 public static final int NO_ROW_LIMIT = Integer.MAX_VALUE; // 默認(rèn)的RowBounds實(shí)例,無(wú)偏移,無(wú)限制 public static final RowBounds DEFAULT = new RowBounds(); private final int offset; // 偏移量,從第幾行開始 private final int limit; // 限制返回的行數(shù) /** * 構(gòu)造函數(shù),默認(rèn)偏移量為0,限制的行數(shù)為最大整數(shù)值。 */ public RowBounds() { this.offset = 0; this.limit = Integer.MAX_VALUE; } /** * 構(gòu)造函數(shù),設(shè)置自定義的偏移量和限制的行數(shù)。 * * @param offset 查詢結(jié)果的偏移量,即從第幾行開始。 * @param limit 返回結(jié)果集的最大行數(shù)。 */ public RowBounds(int offset, int limit) { this.offset = offset; this.limit = limit; } /** * 獲取偏移量。 * * @return 偏移量,從第幾行開始。 */ public int getOffset() { return this.offset; } /** * 獲取限制的行數(shù)。 * * @return 返回結(jié)果集的最大行數(shù)。 */ public int getLimit() { return this.limit; } }
Mapper接口定義如下
public List<Role> findByRowBounds(@Param("roleName") String rolename, @Param("note") String note, RowBounds rowBounds);
Mapper映射文件如下
<select id="findByRowBounds" resultType="role"> select id, role_name as roleName, note from t_role where role_name like concat('%', #{roleName}, '%') and note like concat('%', #{note}, '%') </select>
映射代碼中沒有任何關(guān)于RowBounds參數(shù)的信息,MyBatis自身會(huì)自動(dòng)識(shí)別和啟用它
執(zhí)行代碼如下
Logger log = Logger.getLogger(Main.class); SqlSession sqlsession = null; try{ sqlsession = SqlSessionFacotryUtils.openSqlSession(); RoleDao roleDao = sqlSession.getMapper(RoleDao.class); List<Role> roleList = roleDao.findByRowBounds("role", "note", new RownBounds(0,20)); log.info(roleList.size()); }finally{ if(sqlSession!=null){ sqlSession.close(); } }
RowBounds分頁(yè)一般來(lái)說只適合做少量數(shù)據(jù)的分頁(yè),其原理是在執(zhí)行SQL的查詢后,根據(jù)偏移量和限制條數(shù)返回結(jié)果,因此大量的數(shù)據(jù)查詢性能會(huì)比較差
insert元素
在MyBatis框架中,<insert>
標(biāo)簽用于定義SQL插入語(yǔ)句。以下是其常用的屬性及其說明:
- id:作為命名空間內(nèi)的唯一標(biāo)識(shí)符,與Mapper接口中的方法名相對(duì)應(yīng),用于MyBatis在執(zhí)行時(shí)找到對(duì)應(yīng)的SQL語(yǔ)句。
<insert id="insertUser" ...>
,在同一個(gè)Mapper的XML文件中,id屬性值必須唯一,否則MyBatis在解析時(shí)會(huì)拋出異常。 - parameterType:指定傳入SQL語(yǔ)句的參數(shù)類型,通常是一個(gè)Java類的全限定名(如包名加類名)或別名。支持基本數(shù)據(jù)類型、JavaBean對(duì)象、Map等復(fù)雜數(shù)據(jù)類型。
<insert parameterType="com.example.User" ...>
,MyBatis可以根據(jù)參數(shù)對(duì)象的屬性名自動(dòng)映射到SQL語(yǔ)句中的占位符(如${}或#{}),無(wú)需手動(dòng)指定每一個(gè)參數(shù)。 - useGeneratedKeys:表示是否啟用JDBC的getGeneratedKeys方法來(lái)獲取數(shù)據(jù)庫(kù)自動(dòng)生成的主鍵。默認(rèn)值為false。
<insert useGeneratedKeys="true" ...>
,當(dāng)數(shù)據(jù)庫(kù)表有自增主鍵或其他自動(dòng)生成的主鍵時(shí),設(shè)置為true可以讓MyBatis自動(dòng)獲取并返回生成的主鍵值。這需要數(shù)據(jù)庫(kù)驅(qū)動(dòng)和數(shù)據(jù)庫(kù)本身支持該功能。 - keyProperty:當(dāng)
useGeneratedKeys="true"
時(shí),此屬性指定插入后生成的主鍵值應(yīng)該賦給傳入?yún)?shù)對(duì)象(parameterType指定的對(duì)象)的哪個(gè)屬性。如果主鍵是復(fù)合主鍵,可以使用逗號(hào)分隔多個(gè)屬性名。<insert keyProperty="id" ...> 或 <insert keyProperty="primaryKey1, primaryKey2" ...>
,只有當(dāng)useGeneratedKeys="true"且數(shù)據(jù)庫(kù)支持時(shí),keyProperty才生效。否則,即使指定了該屬性,也不會(huì)有任何效果。 - statementType:指定語(yǔ)句的執(zhí)行類型??蛇x值包括STATEMENT、PREPARED(默認(rèn))和CALLABLE。分別對(duì)應(yīng)使用JDBC的Statement、PreparedStatement和CallableStatement。
<insert statementType="PREPARED" ...>
,通常情況下,保持默認(rèn)的PREPARED即可,因?yàn)樗芊乐筍QL注入攻擊,并允許預(yù)編譯SQL語(yǔ)句提高性能。除非有特定需求,否則不需要更改此屬性。 - flushCache:控制是否在執(zhí)行插入操作后刷新MyBatis的一級(jí)緩存(本地Session緩存)。默認(rèn)值為true,即每次插入后清空緩存。
<insert flushCache="false" ...>
,若希望在插入后保留緩存以優(yōu)化后續(xù)查詢,可以設(shè)置為false。但請(qǐng)注意,這可能會(huì)影響數(shù)據(jù)的一致性,特別是多事務(wù)并發(fā)環(huán)境下,需要謹(jǐn)慎使用。 - timeout:設(shè)置執(zhí)行語(yǔ)句的超時(shí)時(shí)間(單位:秒)。超過這個(gè)時(shí)間仍未得到數(shù)據(jù)庫(kù)響應(yīng)時(shí),MyBatis將拋出異常。
<insert timeout="30" ...>
注意: 根據(jù)數(shù)據(jù)庫(kù)操作的實(shí)際耗時(shí)和系統(tǒng)對(duì)響應(yīng)時(shí)間的要求來(lái)合理設(shè)置。過短可能導(dǎo)致正常操作因超時(shí)而失敗,過長(zhǎng)則可能導(dǎo)致應(yīng)用響應(yīng)緩慢。 - keyColumn:僅對(duì)于insert和update有用,通過生成的鍵值設(shè)置表中的列名,這些設(shè)置僅在某些數(shù)據(jù)庫(kù)如PG中是必須的,當(dāng)主鍵列不是表中的第一列時(shí)需要設(shè)置,如果是復(fù)合主鍵,則需要再把沒一個(gè)名稱用逗號(hào)隔開
- 其他:parameterMap、databaseId
insert元素實(shí)例自增主鍵場(chǎng)景
<!-- 插入一個(gè)新的Role記錄 --> <insert id="insertRole" parameterType="com.ssm.pojo.Role" databaseId="mysql" > INSERT INTO t_role(roleName, note) VALUES (#{roleName}, #{note}) </insert>
這個(gè)語(yǔ)句非常簡(jiǎn)單,因?yàn)楸淼膇d只自增主鍵,因此在插入數(shù)據(jù)的時(shí)候并沒有為該字段做任何事,數(shù)據(jù)庫(kù)會(huì)自動(dòng)完成,但實(shí)際開發(fā)過程中往往插入一條記錄,需要根據(jù)當(dāng)前表的主鍵值處理關(guān)聯(lián)表,MyBatis中可以通過getGeneratedKeys
方法獲得數(shù)據(jù)庫(kù)生成的主鍵,默認(rèn)它是false狀態(tài),也就是不會(huì)返回主鍵值,當(dāng)打開了這個(gè)開關(guān)后,還需要配置其屬性keyProperty
或keyColumn
,從而告訴系統(tǒng)把生成的主鍵放入POJO的對(duì)應(yīng)屬性中,如果存在多個(gè)主鍵,就要用逗號(hào)將他們分隔
<!-- 插入一個(gè)新的Role記錄 參數(shù): - parameterType: 指定插入操作時(shí)使用的參數(shù)類型,這里是 com.ssm.pojo.Role,表示插入的角色對(duì)象。 - databaseId: 指定該SQL語(yǔ)句適用于哪個(gè)數(shù)據(jù)庫(kù),這里是 mysql。 - useGeneratedKeys: 指定是否使用數(shù)據(jù)庫(kù)自動(dòng)生成的鍵值。如果為 true,則表示使用自動(dòng)生成的鍵值。 - keyProperty: 指定生成的鍵值應(yīng)該被設(shè)置到對(duì)象的哪個(gè)屬性上,這里是 id。 返回值: 無(wú)返回值,僅執(zhí)行插入操作。 --> <insert id="insertRole" parameterType="com.ssm.pojo.Role" databaseId="mysql" useGeneratedKeys="true" keyProperty="id" > INSERT INTO t_role(roleName, note) VALUES (#{roleName}, #{note}) </insert>
如此,將useGeneratedKeys配置為true表示采用JDBC的Statement對(duì)象的getGeneratedKeys方法返回主鍵,而keyProperty代表用哪個(gè)POJO的屬性匹配這個(gè)主鍵,這個(gè)例子里是id,說明它會(huì)用數(shù)據(jù)生成的主鍵賦值給這個(gè)POJO的屬性id
insert元素實(shí)例自定義主鍵場(chǎng)景
有時(shí)候主鍵未必是自增的,而是依賴于某些規(guī)則,例如取消角色表的id自增規(guī)則,將其規(guī)則改為當(dāng)角色表記錄為空時(shí)id設(shè)置為1,當(dāng)角色表記錄不為空時(shí),id設(shè)置為當(dāng)前id加3,對(duì)于這樣的特殊規(guī)則主鍵的場(chǎng)景,MyBatis也提供了支持,它主要依賴selectKey元素,允許自定義鍵值生成規(guī)則
<!-- 插入一個(gè)新的Role記錄 參數(shù): - parameterType: 指定插入操作時(shí)使用的參數(shù)類型,這里是com.ssm.pojo.Role,代表插入的角色對(duì)象。 - databaseId: 指定此SQL適用于哪個(gè)數(shù)據(jù)庫(kù),這里是mysql。 - useGeneratedKeys: 指定是否使用數(shù)據(jù)庫(kù)生成的主鍵值。如果為true,MyBatis會(huì)自動(dòng)獲取生成的主鍵值并設(shè)置到對(duì)象中。 - keyProperty: 指定哪個(gè)屬性會(huì)接收生成的主鍵值,這里是id。 返回值: 插入操作成功后,返回值為插入的記錄的主鍵ID。 --> <insert id="insertRole" parameterType="com.ssm.pojo.Role" databaseId="mysql" useGeneratedKeys="true" keyProperty="id" > <!-- 使用selectKey標(biāo)簽來(lái)動(dòng)態(tài)生成主鍵ID。在插入新記錄之前執(zhí)行,通過查詢當(dāng)前角色表中最大ID值,若不存在則默認(rèn)為1,若存在則在最大ID上加3,以保證ID的唯一性。 --> <selectKey keyProperty="id" resultType="int" order="BEFORE"> select if (max(id) = null, 1, max(id) + 3) from t_role </selectKey> <!-- 插入新的Role記錄,#{id}, #{roleName}, #{note}分別代表角色的ID,角色名和備注信息。這些值會(huì)從傳入的Role對(duì)象中獲取。 --> INSERT INTO t_role(id, roleName, note) VALUES (#{id}, #{roleName}, #{note}) </insert>
其他的很容易看明白,唯獨(dú)這個(gè)order,設(shè)置為BEFORE,說明它將于當(dāng)前定義的SQL前執(zhí)行,也就是它會(huì)在插入數(shù)據(jù)前生成主鍵的SQL,如果還有一些需要在SQL執(zhí)行后的動(dòng)作,例如插入語(yǔ)句內(nèi)部可能有嵌入索引調(diào)用,這樣可以把它設(shè)置為AFTER,就會(huì)在執(zhí)行插入后再完成任務(wù)
update元素和delete元素
<!-- 更新Role的信息 --> <!-- 函數(shù)級(jí)別注釋:該標(biāo)簽用于更新Role表中的信息。 參數(shù): - roleName: 角色名,類型為String,用于更新角色的名稱。 - note: 備注信息,類型為String,用于更新角色的備注。 - id: 角色I(xiàn)D,類型為Integer,用于指定要更新的角色。 返回值:無(wú)返回值。 --> <update id="updateRole" parameterType="com.ssm.pojo.Role"> UPDATE t_role SET roleName = #{roleName}, note = #{note} WHERE id = #{id} </update> <!-- 函數(shù)級(jí)別塊注釋: 根據(jù)提供的ID刪除數(shù)據(jù)庫(kù)中特定的Role記錄。 參數(shù): id - 需要?jiǎng)h除的Role記錄的ID,類型為int。 返回值: 無(wú)返回值。 --> <delete id="deleteRole" parameterType="int"> DELETE FROM t_role WHERE id = #{id} </delete>
sql元素
在實(shí)際開發(fā)過程中,往往很多表的列都非常多,在編寫代碼的時(shí)候,重復(fù)寫列名是個(gè)很枯燥的事情,即便編譯器提供了很多方法,但還是很麻煩,MyBatis提供了sql元素,簡(jiǎn)化了該場(chǎng)景下的編碼工作
<!-- 定義查詢角色信息時(shí)需要返回的列名 --> <sql id = "roleCols"> id, roleName, note </sql> <!-- 根據(jù)ID查詢Role信息,返回Role對(duì)象。該查詢針對(duì)Oracle數(shù)據(jù)庫(kù)。 --> <select id="getRoleById" parameterType="int" resultMap="roleMap" databaseId="oracle"> SELECT <include refid="roleCols"/>FROM t_role WHERE id = #{id} </select> <!-- 插入新的Role信息。在插入前,通過selectKey為新Role生成一個(gè)唯一的ID。 --> <insert id="insertRole" parameterType="com.ssm.pojo.Role"> <selectKey keyProperty="id" resultType="int" order="BEFORE" statementType="PREPARED"> select if (max(id) = null, 1, max(id)+3) from t_role </selectKey> insert into t_role(<include refid="roleCols"/>) values(#{id}, #{roleName}, #{note}) </insert>
sql元素還支持變量傳遞
<!-- 定義一個(gè)SQL片段,用于查詢角色表中的id、roleName和note列 --> <!-- 通過傳入的別名(alias)動(dòng)態(tài)拼接SQL語(yǔ)句中的表名前綴 --> <sql id ="roleCols2"> ${alias}.id, ${alias}.roleName, ${alias}.note} </sql> <!-- 根據(jù)ID查詢Role信息,返回Role對(duì)象。該查詢針對(duì)Oracle數(shù)據(jù)庫(kù)。 --> <select id="getRoleById" parameterType="int" resultMap="roleMap" databaseId="oracle"> SELECT <include refid="roleCols"> <property name="alias" value="r"/> </include> FROM t_role r WHERE id = #{id} </select>
include元素中定義了一個(gè)“alias”的變量,其值是SQL中表t_role的別名“r”,sql元素可以通過EL引用這個(gè)變量
到此這篇關(guān)于深入淺出MyBatis映射器的文章就介紹到這了,更多相關(guān)MyBatis映射器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Boot實(shí)現(xiàn)文件上傳示例代碼
本篇文章主要介紹了Spring Boot實(shí)現(xiàn)文件上傳示例代碼,可以實(shí)現(xiàn)單文件和多文件的上傳,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-03-03java struts2學(xué)習(xí)筆記之線程安全
這篇文章主要為大家詳細(xì)介紹了java struts2學(xué)習(xí)筆記之線程安全,感興趣的朋友可以參考一下2016-04-04java 如何給對(duì)象中的包裝類設(shè)置默認(rèn)值
這篇文章主要介紹了java 如何給對(duì)象中的包裝類設(shè)置默認(rèn)值,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03SpringBoot概述及在idea中創(chuàng)建方式
SpringBoot提供了一種快速使用Spring的方式,基于約定大于配置的思想,可以讓開發(fā)人員不必在配置與邏輯業(yè)務(wù)之間進(jìn)行思維的切換,這篇文章主要介紹了SpringBoot概述及在idea中創(chuàng)建方式,需要的朋友可以參考下2022-09-09解析web.xml中在Servlet中獲取context-param和init-param內(nèi)的參數(shù)
本篇文章是對(duì)web.xml中在Servlet中獲取context-param和init-param內(nèi)的參數(shù)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-07-07Spring Boot Actuator監(jiān)控端點(diǎn)小結(jié)
這篇文章主要介紹了Spring Boot Actuator監(jiān)控端點(diǎn)小結(jié),需要的朋友可以參考下2017-06-06通過jenkins發(fā)布java項(xiàng)目到目標(biāo)主機(jī)上的詳細(xì)步驟
這篇文章主要介紹了通過jenkins發(fā)布java項(xiàng)目到目標(biāo)主機(jī)上的詳細(xì)步驟,發(fā)布java項(xiàng)目的步驟很簡(jiǎn)單,通過拉取代碼并打包,備份目標(biāo)服務(wù)器上已有的要發(fā)布項(xiàng)目,具體內(nèi)容詳情跟隨小編一起看看吧2021-10-10