MyBatis开发详解

news2025/7/19 3:50:47

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录

一、MyBatis四个核心组件

1.SqlSessionFactoryBuilder(构造器)

它会根据配置或者代码来生成SqlSessionFactory,采用的是分布构建的Builder模式

2.SqlSessionFactory(工厂接口)

依靠它来生成SqlSession,使用的是工厂模式。对于事务隔离级别,MyBatis 使用了一个 Java 枚举包装器来表示,称为 TransactionIsolationLevel,事务隔离级别支持 JDBC 的五个隔离级别(NONE、READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ 和 SERIALIZABLE),并且与预期的行为一致。

3.SqlSession(会话)

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。一个既可以发送SQL执行返回结果,也可以获取Mapper的接口,在现有的技术中,一般我们会让其在业务逻辑代码中"消失",而使用的是MyBatis提供的SQL Mapper接口编程技术,它能够提高代码的可读性和可维护性

4.本地缓存

Mybatis 使用到了两种缓存:本地缓存(local cache)和二级缓存(second level cache)。

每当一个新 session 被创建,MyBatis 就会创建一个与之相关联的本地缓存。任何在 session 执行过的查询结果都会被保存在本地缓存中,所以,当再次执行参数相同的相同查询时,就不需要实际查询数据库了。本地缓存将会在做出修改、事务提交或回滚,以及关闭 session 时清空。

默认情况下,本地缓存数据的生命周期等同于整个session的周期。由于缓存会被用来解决循环引用问题和加快重复嵌套查询的速度,所以无法将其完全禁用。但是你可以通过设置 localCacheScope=STATEMENT 来只在语句执行时使用缓存。

注意,如果 localCacheScope 被设置为 SESSION,对于某个对象,MyBatis 将返回在本地缓存中唯一对象的引用。对返回的对象(例如 list)做出的任何修改将会影响本地缓存的内容,进而将会影响到在本次 session 中从缓存返回的值。因此,不要对 MyBatis 所返回的对象作出更改,以防后患。

你可以随时调用以下方法来清空本地缓存:

void clearCache()

确保 SqlSession 被关闭

void close()

对于你打开的任何 session,你都要保证它们被妥善关闭,这很重要。保证妥善关闭的最佳代码模式是这样的:

SqlSession session = sqlSessionFactory.openSession();
try (SqlSession session = sqlSessionFactory.openSession()) {
    // 假设下面三行代码是你的业务逻辑
    session.insert(...);
    session.update(...);
    session.delete(...);
    session.commit();
} 
try (SqlSession session = sqlSessionFactory.openSession()) {
  // 你的应用逻辑代码
}

5.SQL Mapper(映射器)

映射器是一些绑定映射语句的接口。映射器接口的实例是从 SqlSession 中获得的。MyBatis新设计存在的组件,它是由一个Java接口和XML文件(或注解)构成,需要给出对应的SQL和映射规则,它负责发送SQL去执行,并返回结果

try (SqlSession session = sqlSessionFactory.openSession()) {
  BlogMapper mapper = session.getMapper(BlogMapper.class);
  // 你的应用逻辑代码
}

映射器的配置元素

映射器注解

设计初期的 MyBatis 是一个 XML 驱动的框架。配置信息是基于 XML 的,映射语句也是定义在 XML 中的。而在 MyBatis 3 中,我们提供了其它的配置方式。MyBatis 3 构建在全面且强大的基于 Java 语言的配置 API 之上。它是 XML 和注解配置的基础。注解提供了一种简单且低成本的方式来实现简单的映射语句。

提示 不幸的是,Java 注解的表达能力和灵活性十分有限。尽管我们花了很多时间在调查、设计和试验上,但最强大的 MyBatis 映射并不能用注解来构建——我们真没开玩笑。而 C# 属性就没有这些限制,因此 MyBatis.NET 的配置会比 XML 有更大的选择余地。虽说如此,基于 Java 注解的配置还是有它的好处的。

注解如下表所示:

注解

使用对象

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>

引用另外一个命名空间的缓存以供使用。注意,即使共享相同的全限定类名,在 XML 映射文件中声明的缓存仍被识别为一个独立的命名空间。属性:value、name。如果你使用了这个注解,你应设置 value 或者 name 属性的其中一个。value 属性用于指定能够表示该命名空间的 Java 类型(命名空间名就是该 Java 类型的全限定类名),name 属性(这个属性仅在 MyBatis 3.4.2 以上可用)则直接指定了命名空间的名字。

@ConstructorArgs

方法

<constructor>

收集一组结果以传递给一个结果对象的构造方法。属性:value,它是一个 Arg 数组。

@Arg

N/A

<arg>

<idArg>

ConstructorArgs 集合的一部分,代表一个构造方法参数。属性:id、column、javaType、jdbcType、typeHandler、select、resultMap。id 属性和 XML 元素 <idArg> 相似,它是一个布尔值,表示该属性是否用于唯一标识和比较对象。从版本 3.5.4 开始,该注解变为可重复注解。

@TypeDiscriminator

方法

<discriminator>

决定使用何种结果映射的一组取值(case)。属性:column、javaType、jdbcType、typeHandler、cases。cases 属性是一个 Case 的数组。

@Case

N/A

<case>

表示某个值的一个取值以及该取值对应的映射。属性:value、type、results。results 属性是一个 Results 的数组,因此这个注解实际上和 ResultMap 很相似,由下面的 Results 注解指定。

@Results

方法

<resultMap>

一组结果映射,指定了对某个特定结果列,映射到某个属性或字段的方式。属性:value、id。value 属性是一个 Result 注解的数组。而 id 属性则是结果映射的名称。从版本 3.5.4 开始,该注解变为可重复注解。

@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; resultMap(3.5.5以上可用), 结果集的完全限定名,该结果映射到查询结果中的集合对象; columnPrefix(3.5.5以上可用),在嵌套的结果集中对所查询的列进行分组的列前缀。 提示 注解 API 不支持联合映射。这是由于 Java 注解不允许产生循环引用。

@Many

N/A

<collection>

复杂类型的集合属性映射。属性: select,指定可加载合适类型实例集合的映射语句(也就是映射器方法)全限定名; fetchType,指定在该映射中覆盖全局配置参数 lazyLoadingEnabled ; resultMap(3.5.5以上可用),结果集的完全限定名,该结果映射到查询结果中的集合对象; columnPrefix(3.5.5以上可用),在嵌套的结果集中对所查询的列进行分组的列前缀。 提示 注解 API 不支持联合映射。这是由于 Java 注解不允许产生循环引用。

@MapKey

方法

供返回值为 Map 的方法使用的注解。它使用对象的某个属性作为 key,将对象 List 转化为 Map。属性:value,指定作为 Map 的 key 值的对象属性名。

@Options

方法

映射语句的属性

该注解允许你指定大部分开关和配置选项,它们通常在映射语句上作为属性出现。与在注解上提供大量的属性相比,Options 注解提供了一致、清晰的方式来指定选项。属性:useCache=true、flushCache=FlushCachePolicy.DEFAULT、resultSetType=DEFAULT、statementType=PREPARED、fetchSize=-1、timeout=-1、useGeneratedKeys=false、keyProperty=""、keyColumn=""、resultSets="", databaseId=""。注意,Java 注解无法指定 null 值。因此,一旦你使用了 Options 注解,你的语句就会被上述属性的默认值所影响。要注意避免默认值带来的非预期行为。 databaseId(3.5.5以上可用), 如果有一个配置好的 DatabaseIdProvider, MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的所有语句。如果同时存在带 databaseId 和不带 databaseId 属性的相同语句,则后者会被舍弃。

注意:keyColumn 属性只在某些数据库中有效(如 Oracle、PostgreSQL 等)。要了解更多关于 keyColumn 和 keyProperty 可选值信息,请查看“insert, update 和 delete”一节。

@Insert

@Update

@Delete

@Select

方法

<insert>

<update>

<delete>

<select>

每个注解分别代表将会被执行的 SQL 语句。它们用字符串数组(或单个字符串)作为参数。如果传递的是字符串数组,字符串数组会被连接成单个完整的字符串,每个字符串之间加入一个空格。这有效地避免了用 Java 代码构建 SQL 语句时产生的“丢失空格”问题。当然,你也可以提前手动连接好字符串。属性:value,指定用来组成单个 SQL 语句的字符串数组。 databaseId(3.5.5以上可用), 如果有一个配置好的 DatabaseIdProvider, MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的所有语句。如果同时存在带 databaseId 和不带 databaseId 属性的相同语句,则后者会被舍弃。

@InsertProvider

@UpdateProvider

@DeleteProvider

@SelectProvider

方法

<insert>

<update>

<delete>

<select>

允许构建动态 SQL。这些备选的 SQL 注解允许你指定返回 SQL 语句的类和方法,以供运行时执行。(从 MyBatis 3.4.6 开始,可以使用 CharSequence 代替 String 来作为返回类型)。当执行映射语句时,MyBatis 会实例化注解指定的类,并调用注解指定的方法。你可以通过 ProviderContext 传递映射方法接收到的参数、"Mapper interface type" 和 "Mapper method"(仅在 MyBatis 3.4.5 以上支持)作为参数。(MyBatis 3.4 以上支持传入多个参数) 属性:value、type、method、databaseId。 value and type 属性用于指定类名 (type 属性是 value 的别名, 你必须指定任意一个。 但是你如果在全局配置中指定 defaultSqlProviderType ,两个属性都可以忽略)。 method 用于指定该类的方法名(从版本 3.5.1 开始,可以省略 method 属性,MyBatis 将会使用 ProviderMethodResolver 接口解析方法的具体实现。如果解析失败,MyBatis 将会使用名为 provideSql 的降级实现)。提示 接下来的“SQL 语句构建器”一章将会讨论该话题,以帮助你以更清晰、更便于阅读的方式构建动态 SQL。 databaseId(3.5.5以上可用), 如果有一个配置好的 DatabaseIdProvider, MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的所有语句。如果同时存在带 databaseId 和不带 databaseId 属性的相同语句,则后者会被舍弃。

@Param

参数

N/A

如果你的映射方法接受多个参数,就可以使用这个注解自定义每个参数的名字。否则在默认情况下,除 RowBounds 以外的参数会以 "param" 加参数位置被命名。例如 #{param1}, #{param2}。如果使用了 @Param("person"),参数就会被命名为 #{person}。

@SelectKey

方法

<selectKey>

这个注解的功能与 <selectKey> 标签完全一致。该注解只能在 @Insert 或 @InsertProvider 或 @Update 或 @UpdateProvider 标注的方法上使用,否则将会被忽略。如果标注了 @SelectKey 注解,MyBatis 将会忽略掉由 @Options 注解所设置的生成主键或设置(configuration)属性。属性:statement 以字符串数组形式指定将会被执行的 SQL 语句,keyProperty 指定作为参数传入的对象对应属性的名称,该属性将会更新成新的值,before 可以指定为 true 或 false 以指明 SQL 语句应被在插入语句的之前还是之后执行。resultType 则指定 keyProperty 的 Java 类型。statementType 则用于选择语句类型,可以选择 STATEMENT、PREPARED 或 CALLABLE 之一,它们分别对应于 Statement、PreparedStatement 和 CallableStatement。默认值是 PREPARED。 databaseId(3.5.5以上可用), 如果有一个配置好的 DatabaseIdProvider, MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的所有语句。如果同时存在带 databaseId 和不带 databaseId 属性的相同语句,则后者会被舍弃。

@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 以上可用)

映射注解示例

这个例子展示了如何使用 @SelectKey 注解来在插入前读取数据库序列的值:

@Insert("insert into table3 (id, name) values(#{nameId}, #{name})")
@SelectKey(statement="call next value for TestSequence", keyProperty="nameId", before=true, resultType=int.class)
int insertTable3(Name name);

这个例子展示了如何使用 @SelectKey 注解来在插入后读取数据库自增列的值:

@Insert("insert into table2 (name) values(#{name})")
@SelectKey(statement="call identity()", keyProperty="nameId", before=false, resultType=int.class)
int insertTable2(Name name);

这个例子展示了如何使用 @Flush 注解来调用 SqlSession#flushStatements():

@Flush
List<BatchResult> flush();

这些例子展示了如何通过指定 @Result 的 id 属性来命名结果集:

@Results(id = "userResult", value = {
  @Result(property = "id", column = "uid", id = true),
  @Result(property = "firstName", column = "first_name"),
  @Result(property = "lastName", column = "last_name")
})
@Select("select * from users where id = #{id}")
User getUserById(Integer id);

@Results(id = "companyResults")
@ConstructorArgs({
  @Arg(column = "cid", javaType = Integer.class, id = true),
  @Arg(column = "name", javaType = String.class)
})
@Select("select * from company where id = #{id}")
Company getCompanyById(Integer id);

二 、支持数据库

MySQL,Oracle,DB2,H2,HSQL,SQLite,PostgreSQL,SQLServer,Phoenix,Gauss ,ClickHouse,Sybase,OceanBase,Firebird,Cubrid,Goldilocks,csiidb

三、动态 SQL

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。

如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

  • if

  • choose (when, otherwise)

  • trim (where, set)

  • foreach

1.if

使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分。比如:

<select id="findActiveBlogWithTitleLike"
     resultType="Blog">
  SELECT * FROM BLOG
  WHERE state = ‘ACTIVE’
  <if test="title != null">
    AND title like #{title}
  </if>
</select>

这条语句提供了可选的查找文本功能。如果不传入 “title”,那么所有处于 “ACTIVE” 状态的 BLOG 都会返回;如果传入了 “title” 参数,那么就会对 “title” 一列进行模糊查找并返回对应的 BLOG 结果(细心的读者可能会发现,“title” 的参数值需要包含查找掩码或通配符字符)。

如果希望通过 “title” 和 “author” 两个参数进行可选搜索该怎么办呢?首先,我想先将语句名称修改成更名副其实的名称;接下来,只需要加入另一个条件即可。

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <if test="title != null">
    AND title like #{title}
  </if>
  <if test="author != null and author.name != null">
    AND author_name like #{author.name}
  </if>
</select>

2.choose、when、otherwise

有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

还是上面的例子,但是策略变为:传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,就返回标记为 featured 的 BLOG(这可能是管理员认为,与其返回大量的无意义随机 Blog,还不如返回一些由管理员精选的 Blog)。

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <choose>
    <when test="title != null">
      AND title like #{title}
    </when>
    <when test="author != null and author.name != null">
      AND author_name like #{author.name}
    </when>
    <otherwise>
      AND featured = 1
    </otherwise>
  </choose>
</select>

3.trim、where、set

前面几个例子已经方便地解决了一个臭名昭著的动态 SQL 问题。现在回到之前的 “if” 示例,这次我们将 “state = ‘ACTIVE’” 设置成动态条件,看看会发生什么。

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG
  WHERE
  <if test="state != null">
    state = #{state}
  </if>
  <if test="title != null">
    AND title like #{title}
  </if>
  <if test="author != null and author.name != null">
    AND author_name like #{author.name}
  </if>
</select>

如果没有匹配的条件会怎么样?最终这条 SQL 会变成这样:

SELECT * FROM BLOG
WHERE

这会导致查询失败。如果匹配的只是第二个条件又会怎样?这条 SQL 会是这样:

SELECT * FROM BLOG
WHERE
AND title like ‘someTitle’

这个查询也会失败。这个问题不能简单地用条件元素来解决。这个问题是如此的难以解决,以至于解决过的人不会再想碰到这种问题。

MyBatis 有一个简单且适合大多数场景的解决办法。而在其他场景中,可以对其进行自定义以符合需求。而这,只需要一处简单的改动:

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG
  <where>
    <if test="state != null">
         state = #{state}
    </if>
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
  </where>
</select>

where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>

prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。

用于动态更新语句的类似解决方案叫做 setset 元素可以用于动态包含需要更新的列,忽略其它不更新的列。比如:

<update id="updateAuthorIfNecessary">
  update Author
    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="bio != null">bio=#{bio}</if>
    </set>
  where id=#{id}
</update>

这个例子中,set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。

或者,你可以通过使用trim元素来达到同样的效果:

<trim prefix="SET" suffixOverrides=",">
  ...
</trim>

4.foreach

动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。比如:

<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT *
  FROM POST P
  <where>
    <foreach item="item" index="index" collection="list"
        open="ID in (" separator="," close=")" nullable="true">
          #{item}
    </foreach>
  </where>
</select>

foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!

提示 你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

至此,我们已经完成了与 XML 配置及映射文件相关的讨论。下一章将详细探讨 Java API,以便你能充分利用已经创建的映射配置。

5.script

要在带注解的映射器接口类中使用动态 SQL,可以使用 script 元素。比如:

@Update({"<script>",
      "update Author",
      "  <set>",
      "    <if test='username != null'>username=#{username},</if>",
      "    <if test='password != null'>password=#{password},</if>",
      "    <if test='email != null'>email=#{email},</if>",
      "    <if test='bio != null'>bio=#{bio}</if>",
      "  </set>",
      "where id=#{id}",
      "</script>"})
    void updateAuthorValues(Author author);

6.bind

bind 元素允许你在 OGNL 表达式以外创建一个变量,并将其绑定到当前的上下文。比如:

<select id="selectBlogsLike" resultType="Blog">
  <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
  SELECT * FROM BLOG
  WHERE title LIKE #{pattern}
</select>

7.多数据库支持

如果配置了 databaseIdProvider,你就可以在动态代码中使用名为 “_databaseId” 的变量来为不同的数据库构建特定的语句。比如下面的例子:

<insert id="insert">
  <selectKey keyProperty="id" resultType="int" order="BEFORE">
    <if test="_databaseId == 'oracle'">
      select seq_users.nextval from dual
    </if>
    <if test="_databaseId == 'db2'">
      select nextval for seq_users from sysibm.sysdummy1"
    </if>
  </selectKey>
  insert into users values (#{id}, #{name})
</insert>

四 、开发实例

在Spring Boot中使用MyBatis可以使用2种方式:

  1. 使用在Spring框架中集成MyBatis的原生集成方式

  1. 使用插件MyBatis-Spring-Boot-Starter集成MyBatis

这里就只介绍第二种了。

1. 引入依赖:

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>x.x.x</version>
</dependency>

2. 配置数据源

在使用数据库之前先要在Spring Boot中配置数据源,如下所示:

spring: 
    datasource: 
        name: testDatasource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/test_springboot
        username: root
        password: 
    mybatis:
    check-config-location: true                             # 是否检测MyBatis运行参数配置文件
    config-location: classpath:/mybatis-config.xml          # 指定MyBatis运行参数配置文件位置
    mapper-locations: classpath:/mapper/**/*.xml            # 注册XML映射器
    type-aliases-package: test.springboot.model             # 配置Java类型包名
    type-handlers-package: test.springboot.handlers         # 配置类型处理器包名
    executor-type: SIMPLE                                   # 指定执行器类型
    configuration:
        default-fetch-size: 20
        default-statement-timeout: 30

3.默认配置

默认情况下,插件MyBatis-Spring-Boot-Starter将进行如下配置:

  • 自动检查Spring Boot的数据源配置并构建DataSource对象

  • 通过SqlSessionFactoryBean使用数据源构建并注册SqlSessionFactory对象

  • 从SqlSessionFactory中创建并注册一个SqlSessionTemplate实例,其实就是构建一个SqlSession对象

  • 自动扫描接口映射器,并将这些映射器与SqlSessionTemplate实例进行关联,同时将它们注册到Spring容器中

其实上述这些默认配置就是我们在原生集成MyBatis方式中做的事情,只不过在Spring Boot中通过插件MyBatis-Spring-Boot-Starter自动完成了。只要理解了这一点,就会明白如何在Spring Boot中灵活使用MyBatis组件了。 既然MyBatis的配置已经完成了,那么下一步的工作就是如何编写和使用接口映射器。

1.定义接口映射器

@Mapper
public interface AccMapper {
    @Select("select * from account where id = #{id}")
    Account getAccount(@Param("id") long id);
}

插件MyBatis-Spring-Boot-Starter会自动搜索使用了注解@Mapper的接口映射器并将其注册到Spring容器中,因此在这里不能使用@Repository注解标记MyBatis的映射器接口,这与原生方式集成MyBatis有所不同。

2.使用接口映射器

@RestController
@RequestMapping("/acc")
public class AccController {
    // 直接通过自动注入的方式使用接口映射器
    @Autowired
    AccMapper accMapper;

    @GetMapping("/{id}")
    @ResponseBody
    public Object acc(@PathVariable("id") long id) {
        return accMapper.getAccount(id);
    }
}

至此可以看到,在Spring Boot中通过插件MyBatis-Spring-Boot-Starter集成MyBatis时非常方便,只需要添加基本的数据源配置就可以使用了。当然,如果需要使用MyBatis更加高级的功能(如:使用xml映射器,定制MyBatis运行时参数),使用默认配置是无法实现的,必须在此基础上对MyBatis进行高级的定制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/395628.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

信息系统基本知识(五)信息系统安全技术

大纲 信息系统与信息化信息系统开发方法常规信息系统集成技术软件工程新一代信息技术信息系统安全技术信息化发展与应用信息系统服务管理信息系统服务规划企业首席信息管及其责任 1.6 信息系统安全技术 1.6.1 信息系统安全的有关概念 信息安全的概念&#xff1a;信息安全强…

机器人向生产力系统迈进,优艾智合稳步“从1到100”

在中国&#xff0c;机器人的“成长”总是令人惊讶。这些“钢铁生命”和“芯片生命”&#xff0c;在工厂流水线、物流仓储园区、机房电站飞速复制&#xff0c;充当产业的手、眼和大脑。国际机器人联合会IFR的数据显示&#xff0c;2020-2024年&#xff0c;中国机器人市场规模CAGR…

源码解析——HashMap

源码解析——HashMap1. 什么 是HashMap2. 为什么要使用HashMap3. HashMap的使用4. 源码解析4.1 关键问题4.1 存储结构4.2 HashMap 的容量和负载因子4.3 初始化过程4.3 put() 方法实现原理4.3.1 hash()4.3.2 resize()4.4 get() 方法实现原理5. 面试题总结6. ConcurrentHashmap(J…

【办公类-16-06】“2022下学期 总园活动室(沙水+建构)排班表”(python 排班表系列)

背景需求&#xff1a;最近保教主任一直在为总园的活动室安排而头疼不已&#xff0c;和组长们商议许久&#xff0c;依旧无法合理把活动室安排好。3月2日下午&#xff0c;听主任和游戏室成员聊了一个小时的排班&#xff0c;结论是除沙水和建构外&#xff0c;其余空余时间都是”自…

【RGB3DS道路检测车智慧运维解决方案】助力城市道路运维数字化转型

随着数字城市建设的全面推进&#xff0c;交通运维数字化转型也逐步进入新的层次。道路表观病害检测作为养护运维的基础和关键环节&#xff0c;亟待投入更多关注。 针对国家对交通运维数字化转型的相关要求与及时有效评估路面健康情况的需求&#xff0c;博雅弘拓科技力推【RGB3…

互联网大厂效率到底有多高?且看大腕怎么说

互联网公司的效率到底有多高&#xff1f; 看抖音创始人张一鸣怎么说 趣讲大白话&#xff1a;组织能力是关键 【趣讲信息科技96期】 ******************************* 对组织而言需要把优秀的标准清晰无误的传递且不断精进。含糊和混淆其实是牺牲。——抖音创始人张一鸣。 把信…

面向对象设计模式:结构型模式之适配器模式

一、引入 Object Oriented Adapters 二、XX 模式 aka&#xff1a;Wrapper (包装器) 2.1 Intent 意图 Convert the interface of a class into another interface clients expect. 将一个类的接口转换成客户希望的另外一个接口. 作为两个不兼容的接口之间的桥梁 适配器模式使…

Leetcode.1359 有效的快递序列数目

题目链接 Leetcode.1359 有效的快递序列数目 Rating &#xff1a; 1723 题目描述 给你 n笔订单&#xff0c;每笔订单都需要快递服务。 请你统计所有有效的 收件/配送 序列的数目&#xff0c;确保第 i 个物品的配送服务 delivery(i)总是在其收件服务 pickup(i)之后。 由于答案…

Locally Differentially Private Protocols for Frequency Estimation论文笔记

文章目录1.Pure LDP Protocol1.1相关背景1.2支持集1.3相关定义2.Basic one-time RAPPOR3.Rappor4.Direct Encoding4.1GRR4.2RR5.Unary Encoding5.1Symmetric Unary Encoding5.1Optimized Unary Encoding6.Local Hashing6.1Binary Local Hashing6.2Local Hashing6.3Optimal Loca…

Java后端实现Excel导入和导出

文章目录前言1.1准备1.2 Excel导入1.2.1 解析为JSON1.2.2 解析为对象&#xff08;基础&#xff09;1.2.3 解析为对象&#xff08;字段自动映射&#xff09;1.2.4 解析为对象&#xff08;获取行号&#xff09;1.2.5 解析为对象&#xff08;获取原始数据&#xff09;1.2.6 解析为…

JavaScript 条件语句 If ... Else实例集合

文章目录JavaScript 条件语句 If ... Else实例集合If 语句If...else 语句随机链接Switch 语句JavaScript 条件语句 If … Else实例集合 If 语句 源码 <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>梁辰兴实例</t…

stack_queue

目录&#xff1a;stack的介绍stack的使用stack的模拟实现queue的介绍queue的使用queue的模拟实现容器适配器是什么priority_queue的介绍priority_queue的使用priority_queue的模拟实现为什么要引“#include<functional>”头文件&#xff1f;回调函数仿函数stack的介绍 s…

无线蓝牙耳机佩戴舒适的有哪几款?入耳舒适的蓝牙耳机推荐

耳机已经成了现代年轻人不可缺少的东西&#xff0c;选择一款佩戴舒适的蓝牙耳机&#xff0c;使人幸福感爆棚&#xff0c;并且还能感受导音质出色声音表现力&#xff0c;下面整理了几款入耳舒适的耳机。 一、南卡小音舱蓝牙耳机 单耳重量&#xff1a;3.1g 佩戴类型&#xff1a…

FISCO BCOS(二十八)———使用java SDK与区块链交互

一、基本环境准备 1、部署配置jdk1.8 https://blog.csdn.net/weixin_46457946/article/details/1232435132、搭建单群组FISCO BCOS联盟链 https://blog.csdn.net/weixin_46457946/article/details/1225463343、配置及使用控制台 https://blog.csdn.net/weixin_46457946/art…

Vue2的基本使用

一、vue的基本使用 第一步 引入vue.js文件 <script src"https://cdn.staticfile.org/vue/2.7.0/vue.min.js"></script> 或者<script src"./js/vue.js"></script> 第二步 在body中设置一个挂载点 {{msg}} <div id"app…

Web3中的营销:如何在2023年获得优势

Mar. 2022, Daniel在过去的一年里&#xff0c;让人们对你的Web3项目或协议感兴趣已经变得越来越有挑战性。许多曾经充满希望的项目因为各种不同的原因&#xff0c;都在熊市中倒下了。然而&#xff0c;那些迄今为止幸存下来的项目都有一个共同点&#xff1a;强大的社区。Web3营销…

九龙证券“风光储锂芯”集体回暖 创业板指探低回升

周一&#xff0c;A股三大指数体现分解&#xff0c;沪指微跌&#xff0c;创业板指探低上升小幅上涨。盘面上&#xff0c;“风景储锂芯”集体反弹&#xff0c;6G概念再度大涨&#xff0c;消费股午后逆势走强&#xff0c;酒店旅游方向领涨&#xff0c;而前期热门的数字经济概念震动…

OpenCV实战(13)——高通滤波器及其应用

OpenCV实战&#xff08;13&#xff09;——高通滤波器以及应用0. 前言1. 检测图像边缘1.2 Sobel 滤波器1.2 梯度算子1.3 高斯导数2. 图像拉普拉斯算子2.1 拉普拉斯算子2.2 使用拉普拉斯算子增强图像的对比度2.3 高斯差3. 完整代码小结系列链接0. 前言 在频域分析中&#xff0c…

谷歌霸屏外推技术原理,谷歌留痕霸屏怎么做?

首先&#xff0c;让我解释一下谷歌霸屏外推技术原理 谷歌霸屏外推是指拥有一批网站资源&#xff0c;这些网站旨在通过搜索引擎优化技术提高排名&#xff0c;并将流量引导到主要网站。 这些网站通常具有相似的设计和内容&#xff0c;但使用不同的域名和IP地址。 如果您想通过…

C++中的谓词、空指针与野指针、内存四区、引用的详细介绍——C++学习记录05

文章目录1. 谓词2. 空指针与野指针3. 指针常量、常量指针与常量指针常量4.内存四区4.1 代码区&#xff1a;存放函数体的二进制代码4.2 全局区&#xff1a;4.3 栈区&#xff1a;4.4 堆区&#xff1a;5. 引用5.1基本定义5.2 引用做形参5.3 引用的本质5.4 常量引用1. 谓词 定义&a…