MyBatis 是一款優秀的持久層框架,它支持定製化 SQL、存儲過程以及高級映射。MyBatis 避免了幾乎全部的 JDBC 代碼和手動設置參數以及獲取結果集。MyBatis 可使用簡單的 XML 或註解來配置和映射原生信息,將接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java對象)映射成數據庫中的記錄。php
不管是使用註解仍是 xml 映射文件配置方式,在使用以前有兩步是必須的:前端
引入依賴java
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
複製代碼
在啓動類上加註解 @MapperScan
指明 mapper 類的位置git
@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 文件。但有個顯而易見的缺點是若是 sql 太長了,像字段多的 @Insert
,若是換行須要用 +
鏈接,不利於後期維護。github
MyBatis 支持的註解屬性表:spring
註解 | 使用對象 | 相對應的 XML | 描述 |
---|---|---|---|
@CacheNamespace |
類 |
<cache> |
爲給定的命名空間(好比類)配置緩存。屬性有:implemetation , eviction , flushInterval , size , readWrite , blocking 和properties 。 |
@Property |
N/A | <property> |
指定參數值或佔位值(placeholder)(能被 mybatis-config.xml 內的配置屬性覆蓋)。屬性有:name , value 。(僅在MyBatis 3.4.2以上版本生效) |
@CacheNamespaceRef |
類 |
<cacheRef> |
參照另一個命名空間的緩存來使用。屬性有:value , name 。若是你使用了這個註解,你應設置 value 或者 name 屬性的其中一個。value 屬性用於指定 Java 類型而指定命名空間(命名空間名就是指定的 Java 類型的全限定名),name 屬性(這個屬性僅在MyBatis 3.4.2以上版本生效)直接指定了命名空間的名字。 |
@ConstructorArgs |
方法 |
<constructor> |
收集一組結果傳遞給一個結果對象的構造方法。屬性有:value ,它是形式參數數組。 |
@Arg |
N/A | <arg> <idArg> |
單參數構造方法,是 ConstructorArgs 集合的一部分。屬性有:id , column , javaType , jdbcType , typeHandler , select 和 resultMap 。id 屬性是布爾值,來標識用於比較的屬性,和<idArg> XML 元素類似。 |
@TypeDiscriminator |
方法 |
<discriminator> |
一組實例值被用來決定結果映射的表現。屬性有:column , javaType , jdbcType , typeHandler 和 cases 。cases 屬性是實例數組。 |
@Case |
N/A | <case> |
單獨實例的值和它對應的映射。屬性有:value , type , results 。results 屬性是結果數組,所以這個註解和實際的 ResultMap 很類似,由下面的 Results 註解指定。 |
@Results |
方法 |
<resultMap> |
結果映射的列表,包含了一個特別結果列如何被映射到屬性或字段的詳情。屬性有:value , id 。value 屬性是 Result 註解的數組。這個 id 的屬性是結果映射的名稱。 |
@Result |
N/A | <result> <id> |
在列和屬性或字段之間的單獨結果映射。屬性有:id , column , javaType , jdbcType , typeHandler , one , many 。id 屬性是一個布爾值,來標識應該被用於比較(和在 XML 映射中的<id> 類似)的屬性。one 屬性是單獨的聯繫,和 <association> 類似,而 many 屬性是對集合而言的,和<collection> 類似。它們這樣命名是爲了不名稱衝突。 |
@One |
N/A | <association> |
複雜類型的單獨屬性值映射。屬性有:select ,已映射語句(也就是映射器方法)的全限定名,它能夠加載合適類型的實例。fetchType 會覆蓋全局的配置參數 lazyLoadingEnabled 。注意 聯合映射在註解 API中是不支持的。這是由於 Java 註解的限制,不容許循環引用。 |
@Many |
N/A | <collection> |
映射到複雜類型的集合屬性。屬性有:select ,已映射語句(也就是映射器方法)的全限定名,它能夠加載合適類型的實例的集合,fetchType 會覆蓋全局的配置參數 lazyLoadingEnabled 。注意 聯合映射在註解 API中是不支持的。這是由於 Java 註解的限制,不容許循環引用 |
@MapKey |
方法 |
這是一個用在返回值爲 Map 的方法上的註解。它可以將存放對象的 List 轉化爲 key 值爲對象的某一屬性的 Map。屬性有: value ,填入的是對象的屬性名,做爲 Map 的 key 值。 |
|
@Options |
方法 |
映射語句的屬性 | 這個註解提供訪問大範圍的交換和配置選項的入口,它們一般在映射語句上做爲屬性出現。Options 註解提供了通俗易懂的方式來訪問它們,而不是讓每條語句註解變複雜。屬性有:useCache=true , flushCache=FlushCachePolicy.DEFAULT , resultSetType=FORWARD_ONLY , statementType=PREPARED , fetchSize=-1 , timeout=-1 , useGeneratedKeys=false , keyProperty="id" , keyColumn="" , resultSets="" 。值得一提的是, Java 註解沒法指定 null 值。所以,一旦你使用了 Options 註解,你的語句就會被上述屬性的默認值所影響。要注意避免默認值帶來的預期之外的行爲。 注意: keyColumn 屬性只在某些數據庫中有效(如 Oracle、PostgreSQL等)。請在插入語句一節查看更多關於 keyColumn 和 keyProperty 二者的有效值詳情。 |
@Insert @Update @Delete @Select |
方法 |
<insert> <update> <delete> <select> |
這四個註解分別表明將會被執行的 SQL 語句。它們用字符串數組(或單個字符串)做爲參數。若是傳遞的是字符串數組,字符串之間先會被填充一個空格再鏈接成單個完整的字符串。這有效避免了以 Java 代碼構建 SQL 語句時的「丟失空格」的問題。然而,你也能夠提早手動鏈接好字符串。屬性有:value ,填入的值是用來組成單個 SQL 語句的字符串數組。 |
@InsertProvider @UpdateProvider @DeleteProvider @SelectProvider |
方法 |
<insert> <update> <delete> <select> |
容許構建動態 SQL。這些備選的 SQL 註解容許你指定類名和返回在運行時執行的 SQL 語句的方法。(自從MyBatis 3.4.6開始,你能夠用 CharSequence 代替 String 來返回類型返回值了。)當執行映射語句的時候,MyBatis 會實例化類並執行方法,類和方法就是填入了註解的值。你能夠把已經傳遞給映射方法了的對象做爲參數,"Mapper interface type" 和 "Mapper method" 會通過 ProviderContext (僅在MyBatis 3.4.5及以上支持)做爲參數值。(MyBatis 3.4及以上的版本,支持多參數傳入)屬性有: type , method 。type 屬性需填入類。method 需填入該類定義了的方法名。注意 接下來的小節將會討論類,能幫助你更輕鬆地構建動態 SQL。 |
@Param |
參數 |
N/A | 若是你的映射方法的形參有多個,這個註解使用在映射方法的參數上就能爲它們取自定義名字。若不給出自定義名字,多參數(不包括 RowBounds 參數)則先以 "param" 做前綴,再加上它們的參數位置做爲參數別名。例如 #{param1} , #{param2} ,這個是默認值。若是註解是 @Param("person") ,那麼參數就會被命名爲 #{person} 。 |
@SelectKey |
方法 |
<selectKey> |
這個註解的功能與 <selectKey> 標籤徹底一致,用在已經被 @Insert 或 @InsertProvider 或 @Update 或 @UpdateProvider 註解了的方法上。若在未被上述四個註解的方法上做 @SelectKey 註解則視爲無效。若是你指定了 @SelectKey 註解,那麼 MyBatis 就會忽略掉由 @Options 註解所設置的生成主鍵或設置(configuration)屬性。屬性有:statement 填入將會被執行的 SQL 字符串數組,keyProperty 填入將會被更新的參數對象的屬性的值,before 填入 true 或 false 以指明 SQL 語句應被在插入語句的以前仍是以後執行。resultType 填入 keyProperty 的 Java 類型和用 Statement 、 PreparedStatement 和 CallableStatement 中的 STATEMENT 、 PREPARED 或 CALLABLE 中任一值填入 statementType 。默認值是 PREPARED 。 |
@ResultMap |
方法 |
N/A | 這個註解給 @Select 或者 @SelectProvider 提供在 XML 映射中的 <resultMap> 的id。這使得註解的 select 能夠複用那些定義在 XML 中的 ResultMap。若是同一 select 註解中還存在 @Results 或者 @ConstructorArgs ,那麼這兩個註解將被此註解覆蓋。 |
@ResultType |
方法 |
N/A | 此註解在使用告終果處理器的狀況下使用。在這種狀況下,返回類型爲 void,因此 Mybatis 必須有一種方式決定對象的類型,用於構造每行數據。若是有 XML 的結果映射,請使用 @ResultMap 註解。若是結果類型在 XML 的 <select> 節點中指定了,就不須要其餘的註解了。其餘狀況下則使用此註解。好比,若是 @Select 註解在一個將使用結果處理器的方法上,那麼返回類型必須是 void 而且這個註解(或者@ResultMap)必選。這個註解僅在方法返回類型是 void 的狀況下生效。 |
@Flush |
方法 |
N/A | 若是使用了這個註解,定義在 Mapper 接口中的方法可以調用 SqlSession#flushStatements() 方法。(Mybatis 3.3及以上) |
xml 配置方式使用 MyBatis 主要步驟有如下三步:sql
application.yml
application.yml
首先在 application.yml
中配置數據庫實體對象的位置和mapper文件的位置,配置了 type-aliases-package
後就能夠在 xml 文件中直接寫類名,而不用寫全限定類名啦。數據庫
mybatis:
type-aliases-package: com.solo.coderiver.project.dataobject
mapper-locations: classpath:mapper/*.xml
複製代碼
若是不配置 mapper-locations
,會報以下錯誤:apache
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.solo.coderiver.project.mapper.ProjectCategoryMapper.insert
複製代碼
以項目類型 ProjectCategory
爲例,添加 MyBatis 的增刪改查實現
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>
複製代碼
後面會講配置的詳細屬性。
ProjectCategoryMapper.java
@Mapper
public interface ProjectCategoryMapper {
int insert(ProjectCategory category);
int deleteByType(Integer type);
int updateByType(ProjectCategory category);
ProjectCategory selectByType(Integer type);
}
複製代碼
新建一個接口,方法名要跟 ProjectCategoryMapper.xml
裏 <insert>
、 <delete>
、 <update>
、 <select>
等 sql 操做語句的 id 保持一致,不然會報錯。
而後再在類名上加註解 @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;
}
}
複製代碼
SQL 映射文件有不多的幾個頂級元素(按照它們應該被定義的順序):
cache
– 給定命名空間的緩存配置。cache-ref
– 其餘命名空間緩存配置的引用。resultMap
– 是最複雜也是最強大的元素,用來描述如何從數據庫結果集中來加載對象。parameterMap
– 已廢棄!老式風格的參數映射。內聯參數是首選,這個元素可能在未來被移除,這裏不會記錄。sql
– 可被其餘語句引用的可重用語句塊。insert
– 映射插入語句update
– 映射更新語句delete
– 映射刪除語句select
– 映射查詢語句查詢語句是 MyBatis 中最經常使用的元素之一,光能把數據存到數據庫中價值並不大,若是還能從新取出來纔有用,多數應用也都是查詢比修改要頻繁。對每一個插入、更新或刪除操做,一般對應多個查詢操做。這是 MyBatis 的基本原則之一,也是將焦點和努力放到查詢和結果映射的緣由。
上文中實現了一個簡單的 select 語句:
<select id="selectByType" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select * from project_category
where category_type = #{categoryType}
</select>
複製代碼
這個語句被稱做 selectByType,接受一個 int(或 Integer)類型的參數,並返回一個 BaseResultMap 定義的 ProjectCategory 對象。這條語句的做用是根據傳入的類型查詢項目類型信息。
注意參數符號:#{categoryType}
, 它代表接收傳入的參數 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 |
在命名空間中惟一的標識符,能夠被用來引用這條語句。 |
parameterType |
將會傳入這條語句的參數類的徹底限定名或別名。這個屬性是可選的,由於 MyBatis 能夠經過 TypeHandler 推斷出具體傳入語句的參數,默認值爲 unset。 |
parameterMap | 這是引用外部 parameterMap 的已經被廢棄的方法。使用內聯參數映射和 parameterType 屬性。 |
resultType |
從這條語句中返回的指望類型的類的徹底限定名或別名。注意若是是集合情形,那應該是集合能夠包含的類型,而不能是集合自己。使用 resultType 或 resultMap,但不能同時使用。 |
resultMap |
外部 resultMap 的命名引用。結果集的映射是 MyBatis 最強大的特性,對其有一個很好的理解的話,許多複雜映射的情形都能迎刃而解。使用 resultMap 或 resultType,但不能同時使用。 |
flushCache |
將其設置爲 true,任什麼時候候只要語句被調用,都會致使本地緩存和二級緩存都會被清空,默認值:false。 |
useCache |
將其設置爲 true,將會致使本條語句的結果被二級緩存,默認值:對 select 元素爲 true。 |
timeout |
這個設置是在拋出異常以前,驅動程序等待數據庫返回請求結果的秒數。默認值爲 unset(依賴驅動)。 |
fetchSize |
這是嘗試影響驅動程序每次批量返回的結果行數和這個設置值相等。默認值爲 unset(依賴驅動)。 |
statementType |
STATEMENT,PREPARED 或 CALLABLE 的一個。這會讓 MyBatis 分別使用 Statement,PreparedStatement 或 CallableStatement,默認值:PREPARED。 |
resultSetType |
FORWARD_ONLY,SCROLL_SENSITIVE 或 SCROLL_INSENSITIVE 中的一個,默認值爲 unset (依賴驅動)。 |
databaseId |
若是配置了 databaseIdProvider,MyBatis 會加載全部的不帶 databaseId 或匹配當前 databaseId 的語句;若是帶或者不帶的語句都有,則不帶的會被忽略。 |
resultOrdered |
這個設置僅針對嵌套結果 select 語句適用:若是爲 true,就是假設包含了嵌套結果集或是分組了,這樣的話當返回一個主結果行的時候,就不會發生有對前面結果集的引用的狀況。這就使得在獲取嵌套的結果集的時候不至於致使內存不夠用。默認值:false 。 |
resultSets |
這個設置僅對多結果集的狀況適用,它將列出語句執行後返回的結果集並每一個結果集給一個名稱,名稱是逗號分隔的。 |
像本文的例子同樣,select
經常使用的屬性其實就是 id
、 parameterType
、resultMap
三個,其餘的瞭解便可。
數據變動語句 insert,update 和 delete 的實現很是接近:
<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 |
命名空間中的惟一標識符,可被用來表明這條語句。 |
parameterType |
將要傳入語句的參數的徹底限定類名或別名。這個屬性是可選的,由於 MyBatis 能夠經過 TypeHandler 推斷出具體傳入語句的參數,默認值爲 unset。 |
parameterMap |
這是引用外部 parameterMap 的已經被廢棄的方法。使用內聯參數映射和 parameterType 屬性。 |
flushCache |
將其設置爲 true,任什麼時候候只要語句被調用,都會致使本地緩存和二級緩存都會被清空,默認值:true(對應插入、更新和刪除語句)。 |
timeout |
這個設置是在拋出異常以前,驅動程序等待數據庫返回請求結果的秒數。默認值爲 unset(依賴驅動)。 |
statementType |
STATEMENT,PREPARED 或 CALLABLE 的一個。這會讓 MyBatis 分別使用 Statement,PreparedStatement 或 CallableStatement,默認值:PREPARED。 |
useGeneratedKeys |
(僅對 insert 和 update 有用)這會令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法來取出由數據庫內部生成的主鍵(好比:像 MySQL 和 SQL Server 這樣的關係數據庫管理系統的自動遞增字段),默認值:false。 |
keyProperty |
(僅對 insert 和 update 有用)惟一標記一個屬性,MyBatis 會經過 getGeneratedKeys 的返回值或者經過 insert 語句的 selectKey 子元素設置它的鍵值,默認:unset 。若是但願獲得多個生成的列,也能夠是逗號分隔的屬性名稱列表。 |
keyColumn |
(僅對 insert 和 update 有用)經過生成的鍵值設置表中的列名,這個設置僅在某些數據庫(像 PostgreSQL)是必須的,當主鍵列不是表中的第一列的時候須要設置。若是但願獲得多個生成的列,也能夠是逗號分隔的屬性名稱列表。 |
databaseId |
若是配置了 databaseIdProvider,MyBatis 會加載全部的不帶 databaseId 或匹配當前 databaseId 的語句;若是帶或者不帶的語句都有,則不帶的會被忽略。 |
三個更新操做經常使用的屬性只有兩個:id
、parameterType
,其餘的瞭解便可。
resultMap
元素是 MyBatis 中最重要最強大的元素。它可讓你從 90% 的 JDBC ResultSets
數據提取代碼中解放出來,並在一些情形下容許你作一些 JDBC 不支持的事情。 實際上,在對複雜語句進行聯合映射的時候,它極可能能夠代替數千行的同等功能的代碼。 ResultMap 的設計思想是,簡單的語句不須要明確的結果映射,而複雜一點的語句只須要描述它們的關係就好了。
下面是 resultMap
元素的概念視圖:
constructor
- 用於在實例化類時,注入結果到構造方法中
idArg
- ID 參數;標記出做爲 ID 的結果能夠幫助提升總體性能arg
- 將被注入到構造方法的一個普通結果id
– 一個 ID 結果;標記出做爲 ID 的結果能夠幫助提升總體性能
result
– 注入到字段或 JavaBean 屬性的普通結果
association
– 一個複雜類型的關聯;許多結果將包裝成這種類型
resultMap
元素,或者引用一個collection
– 一個複雜類型的集合
resultMap
元素,或者引用一個discriminator
– 使用結果值來決定使用哪一個
resultMap
case
– 基於某些值的結果映射
case
也是一個映射它自己的結果,所以能夠包含不少相同的元素,或者它能夠參照一個外部的 resultMap
。屬性 | 描述 |
---|---|
id |
當前命名空間中的一個惟一標識,用於標識一個result map. |
type |
類的徹底限定名, 或者一個類型別名 (內置的別名能夠參考上面的表格). |
autoMapping |
若是設置這個屬性,MyBatis將會爲這個ResultMap開啓或者關閉自動映射。這個屬性會覆蓋全局的屬性 autoMappingBehavior。默認值爲:unset。 |
爲了方便理解,再把上面項目中定義的 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 標籤中的屬性表以下:
屬性 | 描述 |
---|---|
property |
映射到列結果的字段或屬性。若是用來匹配的 JavaBeans 存在給定名字的屬性,那麼它將會被使用。不然 MyBatis 將會尋找給定名稱 property 的字段。 不管是哪種情形,你均可以使用一般的點式分隔形式進行復雜屬性導航。好比,你能夠這樣映射一些簡單的東西: 「username」 ,或者映射到一些複雜的東西: 「address.street.number」 。 |
column |
數據庫中的列名,或者是列的別名。通常狀況下,這和 傳遞給 resultSet.getString(columnName) 方法的參數同樣。 |
javaType |
一個 Java 類的徹底限定名,或一個類型別名(參考上面內建類型別名 的列表) 。若是你映射到一個 JavaBean,MyBatis 一般能夠判定類型。 然而,若是你映射到的是 HashMap,那麼你應該明確地指定 javaType 來保證指望的行爲。 |
jdbcType |
JDBC 類型,所支持的 JDBC 類型參見這個表格以後的「支持的 JDBC 類型」。 只須要在可能執行插入、更新和刪除的容許空值的列上指定 JDBC 類型。這是 JDBC 的要求而非 MyBatis 的要求。若是你直接面向 JDBC 編程,你須要對可能爲 null 的值指定這個類型。 |
typeHandler |
咱們在前面討論過的默認類型處理器。使用這個屬性,你能夠覆蓋默 認的類型處理器。這個屬性值是一個類型處理 器實現類的徹底限定名,或者是類型別名。 |
發現有些小夥伴在寫映射文件的時候,都習慣性的把全部的須要傳入的參數都加上 jdbcType=""
,那到底什麼狀況下須要指明,什麼狀況下不須要指明呢?
查閱官方文檔看到了官方的描述:
若是一個列容許 null 值,而且會傳遞值 null 的參數,就必需要指定 JDBC Type。
複製代碼
也就是說只有當一個列容許 null 並有可能傳入 null 時,才必需要指定 JDBC Type,其餘狀況是不須要指定的。固然指定了也沒錯,就是多寫點代碼。
明白了何時須要指定,那還有個問題,java 中的類型跟 jdbcType 的類型如何對應呢?若是對應關係寫錯了也會報錯。下面就整理出了二者的對應關係:
JDBCType
與 JavaType
對應關係
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]
複製代碼
若是查詢返回的結果是個列表怎麼辦?如何提取出可複用的 sql 呢?
平常使用中還有這兩個常見的應用場景,下面就以項目成員表 ProejctMember
來演示一下。
一個項目能夠對應多個成員,因此根據項目 id 查詢成員的話確定查出來多條數據。
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);
}
複製代碼
返回結果是列表的話,映射文件的 result 仍是隻給定 List 內的類型便可。
用 <sql>
標籤來提出出可複用的 sql 語句
<sql id="baseColumns">
id, project_id, project_name, project_avatar, user_id, user_name,
user_avatar, user_role, role_name, status
</sql>
複製代碼
在須要用到的地方用 <include>
標籤引入 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 中的簡單使用方式介紹。
代碼出自開源項目 coderiver
,致力於打造全平臺型全棧精品開源項目。
coderiver 中文名 河碼,是一個爲程序員和設計師提供項目協做的平臺。不管你是前端、後端、移動端開發人員,或是設計師、產品經理,均可以在平臺上發佈項目,與志同道合的小夥伴一塊兒協做完成項目。
coderiver河碼 相似程序員客棧,但主要目的是方便各細分領域人才之間技術交流,共同成長,多人協做完成項目。暫不涉及金錢交易。
計劃作成包含 pc端(Vue、React)、移動H5(Vue、React)、ReactNative混合開發、Android原生、微信小程序、java後端的全平臺型全棧項目,歡迎關注。
您的鼓勵是我前行最大的動力,歡迎點贊,歡迎送小星星✨ ~