学习在 Spring Boot 中整合 MyBatis 通用 Mapper(TkMybatis)。通用 Mapper 是一个可以实现任意 MyBatis 通用方法的框架,项目提供了常规的增删改查操作以及 Example 相关的单表操作。通用 Mapper 是为了解决 MyBatis 使用中 90% 的基本操作,使用它可以很方便的进行开发,可以节省开发人员大量的时间。
1 概述
通用 Mapper 都可以极大的方便开发人员。可以随意的按照自己的需要选择通用方法,还可以很方便的开发自己的通用方法。
极其方便的使用 MyBatis 单表的增删改查。
支持单表操作,不支持通用的多表联合查询。
使用通用 Mapper 可以无 xml 文件实现数据库操作,只需要继承 TkMybatis 中相关的 Mapper 接口即可。但如果有特殊需求,可以自定义 XXXMapper.xml 文件,实现复杂 sql 语句的操作。
为什么需要通用 Mapper ?
我个人最早用 MyBatis 时,先是完全手写,然后用上了 MyBatis 代码生成器(简称为 MBG),在使用 MBG 过程中,发现一个很麻烦的问题,如果数据库字段变化很频繁,就需要反复重新生成代码,并且由于 MBG 覆盖生成代码和追加方式生成 XML,导致每次重新生成都需要大量的比对修改。除了这个问题外,还有一个问题,仅仅基础的增删改查等方法,就已经产生了大量的 XML 内容,还没有添加一个自己手写的方法,代码可能就已经几百行了,内容多,看着比较碍事。
因为很多人都在使用 MBG,MBG 中定义了很多常用的单表方法,为了解决前面提到的问题,也为了兼容 MBG 的方法避免项目重构太多,在 MBG 的基础上结合了部分 JPA 注解产生了通用 Mapper。通用 Mapper 可以很简单的让你获取基础的单表方法,也很方便扩展通用方法。使用通用 Mapper 可以极大的提高你的工作效率。
说明:我们也可以改造 MBG ,比如自动生成一套基本的 model/mapper/service 等,与表对应,不去做修改,自定义的都写在对应的另一个子类上,这样,当表字段修改后,只需全部重新生成上述基本的那些文件,再手动修改自定义的文件(如果有需要)即可。
2 基本使用
创建项目,引入依赖
创建 Spring Boot 项目 spring-boot-mybatis-tkmybatis
,添加 Web/MySQL Driver
依赖,如下:

之后手动在 pom 文件中添加 Druid/
依赖(Spring Boot 版本),最终的依赖如下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>5.1.27</version>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.1.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>复制
接着在 application.properties
配置文件中添加数据库相关信息的配置,如下:
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=000000
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/cxy35?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&autoReconnectForPools=true复制
新建实体类
手动新建或用代码生成器生成 User
实体类,并增加相关注解,如下:
@Table(name = "t_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY, generator = "JDBC")
private Integer id;
private String username;
private String password;
private Boolean enabled;
private Boolean locked;
// @Column(name = "c_address")
private String address;
private String nickName;
private Date createTime;
private Date updateTime;
// getter/setter
}复制
注解说明:
@Table
:指定该实体类对应的表名,如果表名为 t_user ,类名为 TUser ,则可以不需要此注解(默认驼峰命名规则)。@Column
:指定该属性对应的列名,如果列名为 create_time ,属性名为 createTime ,则可以不需要此注解(默认驼峰命名规则)。@Id
:标识该字段对应数据库表的主键 id 。@GeneratedValue
:指定主键 id 生成规则,其中 strategy 表示使用数据库自带的主键生成策略, generator 配置为"JDBC",在数据插入完毕之后,会自动将主键id填充到实体类中,类似普通 mapper.xml 中配置的 selectKey 标签。
新建 Mapper 接口
public interface UserMapper extends Mapper<User> {
}复制
这里继承 TkMybatis 中最基本的一个通用 Mapper 接口,这样就自动拥有了这个 Mapper 中的一些接口,不用写 XXXMapper.xml 文件。
相关接口如下:

除了 Mapper 接口,官方还提供了一些几个好用的通用 Mapper 接口,都可以用来继承使用,汇总如下:
Mapper 接口:

IdsMapper 接口:

ConditionMapper 接口:

MySqlMapper 接口:

SqlServerMapper 接口:

当然,我们也可以根据自己的实际业务需求,抽取通用业务逻辑,自定义通用 Mapper 接口,参考 通用 Mapper 进阶实例:为什么好久都没更新了? 。
配置 Mapper 接口的扫描
可以在启动类上或自定义 MyBatis 的配置类上,通过 @MapperScan
注解配置。
@SpringBootApplication
@tk.mybatis.spring.annotation.MapperScan(basePackages = "com.cxy35.sample.springboot.mybatis.tkmybatis.mapper")
public class SpringBootMybatisTkmybatisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootMybatisTkmybatisApplication.class, args);
}
}复制
测试
在测试类中注入 UserMapper
完成测试,如下:
@SpringBootTest
class SpringBootMybatisTkmybatisApplicationTests {
@Autowired
UserMapper userMapper;
@Test
public void insertSelective() {
User user = new User();
user.setUsername("zhangsan");
user.setPassword("123456");
user.setAddress("杭州");
user.setNickName("zs");
user.setCreateTime(new Date());
user.setUpdateTime(new Date());
userMapper.insertSelective(user);
}
@Test
public void deleteByPrimaryKey() {
userMapper.deleteByPrimaryKey(2);
}
@Test
public void updateByPrimaryKeySelective() {
User user = new User();
user.setId(1);
user.setUsername("zhangsan2");
user.setPassword("654321");
user.setNickName("zs2");
user.setAddress("上海");
userMapper.updateByPrimaryKeySelective(user);
}
@Test
public void selectAll() {
List<User> users = userMapper.selectAll();
System.out.println(users);
}
@Test
public void selectByExample() {
Example example = new Example(User.class);
Example.Criteria criteria = example.createCriteria();
criteria.andLike("username", "zhangsan%");
criteria.andEqualTo("address", "杭州");
List<User> users = userMapper.selectByExample(example);
System.out.println(users);
}
}复制
3 自定义 XXXMapper.xml(非必须)
虽然大多数复杂的需求,都能通过 TkMyBatis 的组合完成操作。但如果有特殊需求,可以自定义 XXXMapper.xml 文件,实现复杂 sql 语句的操作,这里以联表查询为例。
在 UserMapper.java
所在包下新建 UserMapper.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.cxy35.sample.springboot.mybatis.tkmybatis.mapper.UserMapper">
<select id="selectByRoleId" parameterType="java.lang.Integer" resultType="com.cxy35.sample.springboot.mybatis.tkmybatis.pojo.User">
SELECT
u.*
FROM
t_user u
INNER JOIN t_user_role ur ON u.id = ur.user_id
WHERE
ur.role_id = #{roleId, jdbcType=INTEGER};
</select>
</mapper>复制
上述 xml 文件与普通 xml 文件的不同之处在于:这里不需要使用 resultMap 进行字段的映射。当然,如果想在返回的 Map 中新增返回字段映射,直接添加新的字段即可。
注意:不要在 xml 文件中写 TkMyBatis 中已经有的一些基础方法,否则会报错,提示方法重复。
接着,修改 UserMapper.java ,增加对应的接口:
public interface UserMapper extends Mapper<User> {
// 测试用,非必须
List<User> selectByRoleId(Integer roleId);
}复制
上述 UserMapper.xml 放在 UserMapper.java 所在的包下面,会被自动扫描到。但在项目打包时会被忽略掉,因此需要在 pom.xml 中配置 Maven 构建时的资源路径。
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>复制
关于 XXXMapper.xml 文件位置,还有其他方案,这里不再赘述,具体可参考 Spring Boot 整合 MyBatis 。
最后在测试类中增加方法,完成测试:
@Test
public void selectByRoleId() {
List<User> users = userMapper.selectByRoleId(2);
System.out.println(users);
}复制
4 代码生成器插件
通用 Mapper 插件: tk.mybatis.mapper.generator.MapperPlugin
,可以生成带@Table/@Id/@Column
等注解的实体类,方便自动与数据库字段进行映射。通用代码生成器插件: tk.mybatis.mapper.generator.TemplateFilePlugin
,实际上是对 MyBatis Generator 的一个扩展,使用这个扩展可以很方便的使用 Freemarker 模板语言编写代码。
首先,在 pom.xml 中增加 MBG 的依赖(因为基于 MBG 插件)和通用 Mapper 的插件依赖,如下:
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.7</version>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-generator</artifactId>
<version>1.1.5</version>
</dependency>复制
接着,在 src/main/resources
目录下新建 generatorConfig.xml
文件,用于配置代码生成器。
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- 引入外部属性文件 -->
<properties resource="application.properties"/>
<context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat">
<property name="beginningDelimiter" value="`"/>
<property name="endingDelimiter" value="`"/>
<property name="javaFileEncoding" value="UTF-8"/>
<!--配置是否使用通用 Mapper 自带的注释扩展,默认 true-->
<!--<property name="useMapperCommentGenerator" value="false"/>-->
<!-- 为模型生成序列化方法-->
<!--<plugin type="org.mybatis.generator.plugins.SerializablePlugin"/>-->
<!-- 为生成的 Java 模型创建一个 toString 方法 -->
<!--<plugin type="org.mybatis.generator.plugins.ToStringPlugin"/>-->
<!-- 通用 Mapper 插件,可以生成带注解的实体类 -->
<plugin type="tk.mybatis.mapper.generator.MapperPlugin">
<!-- 生成的 Mapper 接口会自动继承这里配置的接口 -->
<property name="mappers" value="tk.mybatis.mapper.common.Mapper"/>
<!-- 是否区分大小写,默认值 false。如果数据库区分大小写,这里就需要配置为 true,这样当表名为 USER 时,会生成 @Table(name = "USER") 注解,否则使用小写 user 时会找不到表。 -->
<property name="caseSensitive" value="true"/>
<!-- 是否强制生成注解,默认 false,如果设置为 true,不管数据库名和字段名是否一致,都会生成注解(包含 @Table 和 @Column)。 -->
<property name="forceAnnotation" value="true"/>
<!-- 在生成的 model 中,增加字段名的常量,便于使用 Example 拼接查询条件的时候使用。 -->
<property name="generateColumnConsts" value="true"/>
<!-- -->
<!--<property name="generateDefaultInstanceMethod" value="true"/>-->
<!-- 开始和结束分隔符,对于有关键字的情况下适用。 -->
<property name="beginningDelimiter" value="`"/>
<property name="endingDelimiter" value="`"/>
<!-- 配置是否启用lombok, 支持如下6种注解 -->
<!-- 注意:当配置 Data 后,Getter Setter ToString EqualsAndHashCode 会被忽略-->
<!--<property name="lombok" value="Getter,Setter,Data,ToString,Accessors,EqualsAndHashCode"/>-->
<!--<property name="lombokEqualsAndHashCodeCallSuper" value="true"/>-->
<!-- -->
<!--<property name="swagger" value="true"/>-->
</plugin>
<!-- 通用代码生成器插件:支持基于 Freemarker 模板生成各种代码(未实测) -->
<!-- mapper接口 -->
<!--<plugin type="tk.mybatis.mapper.generator.TemplateFilePlugin">
<property name="targetProject" value="spring-boot-dao/spring-boot-mybatis-tkmybatis/src/main/java"/>
<property name="targetPackage" value="com.cxy35.sample.springboot.mybatis.tkmybatis.mbg.mapper"/>
<property name="templatePath" value="generator/mapper.ftl"/>
<property name="fileName" value="${tableClass.shortClassName}${mapperSuffix}.java"/>
<property name="mapperSuffix" value="Dao"/>
</plugin>-->
<!-- mapper.xml -->
<!--<plugin type="tk.mybatis.mapper.generator.TemplateFilePlugin">
<property name="targetProject" value="spring-boot-dao/spring-boot-mybatis-tkmybatis/src/main/java"/>
<property name="targetPackage" value="com.cxy35.sample.springboot.mybatis.tkmybatis.mbg.mapper"/>
<property name="templatePath" value="generator/mapperXml.ftl"/>
<property name="fileName" value="${tableClass.shortClassName}${mapperSuffix}.xml"/>
<property name="mapperSuffix" value="Dao"/>
<property name="mapperPackage" value="com.cxy35.sample.springboot.mybatis.tkmybatis.mbg.mapper"/>
</plugin>-->
<!-- 配置数据库连接 -->
<jdbcConnection driverClass="${spring.datasource.driver-class-name}"
connectionURL="${spring.datasource.url}"
userId="${spring.datasource.username}"
password="${spring.datasource.password}">
<!-- 解决 mysql 驱动升级到 8.0 后不生成指定数据库代码的问题 -->
<property name="nullCatalogMeansCurrent" value="true" />
</jdbcConnection>
<!-- 指定生成 model 的路径 -->
<javaModelGenerator targetPackage="com.cxy35.sample.springboot.mybatis.tkmybatis.mbg.model" targetProject="spring-boot-dao/spring-boot-mybatis-tkmybatis/src/main/java"/>
<!-- 指定生成 mapper 接口的的路径 -->
<javaClientGenerator targetPackage="com.cxy35.sample.springboot.mybatis.tkmybatis.mbg.mapper" targetProject="spring-boot-dao/spring-boot-mybatis-tkmybatis/src/main/java" type="XMLMAPPER"/>
<!-- 非必须 -->
<!-- 指定生成 mapper.xml 的路径 -->
<!--<sqlMapGenerator targetPackage="com.cxy35.sample.springboot.mybatis.tkmybatis.mbg.mapper" targetProject="spring-boot-dao/spring-boot-mybatis-tkmybatis/src/main/java"/>-->
<!-- tableName 可以使用 % 通配符 -->
<table tableName="t_user">
<generatedKey column="id" sqlStatement="JDBC"/>
</table>
<!--<table tableName="t_user_role">
<generatedKey column="id" sqlStatement="JDBC"/>
</table>-->
</context>
</generatorConfiguration>复制
最后,在 com.cxy35.sample.springboot.mybatis.tkmybatis
下新建 mbg
包,用来存放代码生成器相关配置代码和最终生成的业务代码。新建 Generator.java
如下:
public class Generator {
public static InputStream getResourceAsStream(String path) {
return Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
}
public static void main(String[] args) throws Exception {
//MBG 执行过程中的警告信息
List<String> warnings = new ArrayList<String>();
//当生成的代码重复时,覆盖原代码
boolean overwrite = true;
//读取我们的 MBG 配置文件
InputStream is = Generator.class.getResourceAsStream("/generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(is);
is.close();
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
//创建 MBG
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
//执行生成代码
myBatisGenerator.generate(null);
//输出警告信息
for (String warning : warnings) {
System.out.println(warning);
}
}
}复制
运行上述 main 方法即可自动生成代码,分别如下:
TUser.java
@Table(name = "`t_user`")
public class TUser {
/**
* 主键id
*/
@Id
@Column(name = "`id`")
@GeneratedValue(generator = "JDBC")
private Integer id;
/**
* 用户名
*/
@Column(name = "`username`")
private String username;
/**
* 密码
*/
@Column(name = "`password`")
private String password;
/**
* 是否启用:1 启用;0 未启用
*/
@Column(name = "`enabled`")
private Boolean enabled;
/**
* 是否锁定:1 锁定;0 未锁定
*/
@Column(name = "`locked`")
private Boolean locked;
/**
* 地址
*/
@Column(name = "`address`")
private String address;
/**
* 昵称
*/
@Column(name = "`nick_name`")
private String nickName;
/**
* 创建时间
*/
@Column(name = "`create_time`")
private Date createTime;
/**
* 更新时间
*/
@Column(name = "`update_time`")
private Date updateTime;
public static final String ID = "id";
public static final String DB_ID = "id";
public static final String USERNAME = "username";
public static final String DB_USERNAME = "username";
public static final String PASSWORD = "password";
public static final String DB_PASSWORD = "password";
public static final String ENABLED = "enabled";
public static final String DB_ENABLED = "enabled";
public static final String LOCKED = "locked";
public static final String DB_LOCKED = "locked";
public static final String ADDRESS = "address";
public static final String DB_ADDRESS = "address";
public static final String NICK_NAME = "nickName";
public static final String DB_NICK_NAME = "nick_name";
public static final String CREATE_TIME = "createTime";
public static final String DB_CREATE_TIME = "create_time";
public static final String UPDATE_TIME = "updateTime";
public static final String DB_UPDATE_TIME = "update_time";
// getter/setter
}复制
TUserMapper.java
public interface TUserMapper extends Mapper<TUser> {
}复制
TUserMapper.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.cxy35.sample.springboot.mybatis.tkmybatis.mbg.mapper.TUserMapper">
<resultMap id="BaseResultMap" type="com.cxy35.sample.springboot.mybatis.tkmybatis.mbg.model.TUser">
<!--
WARNING - @mbg.generated
-->
<id column="id" jdbcType="INTEGER" property="id" />
<result column="username" jdbcType="VARCHAR" property="username" />
<result column="password" jdbcType="VARCHAR" property="password" />
<result column="enabled" jdbcType="BIT" property="enabled" />
<result column="locked" jdbcType="BIT" property="locked" />
<result column="address" jdbcType="VARCHAR" property="address" />
<result column="nick_name" jdbcType="VARCHAR" property="nickName" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
</resultMap>
</mapper>复制
扩展阅读:
Mybatis 通用 Mapper 代码生成器 通用 Mapper 专用代码生成器 MyBatis Generator 详解
Spring Boot 教程合集(微信左下方阅读全文可直达)。 Spring Boot 教程合集示例代码:https://github.com/cxy35/spring-boot-samples 本文示例代码:https://github.com/cxy35/spring-boot-samples/tree/master/spring-boot-dao/spring-boot-mybatis-tkmybatis