概览
上篇我们介绍Spring Boot是如何集成Mybatis来完成数据库的访问,实际项目开发过程中,常用的一共有4种组合,分别是:
- MyBatis + XML
- MyBatis + 注解
- MyBatisPlus
- TkMyBatis
上篇文章我们把前两种方式做了一个入门教程,如有需要可以参看:juejin.cn/post/692241…,接下来我们继续介绍MyBatisPlus和 TkMyBatis
MyBatis-Plus
作为一名Java开发工程师,想必对大名鼎鼎的MyBatis-Plus并不陌生,作者的理念是【为简化开发而生】,实际使用确实大大简化的Mybatis开发,提升了开发效率。官网地址: https://mybatis.plus/
实例代码对应的仓库地址:github.com/dragon8844/…
本小节,我们会使用 mybatis-plus-boot-starter 自动化配置 MyBatis-Plus 的配置。同时,演示如何使用 MyBatis-Plus 实现各种CRUD的操作。
引入依赖
<!-- 实现对数据库连接池的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- 本示例,我们使用 MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 实现对 MyBatis Plus 的自动化配置 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<!-- 方便用单元测试验证-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- lombok简化代码-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
添加配置
-
应用配置
在resources目录下创建应用的配置文件application.yml,添加如下配置内容:`
spring: # datasource 数据源配置内容 datasource: url: jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8 driver-class-name: com.mysql.cj.jdbc.Driver username: root password: root # mybatis-plus 配置内容 mybatis-plus: configuration: map-underscore-to-camel-case: true global-config: db-config: id-type: auto # ID 主键自增 logic-delete-value: 1 # 逻辑已删除值(默认为 1) logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) mapper-locations: classpath*:mapper/*.xml type-aliases-package: com.dragon.mybatisplus.entity -
配置类
在config包下创建MybatisPlusConfig配置类,添加如下配置内容:
/** * @author lilong */ @MapperScan("com.dragon.mybatisplus.mapper") @Configuration public class MybatisPlusConfig { }因为这是个入门的demo,这里我们只需要配置的Mybatis的包扫描路径
编写代码
-
编写实体类
@Data @TableName(value = "user") public class User { /** * 主键 */ private Integer id; /** * 用户名 */ private String username; /** * 密码 */ private String password; /** * 创建时间 */ private Date createTime; /** * 是否删除 */ @TableLogic private Integer deleted; }实体类对应的DDL语句:
CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', `username` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '用户名', `password` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '密码', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `deleted` tinyint(1) DEFAULT NULL COMMENT '是否删除 0-未删除;1-删除', PRIMARY KEY (`id`), UNIQUE KEY `idx_username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; -
编写Mapper类
com.dragon.mybatisplus.mapper包下创建接口UserMapper,这个时候我们需要继承MyBatis-Plus的基础Mapper,
com.baomidou.mybatisplus.core.mapper.BaseMapper接口,代码如下:
/** * @author lilong */ @Repository public interface UserMapper extends BaseMapper<User> { /** * 根据username查询 * * @param username * @return */ default User selectByUsername(@Param("username") String username) { LambdaQueryWrapper<User> wrapper = new QueryWrapper<User>().lambda(); return selectOne(wrapper.eq(User::getUsername, username)); } } -
对比下MyBatis + XML 这种方式,我们发现,通过继承com.baomidou.mybatisplus.core.mapper.BaseMapper接口,对数据库单表的CRUD操作MyBatis-Plus替我们自动完成了,分析源码如下:
public interface BaseMapper<T> extends Mapper<T> { int insert(T entity); int deleteById(Serializable id); int deleteByMap(@Param("cm") Map<String, Object> columnMap); int delete(@Param("ew") Wrapper<T> wrapper); int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList); int updateById(@Param("et") T entity); int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper); T selectById(Serializable id); List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList); List<T> selectByMap(@Param("cm") Map<String, Object> columnMap); T selectOne(@Param("ew") Wrapper<T> queryWrapper); Integer selectCount(@Param("ew") Wrapper<T> queryWrapper); List<T> selectList(@Param("ew") Wrapper<T> queryWrapper); List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper); List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper); IPage<T> selectPage(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper); IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper); }通过查看源码,我们发现Mybatis-plus自动帮助我们生成的方法相当全面,一般来说,开发业务代码的时候,最耗时最枯燥的莫过于单表的CURD的操作,Mybatis-plus确实能大大简化我们开发。
-
对于
#selectByUsername(@Param("username") String username)方法,我们使用了com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<T>构造相对灵活的条件,这样一些动态 SQL 我们就无需在 XML 中编写。代码如下:
default User selectByUsername(@Param("username") String username) { LambdaQueryWrapper<User> wrapper = new QueryWrapper<User>().lambda(); return selectOne(wrapper.eq(User::getUsername, username)); }QueryWrapper 已经提供好的非常多的拼接方法,具体的使用方式:《MyBatis-Plus 文档 —— 条件构造器》
单元测试
走一个单元测试,代码如下:
@SpringBootTest
@Slf4j
class UserMapperTest {
@Resource
UserMapper userMapper;
@Test
void insert() {
User user = new User();
user.setUsername("张三");
user.setPassword("123456");
user.setCreateTime(new Date());
Integer count = userMapper.insert(user);
log.info("count:{}", count);
}
@Test
void selectById() {
User user = userMapper.selectById(13);
log.info("user:{}", user.toString());
}
@Test
void selectByUsername() {
User user = userMapper.selectByUsername("张三");
log.info("user:{}", user.toString());
}
@Test
void updateById() {
User user = new User();
user.setId(13);
user.setUsername("李四");
user.setPassword("111111");
Integer count = userMapper.updateById(user);
log.info("count:{}", count);
}
@Test
void deleteById() {
Integer count = userMapper.deleteById(13);
log.info("count:{}", count);
}
}
tkMybatis
tkMybatis我在实际工作的中使用的并不是很多,我基本上是从Mybatis + XML直接过度到MyBatis-Plus,中间也只有一个项目使用了tkMybatis, tk我理解的应该是toolkit的缩写,就是工具包的意思,主要是有两个开源的项目组合而来的
- Mapper :提供通用的 MyBatis Mapper 。
- Mybatis-PageHelper :提供 MyBatis 分页插件。
更多的资料可以参考官方:mybatis.io/
实例代码对应的仓库地址:github.com/dragon8844/…
本小节,我们会使用 tkmybatis 实现我们各种 CRUD 操作。
引入依赖
在pom.xml文件中,引入相关依赖,依赖稍微有点多 如下:
<!-- 实现对数据库连接池的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- 本示例,我们使用 MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 实现对 MyBatis 的自动化配置 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<!-- 实现对 Mapper 的自动化配置-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.1.5</version>
</dependency>
<!-- 实现对 PageHelper 的自动化配置-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.5</version>
<exclusions>
<exclusion>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 方便用单元测试验证-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- lombok简化代码-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
- 引入
mybatis-spring-boot-starter依赖,自动化配置 MyBatis 。 - 引入
mapper-spring-boot-starter依赖,自动化配置 Mapper 。 - 引入
pagehelper-spring-boot-starter依赖,自动化配置 PageHelper 。
添加配置
-
应用配置
在resources目录下创建应用的配置文件application.yml,添加如下配置内容:
spring: # datasource 数据源配置内容 datasource: url: jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8 driver-class-name: com.mysql.cj.jdbc.Driver username: root password: root # mybatis 配置内容 mybatis: config-location: classpath:mybatis-config.xml # 配置 MyBatis 配置文件路径 mapper-locations: classpath:mapper/*.xml # 配置 Mapper XML 地址 type-aliases-package: com.dragon.tkmybatis.entity # 配置数据库实体包路径 # mapper 配置内容 mapper: not-empty: true # 在 INSERT 和 UPDATE 操作时,是否会判断字段是否为空。即 <if test='xxx != null' /> identity: MYSQL # PageHelper 配置内容 # 具体的参数作用,看 https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md pagehelper: helperDialect: mysql # 分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。 你可以配置helperDialect属性来指定分页插件使用哪种方言。 reasonable: true # 分页合理化参数,默认值为false。当该参数设置为 true 时,pageNum<=0 时会查询第一页, pageNum>pages(超过总数时),会查询最后一页。默认false 时,直接根据参数进行查询。 supportMethodsArguments: true # 支持通过 Mapper 接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页 -
mybatis的配置
在resources目录下创建mybatis-config.xml,并且添加如下配置:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <!-- 使用驼峰命名法转换字段。 --> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> <typeAliases> <typeAlias alias="Integer" type="java.lang.Integer"/> <typeAlias alias="Long" type="java.lang.Long"/> <typeAlias alias="HashMap" type="java.util.HashMap"/> <typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap"/> <typeAlias alias="ArrayList" type="java.util.ArrayList"/> <typeAlias alias="LinkedList" type="java.util.LinkedList"/> </typeAliases> </configuration> -
在config包下创建MyBatisConfig配置类,添加如下配置内容:
/** * @author lilong */ @MapperScan(basePackages = "com.dragon.tkmybatis.mapper") @Configuration public class MybatisConfig { }来用指定Mybatis的扫描包的基本包路径
编写代码
-
编写实体类
@Data @Table(name = "user") public class User { /** * 主键 */ // 表示该字段为主键 ID @Id @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "JDBC") private Integer id; /** * 用户名 */ private String username; /** * 密码 */ private String password; /** * 创建时间 */ private Date createTime; }实体类对应的DDL语句:
CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', `username` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '用户名', `password` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '密码', `create_time` datetime DEFAULT NULL COMMENT '创建时间', PRIMARY KEY (`id`), UNIQUE KEY `idx_username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; -
编写Mapper类
com.dragon.tkmybatis.mapper包下创建接口UserMapper,同理和MyBatis-Plus一样,这个时候我们需要继承tkMybatis的基础Mapper,
tk.mybatis.mapper.common.Mapper接口,代码如下:
/** * @author lilong */ @Repository public interface UserMapper extends Mapper<User> { /** * 根据username查询 * * @param username * @return */ default User selectByUsername(@Param("username") String username){ Example example = new Example(User.class); // 创建 Criteria 对象,设置 username 查询条件 example.createCriteria().andEqualTo("username", username); // 执行查询 return selectOneByExample(example); } /** * 根据创建时间查询 * @param createTime * @return */ default List<User> selectByCreateTime(@Param("createTime") Date createTime) { Example example = new Example(User.class); // 创建 Criteria 对象,设置 create_time 查询条件 example.createCriteria().andGreaterThan("createTime", createTime); return selectByExample(example); } }-
在 MyBatis-Plus 中,我们使用 QueryWrapper 拼装动态 SQL 。而在 tkmybatis 中,通过使用它提供的 Example 和 Criteria 类。
-
关于分页,PageHelper 的使用方式,在单元测试中会有体现
-
单元测试
@SpringBootTest
@Slf4j
class UserMapperTest {
@Resource
UserMapper userMapper;
@Test
void insert() {
User user = new User();
user.setUsername("张三");
user.setPassword("123456");
user.setCreateTime(new Date());
Integer count = userMapper.insert(user);
log.info("count:{}", count);
}
@Test
void selectByPrimaryKey() {
User user = userMapper.selectByPrimaryKey(14);
log.info("user:{}", user.toString());
}
@Test
void selectByUsername() {
User user = userMapper.selectByUsername("李四");
log.info("user:{}", user.toString());
}
@Test
void updateByPrimaryKey() {
User user = new User();
user.setId(14);
user.setUsername("李四");
user.setPassword("111111");
Integer count = userMapper.updateByPrimaryKey(user);
log.info("count:{}", count);
}
@Test
void deleteByPrimaryKey() {
Integer count = userMapper.deleteByPrimaryKey(14);
log.info("count:{}", count);
}
@Test // 更多使用,可以参考 https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md
public void testSelectPageByCreateTime() {
// 设置分页
PageHelper.startPage(1, 10);
Date createTime = new Date(2018 - 1990, Calendar.FEBRUARY, 24); // 临时 Demo ,实际不建议这么写
// 执行列表查询
// PageHelper 会自动发起分页的数量查询,设置到 PageHelper 中
List<User> users = userMapper.selectByCreateTime(createTime); // 实际返回的是 com.github.pagehelper.Page 代理对象
// 转换成 PageInfo 对象,并输出分页
PageInfo<User> page = new PageInfo<>(users);
System.out.println(page.getTotal());
}
}
分页逻辑,在 #testSelectPageByCreateTime() 方法中,我们已经进行实现。
小结
至此SpringBoot整合Mybaits入门的教程已完结,我们来回忆下,整合Mybatis一共有4中组合方式,分别是:
-
MyBatis + XML
-
MyBatis + 注解
-
MyBatisPlus
-
TkMyBatis
XML方式比较原始,需要手写大量的CRUD的SQL,开发效率不太高,需要手写大量的SQL。
注解这种方式虽然说可以省略xml文件的编写,不过把SQL写到java代码中,代码的维护性、可读性比较差,同样避免不了手写大量的SQL。
推荐是用MyBatisPlus,对于单表的CRUD可以自动帮助生成,官方的文档也是比较系统和全面的。
至于TkMyBatis,定位是MyBatis的工具箱,是有通用Mapper和Mybatis-PageHelper两个开源项目组成的,同样可以提供MyBatisPlus相同的功能,官方的文档目前稍微欠缺。
最后说一句
如果这篇文章对您有所帮助,或者有所启发的话,帮忙关注一下,您的支持是我坚持写作最大的动力,多谢支持。
此外,关注公众号:黑色的灯塔,专注Java后端技术分享,涵盖Spring,Spring Boot,SpringCloud,Docker,Kubernetes中间件等技术。