MyBatis 與 SpringBoot 整合:注解和xml兩種使用方式介紹

MyBatis 是一款優(yōu)秀的持久層框架荡含,它支持定制化 SQL、存儲過程以及高級映射届垫。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設(shè)置參數(shù)以及獲取結(jié)果集释液。MyBatis 可以使用簡單的 XML 或注解來配置和映射原生信息,將接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java對象)映射成數(shù)據(jù)庫中的記錄装处。


無論是使用注解還是 xml 映射文件配置方式误债,在使用之前有兩步是必須的:

  1. 引入依賴

    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
    </dependency>
    
  2. 在啟動類上加注解 @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, blockingproperties
@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, selectresultMap横漏。id 屬性是布爾值,來標(biāo)識用于比較的屬性熟掂,和<idArg> XML 元素相似缎浇。
@TypeDiscriminator 方法 <discriminator> 一組實(shí)例值被用來決定結(jié)果映射的表現(xiàn)。屬性有:column, javaType, jdbcType, typeHandlercases赴肚。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)于 keyColumnkeyProperty 兩者的有效值詳情逗概。
@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 填入 truefalse 以指明 SQL 語句應(yīng)被在插入語句的之前還是之后執(zhí)行败玉。resultType 填入 keyProperty 的 Java 類型和用 Statement敌土、 PreparedStatementCallableStatement 中的 STATEMENTPREPAREDCALLABLE 中任一值填入 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 主要步驟有以下三步:

  1. 配置 application.yml
  2. 編寫 mapper xml 文件
  3. 寫 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è)
  • collection

    – 一個(gè)復(fù)雜類型的集合

    • 嵌套結(jié)果映射 – 集合可以指定為一個(gè) resultMap 元素,或者引用一個(gè)
  • discriminator

    – 使用結(jié)果值來決定使用哪個(gè)

    resultMap

    • case

      – 基于某些值的結(jié)果映射

      • 嵌套結(jié)果映射 – 一個(gè) case 也是一個(gè)映射它本身的結(jié)果,因此可以包含很多相同的元素滤灯,或者它可以參照一個(gè)外部的 resultMap坪稽。
屬性 描述
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)系:

JDBCTypeJavaType 對應(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)贊邀桑,歡迎送小星星? ~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市科乎,隨后出現(xiàn)的幾起案子壁畸,更是在濱河造成了極大的恐慌,老刑警劉巖茅茂,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捏萍,死亡現(xiàn)場離奇詭異,居然都是意外死亡玉吁,警方通過查閱死者的電腦和手機(jī)照弥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來进副,“玉大人,你說我怎么就攤上這事∮鞍撸” “怎么了给赞?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長矫户。 經(jīng)常有香客問我片迅,道長,這世上最難降的妖魔是什么皆辽? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任柑蛇,我火速辦了婚禮,結(jié)果婚禮上驱闷,老公的妹妹穿的比我還像新娘耻台。我一直安慰自己,他們只是感情好空另,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布盆耽。 她就那樣靜靜地躺著,像睡著了一般扼菠。 火紅的嫁衣襯著肌膚如雪摄杂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天循榆,我揣著相機(jī)與錄音析恢,去河邊找鬼。 笑死秧饮,一個(gè)胖子當(dāng)著我的面吹牛氮昧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播浦楣,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼袖肥,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了振劳?” 一聲冷哼從身側(cè)響起椎组,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎历恐,沒想到半個(gè)月后寸癌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡弱贼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年蒸苇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吮旅。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡溪烤,死狀恐怖味咳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情檬嘀,我是刑警寧澤槽驶,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站鸳兽,受9級特大地震影響掂铐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜揍异,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一全陨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧衷掷,春花似錦辱姨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至渡处,卻和暖如春镜悉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背医瘫。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工侣肄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人醇份。 一個(gè)月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓稼锅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親僚纷。 傳聞我的和親對象是個(gè)殘疾皇子矩距,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容