MyBatis 是一款優(yōu)秀的持久層框架荡含,它支持定制化 SQL、存儲過程以及高級映射届垫。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設(shè)置參數(shù)以及獲取結(jié)果集释液。MyBatis 可以使用簡單的 XML 或注解來配置和映射原生信息,將接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java對象)映射成數(shù)據(jù)庫中的記錄装处。
無論是使用注解還是 xml 映射文件配置方式误债,在使用之前有兩步是必須的:
-
引入依賴
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency>
-
在啟動類上加注解
@MapperScan
指明 mapper 類的位置@MapperScan("com.solo.coderiver.project.mapper") public class ProjectApplication { public static void main(String[] args) { SpringApplication.run(ProjectApplication.class, args); } }
一、注解方式
相比于 xml 映射方式妄迁,注解方式明顯更簡潔寝蹈,但沒有 xml 方式靈活。目前大部分公司還是主要用 xml 方式登淘。
package com.solo.coderiver.project.mapper;
import com.solo.coderiver.project.dataobject.ProjectInfo;
import org.apache.ibatis.annotations.*;
/**
* 注解方式使用 mybatis 增刪改查
*/
@Mapper
public interface ProjectMapper {
@Select("SELECT * FROM project_info WHERE project_id = #{id}")
@Results({
@Result(property = "projectId", column = "project_id"),
@Result(property = "projectName", column = "project_name"),
@Result(property = "projectAvatar", column = "project_avatar"),
@Result(property = "projectDifficulty", column = "project_difficulty"),
@Result(property = "categoryType", column = "category_type"),
@Result(property = "categoryName", column = "category_name"),
@Result(property = "projectProgress", column = "project_progress"),
@Result(property = "projectStatus", column = "project_status"),
@Result(property = "projectIntroduce", column = "project_introduce"),
@Result(property = "projectCreatorId", column = "project_creator_id"),
@Result(property = "teamId", column = "team_id"),
})
ProjectInfo findProjectById(String id);
@Insert("INSERT INTO " +
"project_info(project_id, project_name, project_avatar, project_difficulty," +
" category_type, category_name, project_progress, project_status, " +
"project_introduce, project_creator_id, team_id) " +
"VALUES(#{projectId}, #{projectName}, #{projectAvatar}, #{projectDifficulty}," +
"#{categoryType}, #{categoryName}, #{projectProgress}, #{projectStatus}," +
"#{projectIntroduce}, #{projectCreatorId}, #{teamId})")
int insertProject(ProjectInfo info);
@Update("UPDATE project_info set project_name = #{name} where project_id = #{id}")
int updateProjectName(String id, String name);
@Delete("DELETE FROM project_info WHERE project_id = #{id}")
int deleteProject(String id);
}
直接將 sql 語句寫在注解里箫老,免去了配置 xml 文件。但有個(gè)顯而易見的缺點(diǎn)是如果 sql 太長了黔州,像字段多的 @Insert
耍鬓,如果換行需要用 +
連接,不利于后期維護(hù)流妻。
MyBatis 支持的注解屬性表:
注解 | 使用對象 | 相對應(yīng)的 XML | 描述 |
---|---|---|---|
@CacheNamespace |
類 |
<cache> |
為給定的命名空間(比如類)配置緩存牲蜀。屬性有:implemetation , eviction , flushInterval , size , readWrite , blocking 和properties 。 |
@Property |
N/A | <property> |
指定參數(shù)值或占位值(placeholder)(能被 mybatis-config.xml 內(nèi)的配置屬性覆蓋)绅这。屬性有:name , value 涣达。(僅在MyBatis 3.4.2以上版本生效) |
@CacheNamespaceRef |
類 |
<cacheRef> |
參照另外一個(gè)命名空間的緩存來使用。屬性有:value , name 。如果你使用了這個(gè)注解峭判,你應(yīng)設(shè)置 value 或者 name 屬性的其中一個(gè)。value 屬性用于指定 Java 類型而指定命名空間(命名空間名就是指定的 Java 類型的全限定名)棕叫,name 屬性(這個(gè)屬性僅在MyBatis 3.4.2以上版本生效)直接指定了命名空間的名字林螃。 |
@ConstructorArgs |
方法 |
<constructor> |
收集一組結(jié)果傳遞給一個(gè)結(jié)果對象的構(gòu)造方法。屬性有:value 俺泣,它是形式參數(shù)數(shù)組疗认。 |
@Arg |
N/A |
<arg> <idArg>
|
單參數(shù)構(gòu)造方法,是 ConstructorArgs 集合的一部分伏钠。屬性有:id , column , javaType , jdbcType , typeHandler , select 和 resultMap 横漏。id 屬性是布爾值,來標(biāo)識用于比較的屬性熟掂,和<idArg> XML 元素相似缎浇。 |
@TypeDiscriminator |
方法 |
<discriminator> |
一組實(shí)例值被用來決定結(jié)果映射的表現(xiàn)。屬性有:column , javaType , jdbcType , typeHandler 和 cases 赴肚。cases 屬性是實(shí)例數(shù)組素跺。 |
@Case |
N/A | <case> |
單獨(dú)實(shí)例的值和它對應(yīng)的映射。屬性有:value , type , results 誉券。results 屬性是結(jié)果數(shù)組指厌,因此這個(gè)注解和實(shí)際的 ResultMap 很相似,由下面的 Results 注解指定踊跟。 |
@Results |
方法 |
<resultMap> |
結(jié)果映射的列表踩验,包含了一個(gè)特別結(jié)果列如何被映射到屬性或字段的詳情。屬性有:value , id 商玫。value 屬性是 Result 注解的數(shù)組箕憾。這個(gè) id 的屬性是結(jié)果映射的名稱。 |
@Result |
N/A |
<result> <id>
|
在列和屬性或字段之間的單獨(dú)結(jié)果映射拳昌。屬性有:id , column , javaType , jdbcType , typeHandler , one , many 厕九。id 屬性是一個(gè)布爾值,來標(biāo)識應(yīng)該被用于比較(和在 XML 映射中的<id> 相似)的屬性地回。one 屬性是單獨(dú)的聯(lián)系扁远,和 <association> 相似,而 many 屬性是對集合而言的刻像,和<collection> 相似畅买。它們這樣命名是為了避免名稱沖突。 |
@One |
N/A | <association> |
復(fù)雜類型的單獨(dú)屬性值映射细睡。屬性有:select 谷羞,已映射語句(也就是映射器方法)的全限定名,它可以加載合適類型的實(shí)例。fetchType 會覆蓋全局的配置參數(shù) lazyLoadingEnabled 湃缎。注意 聯(lián)合映射在注解 API中是不支持的犀填。這是因?yàn)?Java 注解的限制,不允許循環(huán)引用。 |
@Many |
N/A | <collection> |
映射到復(fù)雜類型的集合屬性嗓违。屬性有:select 九巡,已映射語句(也就是映射器方法)的全限定名,它可以加載合適類型的實(shí)例的集合蹂季,fetchType 會覆蓋全局的配置參數(shù) lazyLoadingEnabled 冕广。注意 聯(lián)合映射在注解 API中是不支持的。這是因?yàn)?Java 注解的限制偿洁,不允許循環(huán)引用 |
@MapKey |
方法 |
這是一個(gè)用在返回值為 Map 的方法上的注解撒汉。它能夠?qū)⒋娣艑ο蟮?List 轉(zhuǎn)化為 key 值為對象的某一屬性的 Map。屬性有: value 涕滋,填入的是對象的屬性名睬辐,作為 Map 的 key 值。 |
|
@Options |
方法 |
映射語句的屬性 | 這個(gè)注解提供訪問大范圍的交換和配置選項(xiàng)的入口宾肺,它們通常在映射語句上作為屬性出現(xiàn)溉委。Options 注解提供了通俗易懂的方式來訪問它們,而不是讓每條語句注解變復(fù)雜爱榕。屬性有:useCache=true , flushCache=FlushCachePolicy.DEFAULT , resultSetType=FORWARD_ONLY , statementType=PREPARED , fetchSize=-1 , timeout=-1 , useGeneratedKeys=false , keyProperty="id" , keyColumn="" , resultSets="" 瓣喊。值得一提的是, Java 注解無法指定 null 值黔酥。因此藻三,一旦你使用了 Options 注解,你的語句就會被上述屬性的默認(rèn)值所影響跪者。要注意避免默認(rèn)值帶來的預(yù)期以外的行為棵帽。 注意: keyColumn 屬性只在某些數(shù)據(jù)庫中有效(如 Oracle、PostgreSQL等)渣玲。請?jiān)诓迦胝Z句一節(jié)查看更多關(guān)于 keyColumn 和 keyProperty 兩者的有效值詳情逗概。 |
@Insert @Update @Delete @Select
|
方法 |
<insert> <update> <delete> <select>
|
這四個(gè)注解分別代表將會被執(zhí)行的 SQL 語句。它們用字符串?dāng)?shù)組(或單個(gè)字符串)作為參數(shù)忘衍。如果傳遞的是字符串?dāng)?shù)組逾苫,字符串之間先會被填充一個(gè)空格再連接成單個(gè)完整的字符串。這有效避免了以 Java 代碼構(gòu)建 SQL 語句時(shí)的“丟失空格”的問題枚钓。然而铅搓,你也可以提前手動連接好字符串。屬性有:value 搀捷,填入的值是用來組成單個(gè) SQL 語句的字符串?dāng)?shù)組星掰。 |
@InsertProvider @UpdateProvider @DeleteProvider @SelectProvider
|
方法 |
<insert> <update> <delete> <select>
|
允許構(gòu)建動態(tài) SQL。這些備選的 SQL 注解允許你指定類名和返回在運(yùn)行時(shí)執(zhí)行的 SQL 語句的方法。(自從MyBatis 3.4.6開始氢烘,你可以用 CharSequence 代替 String 來返回類型返回值了怀偷。)當(dāng)執(zhí)行映射語句的時(shí)候,MyBatis 會實(shí)例化類并執(zhí)行方法播玖,類和方法就是填入了注解的值椎工。你可以把已經(jīng)傳遞給映射方法了的對象作為參數(shù),"Mapper interface type" 和 "Mapper method" 會經(jīng)過 ProviderContext (僅在MyBatis 3.4.5及以上支持)作為參數(shù)值黎棠。(MyBatis 3.4及以上的版本,支持多參數(shù)傳入)屬性有: type , method 镰绎。type 屬性需填入類脓斩。method 需填入該類定義了的方法名。注意 接下來的小節(jié)將會討論類畴栖,能幫助你更輕松地構(gòu)建動態(tài) SQL随静。 |
@Param |
參數(shù) |
N/A | 如果你的映射方法的形參有多個(gè),這個(gè)注解使用在映射方法的參數(shù)上就能為它們?nèi)∽远x名字吗讶。若不給出自定義名字燎猛,多參數(shù)(不包括 RowBounds 參數(shù))則先以 "param" 作前綴,再加上它們的參數(shù)位置作為參數(shù)別名照皆。例如 #{param1} , #{param2} 重绷,這個(gè)是默認(rèn)值。如果注解是 @Param("person") 膜毁,那么參數(shù)就會被命名為 #{person} 昭卓。 |
@SelectKey |
方法 |
<selectKey> |
這個(gè)注解的功能與 <selectKey> 標(biāo)簽完全一致,用在已經(jīng)被 @Insert 或 @InsertProvider 或 @Update 或 @UpdateProvider 注解了的方法上瘟滨。若在未被上述四個(gè)注解的方法上作 @SelectKey 注解則視為無效候醒。如果你指定了 @SelectKey 注解,那么 MyBatis 就會忽略掉由 @Options 注解所設(shè)置的生成主鍵或設(shè)置(configuration)屬性杂瘸。屬性有:statement 填入將會被執(zhí)行的 SQL 字符串?dāng)?shù)組倒淫,keyProperty 填入將會被更新的參數(shù)對象的屬性的值,before 填入 true 或 false 以指明 SQL 語句應(yīng)被在插入語句的之前還是之后執(zhí)行败玉。resultType 填入 keyProperty 的 Java 類型和用 Statement 敌土、 PreparedStatement 和 CallableStatement 中的 STATEMENT 、 PREPARED 或 CALLABLE 中任一值填入 statementType 运翼。默認(rèn)值是 PREPARED 纯赎。 |
@ResultMap |
方法 |
N/A | 這個(gè)注解給 @Select 或者 @SelectProvider 提供在 XML 映射中的 <resultMap> 的id。這使得注解的 select 可以復(fù)用那些定義在 XML 中的 ResultMap南蹂。如果同一 select 注解中還存在 @Results 或者 @ConstructorArgs 犬金,那么這兩個(gè)注解將被此注解覆蓋。 |
@ResultType |
方法 |
N/A | 此注解在使用了結(jié)果處理器的情況下使用。在這種情況下晚顷,返回類型為 void峰伙,所以 Mybatis 必須有一種方式?jīng)Q定對象的類型,用于構(gòu)造每行數(shù)據(jù)该默。如果有 XML 的結(jié)果映射瞳氓,請使用 @ResultMap 注解。如果結(jié)果類型在 XML 的 <select> 節(jié)點(diǎn)中指定了栓袖,就不需要其他的注解了匣摘。其他情況下則使用此注解。比如裹刮,如果 @Select 注解在一個(gè)將使用結(jié)果處理器的方法上音榜,那么返回類型必須是 void 并且這個(gè)注解(或者@ResultMap)必選。這個(gè)注解僅在方法返回類型是 void 的情況下生效捧弃。 |
@Flush |
方法 |
N/A | 如果使用了這個(gè)注解赠叼,定義在 Mapper 接口中的方法能夠調(diào)用 SqlSession#flushStatements() 方法。(Mybatis 3.3及以上) |
二违霞、xml 方式使用
2.1 快速實(shí)現(xiàn)
xml 配置方式使用 MyBatis 主要步驟有以下三步:
- 配置
application.yml
- 編寫 mapper xml 文件
- 寫 mapper java 代碼
1. 配置 application.yml
首先在 application.yml
中配置數(shù)據(jù)庫實(shí)體對象的位置和mapper文件的位置嘴办,配置了 type-aliases-package
后就可以在 xml 文件中直接寫類名,而不用寫全限定類名啦买鸽。
mybatis:
type-aliases-package: com.solo.coderiver.project.dataobject
mapper-locations: classpath:mapper/*.xml
如果不配置 mapper-locations
涧郊,會報(bào)如下錯(cuò)誤:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.solo.coderiver.project.mapper.ProjectCategoryMapper.insert
2. 編寫 mapper xml 映射文件
以項(xiàng)目類型 ProjectCategory
為例,添加 MyBatis 的增刪改查實(shí)現(xiàn)
ProjectCategoryMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.solo.coderiver.project.mapper.ProjectCategoryMapper" >
<resultMap id="BaseResultMap" type="ProjectCategory">
<id column="category_id" property="categoryId" jdbcType="INTEGER"/>
<result column="category_name" property="categoryName" jdbcType="VARCHAR" />
<result column="category_type" property="categoryType" jdbcType="INTEGER" />
</resultMap>
<insert id="insert" parameterType="ProjectCategory">
insert into project_category(category_id, category_name, category_type)
values(#{categoryId, jdbcType=INTEGER}, #{categoryName, jdbcType=VARCHAR}, #{categoryType, jdbcType=INTEGER})
</insert>
<delete id="deleteByType" parameterType="java.lang.Integer">
delete from project_category
where category_type = #{type, jdbcType=INTEGER}
</delete>
<update id="updateByType" parameterType="ProjectCategory">
update project_category
set category_name = #{categoryName}
where category_type = #{categoryType}
</update>
<select id="selectByType" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select * from project_category
where category_type = #{categoryType}
</select>
</mapper>
后面會講配置的詳細(xì)屬性眼五。
3. 寫 mapper java 代碼
ProjectCategoryMapper.java
@Mapper
public interface ProjectCategoryMapper {
int insert(ProjectCategory category);
int deleteByType(Integer type);
int updateByType(ProjectCategory category);
ProjectCategory selectByType(Integer type);
}
新建一個(gè)接口底燎,方法名要跟 ProjectCategoryMapper.xml
里 <insert>
、 <delete>
弹砚、 <update>
双仍、 <select>
等 sql 操作語句的 id 保持一致,否則會報(bào)錯(cuò)桌吃。
然后再在類名上加注解 @Mapper
就可以啦朱沃。
ProjectCategory
對象
package com.solo.coderiver.project.dataobject;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
@Data
public class ProjectCategory {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer categoryId;
private String categoryName;
private Integer categoryType;
public ProjectCategory() {
}
public ProjectCategory(Integer categoryType, String categoryName) {
this.categoryName = categoryName;
this.categoryType = categoryType;
}
}
2.2 xml 映射文件詳解
SQL 映射文件有很少的幾個(gè)頂級元素(按照它們應(yīng)該被定義的順序):
-
cache
– 給定命名空間的緩存配置。 -
cache-ref
– 其他命名空間緩存配置的引用茅诱。 -
resultMap
– 是最復(fù)雜也是最強(qiáng)大的元素逗物,用來描述如何從數(shù)據(jù)庫結(jié)果集中來加載對象。 -
parameterMap
– 已廢棄瑟俭!老式風(fēng)格的參數(shù)映射翎卓。內(nèi)聯(lián)參數(shù)是首選,這個(gè)元素可能在將來被移除,這里不會記錄摆寄。 -
sql
– 可被其他語句引用的可重用語句塊失暴。 -
insert
– 映射插入語句 -
update
– 映射更新語句 -
delete
– 映射刪除語句 -
select
– 映射查詢語句
select
查詢語句是 MyBatis 中最常用的元素之一坯门,光能把數(shù)據(jù)存到數(shù)據(jù)庫中價(jià)值并不大,如果還能重新取出來才有用逗扒,多數(shù)應(yīng)用也都是查詢比修改要頻繁古戴。對每個(gè)插入、更新或刪除操作矩肩,通常對應(yīng)多個(gè)查詢操作酒觅。這是
MyBatis 的基本原則之一篮奄,也是將焦點(diǎn)和努力放到查詢和結(jié)果映射的原因适掰。
上文中實(shí)現(xiàn)了一個(gè)簡單的 select 語句:
<select id="selectByType" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select * from project_category
where category_type = #{categoryType}
</select>
這個(gè)語句被稱作 selectByType次绘,接受一個(gè) int(或 Integer)類型的參數(shù),并返回一個(gè) BaseResultMap 定義的 ProjectCategory 對象刽酱。這條語句的作用是根據(jù)傳入的類型查詢項(xiàng)目類型信息喳逛。
注意參數(shù)符號:#{categoryType}
, 它表明接收傳入的參數(shù) categoryType
。
select 的屬性表:
<select
id="selectPerson"
parameterType="int"
parameterMap="deprecated"
resultType="hashmap"
resultMap="personResultMap"
flushCache="false"
useCache="true"
timeout="10000"
fetchSize="256"
statementType="PREPARED"
resultSetType="FORWARD_ONLY">
屬性 | 描述 |
---|---|
id |
在命名空間中唯一的標(biāo)識符肛跌,可以被用來引用這條語句艺配。 |
parameterType |
將會傳入這條語句的參數(shù)類的完全限定名或別名察郁。這個(gè)屬性是可選的衍慎,因?yàn)?MyBatis 可以通過 TypeHandler 推斷出具體傳入語句的參數(shù),默認(rèn)值為 unset皮钠。 |
parameterMap | 這是引用外部 parameterMap 的已經(jīng)被廢棄的方法稳捆。使用內(nèi)聯(lián)參數(shù)映射和 parameterType 屬性。 |
resultType |
從這條語句中返回的期望類型的類的完全限定名或別名麦轰。注意如果是集合情形乔夯,那應(yīng)該是集合可以包含的類型,而不能是集合本身款侵。使用 resultType 或 resultMap末荐,但不能同時(shí)使用。 |
resultMap |
外部 resultMap 的命名引用新锈。結(jié)果集的映射是 MyBatis 最強(qiáng)大的特性甲脏,對其有一個(gè)很好的理解的話,許多復(fù)雜映射的情形都能迎刃而解妹笆。使用 resultMap 或 resultType块请,但不能同時(shí)使用。 |
flushCache |
將其設(shè)置為 true拳缠,任何時(shí)候只要語句被調(diào)用墩新,都會導(dǎo)致本地緩存和二級緩存都會被清空,默認(rèn)值:false窟坐。 |
useCache |
將其設(shè)置為 true海渊,將會導(dǎo)致本條語句的結(jié)果被二級緩存绵疲,默認(rèn)值:對 select 元素為 true。 |
timeout |
這個(gè)設(shè)置是在拋出異常之前切省,驅(qū)動程序等待數(shù)據(jù)庫返回請求結(jié)果的秒數(shù)最岗。默認(rèn)值為 unset(依賴驅(qū)動)。 |
fetchSize |
這是嘗試影響驅(qū)動程序每次批量返回的結(jié)果行數(shù)和這個(gè)設(shè)置值相等朝捆。默認(rèn)值為 unset(依賴驅(qū)動)般渡。 |
statementType |
STATEMENT,PREPARED 或 CALLABLE 的一個(gè)芙盘。這會讓 MyBatis 分別使用 Statement驯用,PreparedStatement 或 CallableStatement,默認(rèn)值:PREPARED儒老。 |
resultSetType |
FORWARD_ONLY蝴乔,SCROLL_SENSITIVE 或 SCROLL_INSENSITIVE 中的一個(gè),默認(rèn)值為 unset (依賴驅(qū)動)驮樊。 |
databaseId |
如果配置了 databaseIdProvider薇正,MyBatis 會加載所有的不帶 databaseId 或匹配當(dāng)前 databaseId 的語句;如果帶或者不帶的語句都有囚衔,則不帶的會被忽略挖腰。 |
resultOrdered |
這個(gè)設(shè)置僅針對嵌套結(jié)果 select 語句適用:如果為 true,就是假設(shè)包含了嵌套結(jié)果集或是分組了练湿,這樣的話當(dāng)返回一個(gè)主結(jié)果行的時(shí)候猴仑,就不會發(fā)生有對前面結(jié)果集的引用的情況。這就使得在獲取嵌套的結(jié)果集的時(shí)候不至于導(dǎo)致內(nèi)存不夠用肥哎。默認(rèn)值:false 辽俗。 |
resultSets |
這個(gè)設(shè)置僅對多結(jié)果集的情況適用,它將列出語句執(zhí)行后返回的結(jié)果集并每個(gè)結(jié)果集給一個(gè)名稱篡诽,名稱是逗號分隔的崖飘。 |
像本文的例子一樣,select
常用的屬性其實(shí)就是 id
杈女、 parameterType
朱浴、resultMap
三個(gè),其他的了解即可碧信。
insert, update 和 delete
數(shù)據(jù)變更語句 insert赊琳,update 和 delete 的實(shí)現(xiàn)非常接近:
<insert
id="insertAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
keyProperty=""
keyColumn=""
useGeneratedKeys=""
timeout="20">
<update
id="updateAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
timeout="20">
<delete
id="deleteAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
timeout="20">
屬性表
屬性 | 描述 |
---|---|
id |
命名空間中的唯一標(biāo)識符,可被用來代表這條語句砰碴。 |
parameterType |
將要傳入語句的參數(shù)的完全限定類名或別名躏筏。這個(gè)屬性是可選的,因?yàn)?MyBatis 可以通過 TypeHandler 推斷出具體傳入語句的參數(shù)呈枉,默認(rèn)值為 unset趁尼。 |
parameterMap |
這是引用外部 parameterMap 的已經(jīng)被廢棄的方法。使用內(nèi)聯(lián)參數(shù)映射和 parameterType 屬性酥泞。 |
flushCache |
將其設(shè)置為 true,任何時(shí)候只要語句被調(diào)用芝囤,都會導(dǎo)致本地緩存和二級緩存都會被清空,默認(rèn)值:true(對應(yīng)插入瘩扼、更新和刪除語句)。 |
timeout |
這個(gè)設(shè)置是在拋出異常之前溅固,驅(qū)動程序等待數(shù)據(jù)庫返回請求結(jié)果的秒數(shù)爆捞。默認(rèn)值為 unset(依賴驅(qū)動)双霍。 |
statementType |
STATEMENT囤萤,PREPARED 或 CALLABLE 的一個(gè)掸驱。這會讓 MyBatis 分別使用 Statement没佑,PreparedStatement 或 CallableStatement毕贼,默認(rèn)值:PREPARED。 |
useGeneratedKeys |
(僅對 insert 和 update 有用)這會令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法來取出由數(shù)據(jù)庫內(nèi)部生成的主鍵(比如:像 MySQL 和 SQL Server 這樣的關(guān)系數(shù)據(jù)庫管理系統(tǒng)的自動遞增字段)蛤奢,默認(rèn)值:false鬼癣。 |
keyProperty |
(僅對 insert 和 update 有用)唯一標(biāo)記一個(gè)屬性,MyBatis 會通過 getGeneratedKeys 的返回值或者通過 insert 語句的 selectKey 子元素設(shè)置它的鍵值啤贩,默認(rèn):unset 待秃。如果希望得到多個(gè)生成的列,也可以是逗號分隔的屬性名稱列表痹屹。 |
keyColumn |
(僅對 insert 和 update 有用)通過生成的鍵值設(shè)置表中的列名章郁,這個(gè)設(shè)置僅在某些數(shù)據(jù)庫(像 PostgreSQL)是必須的,當(dāng)主鍵列不是表中的第一列的時(shí)候需要設(shè)置痢掠。如果希望得到多個(gè)生成的列驱犹,也可以是逗號分隔的屬性名稱列表嘲恍。 |
databaseId |
如果配置了 databaseIdProvider,MyBatis 會加載所有的不帶 databaseId 或匹配當(dāng)前 databaseId 的語句雄驹;如果帶或者不帶的語句都有佃牛,則不帶的會被忽略。 |
三個(gè)更新操作常用的屬性只有兩個(gè):id
医舆、parameterType
俘侠,其他的了解即可。
Result Maps
resultMap
元素是 MyBatis 中最重要最強(qiáng)大的元素蔬将。它可以讓你從 90% 的 JDBC ResultSets
數(shù)據(jù)提取代碼中解放出來爷速,并在一些情形下允許你做一些 JDBC 不支持的事情。
實(shí)際上霞怀,在對復(fù)雜語句進(jìn)行聯(lián)合映射的時(shí)候惫东,它很可能可以代替數(shù)千行的同等功能的代碼。
ResultMap 的設(shè)計(jì)思想是毙石,簡單的語句不需要明確的結(jié)果映射廉沮,而復(fù)雜一點(diǎn)的語句只需要描述它們的關(guān)系就行了。
下面是 resultMap
元素的概念視圖:
resultMap
-
constructor
- 用于在實(shí)例化類時(shí)徐矩,注入結(jié)果到構(gòu)造方法中
-
idArg
- ID 參數(shù);標(biāo)記出作為 ID 的結(jié)果可以幫助提高整體性能 -
arg
- 將被注入到構(gòu)造方法的一個(gè)普通結(jié)果
-
id
– 一個(gè) ID 結(jié)果;標(biāo)記出作為 ID 的結(jié)果可以幫助提高整體性能result
– 注入到字段或 JavaBean 屬性的普通結(jié)果-
association
– 一個(gè)復(fù)雜類型的關(guān)聯(lián);許多結(jié)果將包裝成這種類型
- 嵌套結(jié)果映射 – 關(guān)聯(lián)可以指定為一個(gè)
resultMap
元素滞时,或者引用一個(gè)
- 嵌套結(jié)果映射 – 關(guān)聯(lián)可以指定為一個(gè)
-
collection
– 一個(gè)復(fù)雜類型的集合
- 嵌套結(jié)果映射 – 集合可以指定為一個(gè)
resultMap
元素,或者引用一個(gè)
- 嵌套結(jié)果映射 – 集合可以指定為一個(gè)
-
discriminator
– 使用結(jié)果值來決定使用哪個(gè)
resultMap
-
case
– 基于某些值的結(jié)果映射
- 嵌套結(jié)果映射 – 一個(gè)
case
也是一個(gè)映射它本身的結(jié)果,因此可以包含很多相同的元素滤灯,或者它可以參照一個(gè)外部的resultMap
坪稽。
- 嵌套結(jié)果映射 – 一個(gè)
-
屬性 | 描述 |
---|---|
id |
當(dāng)前命名空間中的一個(gè)唯一標(biāo)識,用于標(biāo)識一個(gè)result map. |
type |
類的完全限定名, 或者一個(gè)類型別名 (內(nèi)置的別名可以參考上面的表格). |
autoMapping |
如果設(shè)置這個(gè)屬性鳞骤,MyBatis將會為這個(gè)ResultMap開啟或者關(guān)閉自動映射窒百。這個(gè)屬性會覆蓋全局的屬性 autoMappingBehavior。默認(rèn)值為:unset弟孟。 |
為了方便理解贝咙,再把上面項(xiàng)目中定義的 resultMap 貼出來
<resultMap id="BaseResultMap" type="ProjectCategory">
<id column="category_id" property="categoryId" jdbcType="INTEGER"/>
<result column="category_name" property="categoryName" jdbcType="VARCHAR" />
<result column="category_type" property="categoryType" jdbcType="INTEGER" />
</resultMap>
id 和 result 標(biāo)簽中的屬性表如下:
屬性 | 描述 |
---|---|
property |
映射到列結(jié)果的字段或?qū)傩匝颉H绻脕砥ヅ涞?JavaBeans 存在給定名字的屬性拂募,那么它將會被使用。否則 MyBatis 將會尋找給定名稱 property 的字段窟她。 無論是哪一種情形陈症,你都可以使用通常的點(diǎn)式分隔形式進(jìn)行復(fù)雜屬性導(dǎo)航。比如,你可以這樣映射一些簡單的東西: “username” ,或者映射到一些復(fù)雜的東西: “address.street.number” 震糖。 |
column |
數(shù)據(jù)庫中的列名,或者是列的別名录肯。一般情況下,這和 傳遞給 resultSet.getString(columnName) 方法的參數(shù)一樣吊说。 |
javaType |
一個(gè) Java 類的完全限定名,或一個(gè)類型別名(參考上面內(nèi)建類型別名 的列表) 论咏。如果你映射到一個(gè) JavaBean,MyBatis 通秤啪妫可以斷定類型。 然而,如果你映射到的是 HashMap,那么你應(yīng)該明確地指定 javaType 來保證期望的行為厅贪。 |
jdbcType |
JDBC 類型蠢护,所支持的 JDBC 類型參見這個(gè)表格之后的“支持的 JDBC 類型”。 只需要在可能執(zhí)行插入养涮、更新和刪除的允許空值的列上指定 JDBC 類型葵硕。這是 JDBC 的要求而非 MyBatis 的要求。如果你直接面向 JDBC 編程,你需要對可能為 null 的值指定這個(gè)類型贯吓。 |
typeHandler |
我們在前面討論過的默認(rèn)類型處理器懈凹。使用這個(gè)屬性,你可以覆蓋默 認(rèn)的類型處理器。這個(gè)屬性值是一個(gè)類型處理 器實(shí)現(xiàn)類的完全限定名悄谐,或者是類型別名介评。 |
關(guān)于 jdbcType
發(fā)現(xiàn)有些小伙伴在寫映射文件的時(shí)候,都習(xí)慣性的把所有的需要傳入的參數(shù)都加上 jdbcType=""
爬舰,那到底什么情況下需要指明威沫,什么情況下不需要指明呢?
查閱官方文檔看到了官方的描述:
如果一個(gè)列允許 null 值洼专,并且會傳遞值 null 的參數(shù)棒掠,就必須要指定 JDBC Type。
也就是說只有當(dāng)一個(gè)列允許 null 并有可能傳入 null 時(shí)屁商,才必須要指定 JDBC Type烟很,其他情況是不需要指定的。當(dāng)然指定了也沒錯(cuò)蜡镶,就是多寫點(diǎn)代碼雾袱。
明白了什么時(shí)候需要指定,那還有個(gè)問題官还,java 中的類型跟 jdbcType 的類型如何對應(yīng)呢芹橡?如果對應(yīng)關(guān)系寫錯(cuò)了也會報(bào)錯(cuò)。下面就整理出了兩者的對應(yīng)關(guān)系:
JDBCType
與 JavaType
對應(yīng)關(guān)系
JDBCType JavaType
CHAR String
VARCHAR String
LONGVARCHAR String
NUMERIC java.math.BigDecimal
DECIMAL java.math.BigDecimal
BIT boolean
BOOLEAN boolean
TINYINT byte
SMALLINT short
INTEGER int
BIGINT long
REAL float
FLOAT double
DOUBLE double
BINARY byte[]
VARBINARY byte[]
LONGVARBINARY byte[]
DATE java.sql.Date
TIME java.sql.Time
TIMESTAMP java.sql.Timestamp
CLOB Clob
BLOB Blob
ARRAY Array
DISTINCT mapping of underlying type
STRUCT Struct
REF Ref
DATALINK java.net.URL[color=red][/color]
2.3 補(bǔ)充
如果查詢返回的結(jié)果是個(gè)列表怎么辦望伦?如何提取出可復(fù)用的 sql 呢林说?
日常使用中還有這兩個(gè)常見的應(yīng)用場景,下面就以項(xiàng)目成員表 ProejctMember
來演示一下屯伞。
一個(gè)項(xiàng)目可以對應(yīng)多個(gè)成員腿箩,所以根據(jù)項(xiàng)目 id 查詢成員的話肯定查出來多條數(shù)據(jù)。
ProjectMemberMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.solo.coderiver.project.mapper.ProjectMemberMapper">
<resultMap id="BaseResultMap" type="ProjectMember">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="project_id" property="projectId" jdbcType="VARCHAR"/>
<result column="project_name" property="projectName" jdbcType="VARCHAR"/>
<result column="project_avatar" property="projectAvatar" jdbcType="VARCHAR"/>
<result column="user_id" property="userId" jdbcType="VARCHAR"/>
<result column="user_name" property="userName" jdbcType="VARCHAR"/>
<result column="user_avatar" property="userAvatar" jdbcType="VARCHAR"/>
<result column="user_role" property="userRole" jdbcType="INTEGER"/>
<result column="role_name" property="roleName" jdbcType="VARCHAR"/>
<result column="status" property="status" jdbcType="INTEGER"/>
</resultMap>
<sql id="baseColumns">
id, project_id, project_name, project_avatar, user_id, user_name,
user_avatar, user_role, role_name, status
</sql>
<select id="selectByProjectId" parameterType="java.lang.String" resultMap="BaseResultMap">
select
<include refid="baseColumns"/>
from project_member
where project_id = #{projectId, jdbcType=VARCHAR}
</select>
</mapper>
ProjectMemberMapper.java
package com.solo.coderiver.project.mapper;
import com.solo.coderiver.project.dataobject.ProjectMember;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface ProjectMemberMapper {
List<ProjectMember> selectByProjectId(String projectId);
}
返回結(jié)果是列表的話劣摇,映射文件的 result 還是只給定 List 內(nèi)的類型即可珠移。
用 <sql>
標(biāo)簽來提出出可復(fù)用的 sql 語句
<sql id="baseColumns">
id, project_id, project_name, project_avatar, user_id, user_name,
user_avatar, user_role, role_name, status
</sql>
在需要用到的地方用 <include>
標(biāo)簽引入 sql
<select id="selectByProjectId" parameterType="java.lang.String" resultMap="BaseResultMap">
select
<include refid="baseColumns"/>
from project_member
where project_id = #{projectId, jdbcType=VARCHAR}
</select>
然后在 service 中引用 mapper
package com.solo.coderiver.project.service.mybatis;
import com.solo.coderiver.project.dataobject.ProjectMember;
import com.solo.coderiver.project.mapper.ProjectMemberMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ProjectMemberServiceMyBatisImpl {
@Autowired
ProjectMemberMapper mapper;
public List<ProjectMember> findByProjectId(String projectId){
return mapper.selectByProjectId(projectId);
}
}
單元測試
package com.solo.coderiver.project.service.mybatis;
import com.solo.coderiver.project.ProjectApplicationTests;
import com.solo.coderiver.project.dataobject.ProjectMember;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import static org.junit.Assert.*;
public class ProjectMemberServiceMyBatisImplTest extends ProjectApplicationTests {
@Autowired
ProjectMemberServiceMyBatisImpl service;
@Test
public void findByProjectId() {
List<ProjectMember> list = service.findByProjectId("1541062468073593543");
Assert.assertNotEquals(0, list.size());
}
}
以上就是 MyBatis 在 SpringBoot 中的簡單使用方式介紹。
代碼出自開源項(xiàng)目 coderiver
,致力于打造全平臺型全棧精品開源項(xiàng)目钧惧。
coderiver 中文名 河碼暇韧,是一個(gè)為程序員和設(shè)計(jì)師提供項(xiàng)目協(xié)作的平臺。無論你是前端浓瞪、后端锨咙、移動端開發(fā)人員,或是設(shè)計(jì)師追逮、產(chǎn)品經(jīng)理酪刀,都可以在平臺上發(fā)布項(xiàng)目,與志同道合的小伙伴一起協(xié)作完成項(xiàng)目钮孵。
coderiver河碼 類似程序員客棧骂倘,但主要目的是方便各細(xì)分領(lǐng)域人才之間技術(shù)交流,共同成長巴席,多人協(xié)作完成項(xiàng)目历涝。暫不涉及金錢交易。
計(jì)劃做成包含 pc端(Vue漾唉、React)荧库、移動H5(Vue、React)赵刑、ReactNative混合開發(fā)分衫、Android原生、微信小程序般此、java后端的全平臺型全棧項(xiàng)目蚪战,歡迎關(guān)注。
項(xiàng)目地址:https://github.com/cachecats/coderiver
您的鼓勵(lì)是我前行最大的動力铐懊,歡迎點(diǎn)贊邀桑,歡迎送小星星? ~