北京网站建设价钱,建网站 企汇网,专业网站推广软件,淘宝流量网站目录
一、初始化演示数据
二、创建应用
二、应用配置
三、实体类
四、Mapper
五、Mapper 映射文件
六、Service
七、Service 层抽象接口
八、配置 Mapper 扫描包
九、在日志中输出 SQL
十、测试 MyBatis Plus 是 MyBatis 框架的一个增强。除了基本的 MyBatis 功能外…目录
一、初始化演示数据
二、创建应用
二、应用配置
三、实体类
四、Mapper
五、Mapper 映射文件
六、Service
七、Service 层抽象接口
八、配置 Mapper 扫描包
九、在日志中输出 SQL
十、测试 MyBatis Plus 是 MyBatis 框架的一个增强。除了基本的 MyBatis 功能外它还提供了快速的 CURD 方法以及投影查询、分页查询、动态条件等等功能极大的提高了开发效率。
本文将会通过案例教你如何在 Spring Boot 中整合 MyBatis Plus。
文中使用的软件版本如下
Spring Boot3.0.3MySQL8.0.0MyBatis Plus3.5.4
一、初始化演示数据
首先在本地数据库执行以下 SQL 脚本创建一张名为 t_user 的数据表
CREATE TABLE t_user (id int unsigned NOT NULL AUTO_INCREMENT COMMENT ID,create_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间,enabled tinyint unsigned NOT NULL COMMENT 是否启用。0禁用1启用,name varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT 名字,PRIMARY KEY (id),UNIQUE KEY name (name)
) ENGINEInnoDB AUTO_INCREMENT8 DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_general_ci COMMENT用户;然后再执行如下脚本创建初始记录
INSERT INTO demo.t_user (id, create_at, enabled, name) VALUES (3, 2023-10-31 15:11:34, 1, 刘备);
INSERT INTO demo.t_user (id, create_at, enabled, name) VALUES (4, 2023-10-31 15:11:34, 1, 关羽);
INSERT INTO demo.t_user (id, create_at, enabled, name) VALUES (5, 2023-10-31 15:11:34, 1, 张飞);二、创建应用
通过 Spring Initializer 快速初始化一个 Spring Boot 工程。添加 mybatis-plus-boot-starter 以及 mysql-connector-j MySQL 驱动依赖。
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope
/dependency
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId
/dependencydependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.5.4/version
/dependency
dependencygroupIdcom.mysql/groupIdartifactIdmysql-connector-j/artifactId
/dependency二、应用配置
在 application.yaml 中配置必要的基础配置信息
spring:# 基本的数据源配置datasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/demo?useUnicodetruecharacterEncodingUTF-8serverTimezoneGMT%2b8allowMultiQueriestrueusername: rootpassword: root# MyBatis Plus 的配置
mybatis-plus:# mybatis 配置文件的路径# config-location: classpath:mybatis/mybatis.config# mapper 映射文件的路径可以有多个 mapper-locations:- classpath*:mappers/**/*.xml除了必须的数据源配置外还定义了 MyBatis Plus 的配置。
config-location指定了 MyBatis 配置文件的路径非必须的。mapper-locations指定要加载 mapper 文件支持使用通配符。本例中的配置表示加载 classpath 下 mappers 目录以及其所有子目录下所有以 xml 结尾的文件。该配置是一个数组可以配置多个加载路径。 更多关于 MyBatis Plus 的可用配置可以参考其 官方文档。 三、实体类
创建一个实体类 User对应上面的 t_user 表
package cn.springdoc.demo.entity;import java.time.LocalDateTime;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;TableName(t_user)
public class User {TableId(type IdType.AUTO)private Long id;TableFieldprivate String name;TableFieldprivate Boolean enabled;TableFieldprivate LocalDateTime createAt;// 省略 get/set/toString 等方法
}TableName 注解是必须的用于指定数据库中的表名称。 TableId 注解也是必须的用户指定表的 ID 字段并且通过 type 属性设置了 ID 值为 “数据库自增”。
使用 TableField 注解来定义与数据表中对应的列。注意表中的列名使用的是下划线而实体类中字段名称使用的是驼峰。 框架会自动完成这个转换你不用担心。
如果你的表列名和实体属性名称之间不能自动完成这种转换需要通过该注解的 value 属性来定义列名如TableField(u_nick_name)。
TableField 注解还有一个重要的 boolean 属性exist用于定义那些在实体中的 “非 DB 列” 字段。
例如需要在实体中添加一个额外的 nickName 字段用于封装检索的结果这个字段并在表中并没有对应的数据列此时就需要设置 exist 属性为 false。
TableField(exist false)
private String nickName;否则在运行时你可能会遇到 “Unknown column” 异常
org.springframework.jdbc.BadSqlGrammarException:
### Error querying database. Cause: java.sql.SQLSyntaxErrorException: Unknown column nick_name in field list
### The error may exist in cn/springdoc/demo/mapper/UserMapper.java (best guess)
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: SELECT id,name,enabled,create_at,nick_name FROM t_user
### Cause: java.sql.SQLSyntaxErrorException: Unknown column nick_name in field list
; bad SQL grammar []更多可用的注解可以参阅 官方文档。 四、Mapper
创建 UserMapper 接口继承 BaseMapper并且通过泛型指定实体类类型
package cn.springdoc.demo.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import cn.springdoc.demo.entity.User;public interface UserMapper extends BaseMapperUser{/*** 根据 name 检索一条记录* param name* return*/User getByName (String name);
}BaseMapper 已经预置了很多 CRUD 的方法可以直接使用。
并且还在这个接口中定义了一个自定义方法 getByName()根据 name 检索一条记录。添加这个方法的目的是测试 Mapper 映射文件是否成功加载。
五、Mapper 映射文件
在 src/main/resources/mappers 目录下创建 UserMapper.xml 映射文件如下
?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtdmapper namespacecn.springdoc.demo.mapper.UserMapperselect idgetByName resultTypecn.springdoc.demo.entity.UserSELECT * FROM t_user WHERE name #{name}/select/mapper在 UserMapper.xml 中通过 select 节点实现了 UserMapper 接口中的 getByName 方法。
六、Service
MyBatis Plus 甚至还提供了一个 ServiceImplM extends BaseMapperT, T 抽象类它也预定义了很多 CRUD 的方法。
我们的 Service 类可以直接继承它指定泛型为实体类的 Mapper 接口以及实体类类型。
package cn.springdoc.demo.service;import org.springframework.stereotype.Service;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import cn.springdoc.demo.entity.User;
import cn.springdoc.demo.mapper.UserMapper;Service
public class UserService extends ServiceImplUserMapper, User{}七、Service 层抽象接口
如果你喜欢抽象出 Service 接口的话MyBatis Plus 也提供了一个接口IServiceT 可用于继承。
定义业务接口继承 IService
import com.baomidou.mybatisplus.extension.service.IService;
import cn.springdoc.demo.entity.User;
// UserService 继承 IService 接口
public interface UserService extends IServiceUser{
}业务接口实现类 UserServiceImpl实现业务接口并且继承 ServiceImpl 抽象类
package cn.springdoc.demo.service;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.springdoc.demo.entity.User;
import cn.springdoc.demo.mapper.UserMapper;// UserServiceImpl 实现类实现 UserService 接口并且继承 ServiceImpl 抽象类
Service
public class UserServiceImpl extends ServiceImplUserMapper, User implements UserService {
}我个人觉得除非实在是有必要不然真的没必要在 Service 抽象出接口。写一辈子代码也遇不到几次 Service 多实现的场景。
八、配置 Mapper 扫描包
在 main 类上添加 MapperScan 注解指定 mapper 接口所在的包
package cn.springdoc.demo;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplication
MapperScan(cn.springdoc.demo.mapper) // mapper 接口所在的包
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}
}九、在日志中输出 SQL
为了看到执行的 SQL 日志可以在 application.yaml 把 mapper 所在包的日志级别设置为 DEBUG
logging:level:cn.springdoc.demo.mapper: DEBUG至此整合就完成了。
十、测试
创建测试类:
package cn.springdoc.demo.test;import java.util.List;import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;import cn.springdoc.demo.entity.User;
import cn.springdoc.demo.mapper.UserMapper;
import cn.springdoc.demo.service.UserService;SpringBootTest(webEnvironment WebEnvironment.RANDOM_PORT)
public class DemoApplicationTests {static final Logger log LoggerFactory.getLogger(DemoApplicationTests.class);AutowiredUserService userService;Testpublic void test() throws Exception {// 检索所有记录ListUser users this.userService.list();users.stream().forEach(user - {log.info(user {}, user);});// 从 Service 中获取到注入的 Mapper强制转换为具体的实体 MapperUserMapper userMapper (UserMapper) this.userService.getBaseMapper();// 调用 Mapper 中的方法User user userMapper.getByName(刘备);log.info(user {}, user);}
}在测试类中注入了 UserService执行了 2 个查询。
首先使用 MyBatis Plus 提供的 list() 方法检索出表中的所有记录。
然后再通过 getBaseMapper() 方法获取到 Service 中注入的 BaseMapper 接口并且强制转换为对应的 UserMapper。然后调用我们在接口中自定义的方法。
执行测试输出日志如下
[ main] c.s.demo.mapper.UserMapper.selectList : Preparing: SELECT id,name,enabled,create_at FROM t_user
[ main] c.s.demo.mapper.UserMapper.selectList : Parameters:
[ main] c.s.demo.mapper.UserMapper.selectList : Total: 3
[ main] c.s.demo.test.DemoApplicationTests : user User [id3, name刘备, enabledtrue, createAt2023-10-31T15:11:34]
[ main] c.s.demo.test.DemoApplicationTests : user User [id4, name关羽, enabledtrue, createAt2023-10-31T15:11:34]
[ main] c.s.demo.test.DemoApplicationTests : user User [id5, name张飞, enabledtrue, createAt2023-10-31T15:11:34]
[ main] c.s.demo.mapper.UserMapper.getByName : Preparing: SELECT * FROM t_user WHERE name ?
[ main] c.s.demo.mapper.UserMapper.getByName : Parameters: 刘备(String)
[ main] c.s.demo.mapper.UserMapper.getByName : Total: 1
[ main] c.s.demo.test.DemoApplicationTests : user User [id3, name刘备, enabledtrue, createAt2023-10-31T15:11:34]如你所见一切OK