在 Spring Boot 中整合 MyBatis Plus 您所在的位置:网站首页 导入mybatis坐标为什么报错 在 Spring Boot 中整合 MyBatis Plus

在 Spring Boot 中整合 MyBatis Plus

2024-04-15 20:02| 来源: 网络整理| 查看: 265

MyBatis Plus 是 MyBatis 框架的一个增强。除了基本的 MyBatis 功能外,它还提供了快速的 CURD 方法,以及投影查询、分页查询、动态条件等等功能,极大的提高了开发效率。

本文将会通过案例教你如何在 Spring Boot 中整合 MyBatis Plus。

文中使用的软件版本如下:

Spring Boot:3.0.3 MySQL:8.0.0 MyBatis Plus:3.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`) ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_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 驱动)依赖。

org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-starter-web com.baomidou mybatis-plus-boot-starter 3.5.4 com.mysql mysql-connector-j 应用配置

在 application.yaml 中配置必要的基础配置信息:

spring: # 基本的数据源配置 datasource: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8&allowMultiQueries=true username: root password: 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; @TableField private String name; @TableField private Boolean enabled; @TableField private 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 BaseMapper{ /** * 根据 name 检索一条记录 * @param name * @return */ User getByName (String name); }

BaseMapper 已经预置了很多 CRUD 的方法,可以直接使用。

并且,还在这个接口中定义了一个自定义方法 getByName(),根据 name 检索一条记录。添加这个方法的目的是测试 Mapper 映射文件是否成功加载。

Mapper 映射文件

在 src/main/resources/mappers 目录下创建 UserMapper.xml 映射文件,如下:

SELECT * FROM `t_user` WHERE `name` = #{name}

在 UserMapper.xml 中,通过 select 节点实现了 UserMapper 接口中的 getByName 方法。

Service

MyBatis Plus 甚至还提供了一个 ServiceImpl 抽象类,它也预定义了很多 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 ServiceImpl{ } Service 层抽象接口

如果你喜欢抽象出 Service 接口的话,MyBatis Plus 也提供了一个接口:IService 可用于继承。

定义业务接口,继承 IService:

import com.baomidou.mybatisplus.extension.service.IService; import cn.springdoc.demo.entity.User; // UserService 继承 IService 接口 public interface UserService extends IService{ }

业务接口实现类 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 ServiceImpl 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); @Autowired UserService userService; @Test public void test() throws Exception { // 检索所有记录 List users = this.userService.list(); users.stream().forEach(user -> { log.info("user = {}", user); }); // 从 Service 中获取到注入的 Mapper,强制转换为具体的实体 Mapper UserMapper 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 : Preparing: SELECT * FROM `t_user` WHERE `name` = ? [ main] c.s.demo.mapper.UserMapper.getByName : ==> Parameters: 刘备(String) [ main] c.s.demo.mapper.UserMapper.getByName :


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有