MyBatis 与 SpringBoot 整合:注解和xml两种使用方式介绍

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎全部的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。php


不管是使用注解仍是 xml 映射文件配置方式,在使用以前有两步是必须的:前端

  1. 引入依赖java

    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
    </dependency>
    复制代码
  2. 在启动类上加注解 @MapperScan 指明 mapper 类的位置git

    @MapperScan("com.solo.coderiver.project.mapper")
    public class ProjectApplication {
        public static void main(String[] args) {
            SpringApplication.run(ProjectApplication.class, args);
        }
    }
    复制代码

1、注解方式

相比于 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, blockingproperties
@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, selectresultMap。id 属性是布尔值,来标识用于比较的属性,和<idArg> XML 元素类似。
@TypeDiscriminator 方法 <discriminator> 一组实例值被用来决定结果映射的表现。属性有:column, javaType, jdbcType, typeHandlercases。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等)。请在插入语句一节查看更多关于 keyColumnkeyProperty 二者的有效值详情。
@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, methodtype 属性需填入类。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 填入 truefalse 以指明 SQL 语句应被在插入语句的以前仍是以后执行。resultType 填入 keyProperty 的 Java 类型和用 StatementPreparedStatementCallableStatement 中的 STATEMENTPREPAREDCALLABLE 中任一值填入 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及以上)

2、xml 方式使用

2.1 快速实现

xml 配置方式使用 MyBatis 主要步骤有如下三步:sql

  1. 配置 application.yml
  2. 编写 mapper xml 文件
  3. 写 mapper java 代码

1. 配置 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
复制代码

2. 编写 mapper xml 映射文件

以项目类型 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>
复制代码

后面会讲配置的详细属性。

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);
}
复制代码

新建一个接口,方法名要跟 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;
    }
}
复制代码

2.2 xml 映射文件详解

SQL 映射文件有不多的几个顶级元素(按照它们应该被定义的顺序):

  • cache – 给定命名空间的缓存配置。
  • cache-ref – 其余命名空间缓存配置的引用。
  • resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。
  • parameterMap – 已废弃!老式风格的参数映射。内联参数是首选,这个元素可能在未来被移除,这里不会记录。
  • sql – 可被其余语句引用的可重用语句块。
  • insert – 映射插入语句
  • update – 映射更新语句
  • delete – 映射删除语句
  • select – 映射查询语句

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 经常使用的属性其实就是 idparameterTyperesultMap 三个,其余的了解便可。

insert, update 和 delete

数据变动语句 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 的语句;若是带或者不带的语句都有,则不带的会被忽略。

三个更新操做经常使用的属性只有两个:idparameterType,其余的了解便可。

Result Maps

resultMap 元素是 MyBatis 中最重要最强大的元素。它可让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下容许你作一些 JDBC 不支持的事情。 实际上,在对复杂语句进行联合映射的时候,它极可能能够代替数千行的同等功能的代码。 ResultMap 的设计思想是,简单的语句不须要明确的结果映射,而复杂一点的语句只须要描述它们的关系就好了。

下面是 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

发现有些小伙伴在写映射文件的时候,都习惯性的把全部的须要传入的参数都加上 jdbcType="",那到底什么状况下须要指明,什么状况下不须要指明呢?

查阅官方文档看到了官方的描述:

若是一个列容许 null 值,而且会传递值 null 的参数,就必需要指定 JDBC Type。
复制代码

也就是说只有当一个列容许 null 并有可能传入 null 时,才必需要指定 JDBC Type,其余状况是不须要指定的。固然指定了也没错,就是多写点代码。

明白了何时须要指定,那还有个问题,java 中的类型跟 jdbcType 的类型如何对应呢?若是对应关系写错了也会报错。下面就整理出了二者的对应关系:

JDBCTypeJavaType 对应关系

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 补充

若是查询返回的结果是个列表怎么办?如何提取出可复用的 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后端的全平台型全栈项目,欢迎关注。

项目地址:github.com/cachecats/c…

您的鼓励是我前行最大的动力,欢迎点赞,欢迎送小星星✨ ~

相关文章
相关标签/搜索