Spring Boot 实践 :Spring Boot + MyBatis
Spring Boot 实践系列,Spring Boot + MyBatis 。
目的
将 MyBatis 与 Spring Boot 应用程序一起使用来访问数据库。
本次使用的Library
- spring-boot-starter:2.2.0.M4
- mybatis-spring-boot-starter:2.0.1
- mybatis-spring-boot-starter-test:2.0.1
- h2:1.4.199
- lombok:1.18.8
数据库访问
在实现 MyBatis 之前,首先进行 DB 访问的设置。
数据库访问定义
DataSourceSpring Boot自动定义了访问 DB等 bean。
默认情况下,它访问内存中的 H2 数据库,因此您需要将 h2 添加到依赖项中。
pom.xml
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
注意
:您可以通过更改 Spring Boot 配置文件中的驱动程序和连接目标来访问另一个 DB。(需要添加依赖对应的驱动)src/main/resources/application.yml
spring:
datasource:
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://localhost:5432/testdb
username: postgres
password: postgres
如果直接在 src/main/resources 下创建如下 SQL 文件,也可以在应用启动时自动初始化数据库。
默认识别的 SQL 文件如下。
- schema.sql
- schema-${platform}.sql
- data.sql
- data-${platform}.sql
如您所见,我们在 schema.sql 中定义了 DDL,在 data.sql 中定义了 DML。
注
${platform}:spring.datasource.platform在属性中指定。
似乎您可以使用 H2 进行单元测试,使用 Postgresql 进行集成测试。
这一次,创建 schema.sql 并创建一个表。
src/main/resources/schema.sql
create table if not exists todo (
todo_id identity,
todo_title varchar(30),
finished boolean,
created_at timestamp
);
mybatis-spring-boot-starter
它是使用 MyBatis 和 Spring Boot 的入门者。
通过使用 Spring Boot 的 Auto Configuration 机制,自动完成在 Spring Boot 应用中使用 MyBatis 的 Bean 定义。开发者只需要将 mybatis-spring-boot-starter 添加到他们的依赖项中。
pom.xml
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
</dependencies>
src/main/java/*/Application.java
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
主类没有改变 Spring Boot 应用程序中的默认值。
领域类
映射 DB 数据的域类对于普通的 Java Bean 是可以的。
在下文中,Lombok 用于省略 Getter 和 Setter 的实现@Data。
src/main/java/*/domain/Todo.java
@Data
public class Todo {
private String todoId;
private String todoTitle;
private boolean finished;
private LocalDateTime createdAt;
}
存储库接口
MyBatis 的 Mapper 对应 Spring 的 Repository 接口。
MyBatis 的 Mapper 可以通过以下任意一种方式实现。
- 创建Repository接口对应的Mapper XML
@Mapper授予存储库接口
这次我将根据注解库 Spring Boot 用 MyBatis 的 Mapper 来实现@Mapper。
src/main/java/*/repository/TodoRepository.java
@Mapper // (1)
public interface TodoRepository {
// (2)
@Select("SELECT todo_id, todo_title, finished, created_at FROM todo WHERE todo_id = #{todoId}")
Optional<Todo> findById(String todoId);
@Select("SELECT todo_id, todo_title, finished, created_at FROM todo")
Collection<Todo> findAll();
@Insert("INSERT INTO todo (todo_title, finished, created_at) VALUES (#{todoTitle}, #{finished}, #{createdAt})")
@Options(useGeneratedKeys = true, keyProperty = "todoId") // (3)
void create(Todo todo);
@Update("UPDATE todo SET todo_title = #{todoTitle}, finished = #{finished}, created_at = #{createdAt} WHERE todo_id = #{todoId}")
boolean updateById(Todo todo);
@Delete("DELETE FROM todo WHERE todo_id = #{todoId}")
void deleteById(Todo todo);
@Select("SELECT COUNT(*) FROM todo WHERE finished = #{finished}")
long countByFinished(boolean finished);
}
(1)如果添加到Repository界面@Mapper,MyBatis会自动扫描并注册到Mapper中。让我们将Repository接口放在主类下的包中。
(2)在给方法的...中实现要执行的SQL 。由于参数在 SQL 中使用,因此比 XML 更容易理解,因为它在同一个文件中进行了描述。@Select@Insert@Update@Delete#{}
(3) @Options在需要执行异常设置的 SQL 时给出。这里,由于表的关键项是IDENTITY列,所以在DB端是自动编号的,但是@Options你可以通过using来使用自动编号的ID。
多行 SQL
虽然上面的 SQL 是用一行描述的,但还是建议多行描述,因为它不可读。
它比 XML 更难看,因为它是一种像这样的字符串连接形式。
@Select("SELECT"
+ " todo_id,"
+ " todo_title,"
+ " finished,"
+ " created_at"
+ " FROM todo"
+ " WHERE"
+ " todo_id = #{todoId}")
Optional<Todo> findById(String todoId);
选择结果的自动和手动映射
Select 结果映射失败,因为图示的 Select 语句的结果列名称和 Todo 类的属性名称不同。(todo_title等等todoTitle)
有以下方法之一可以解决此问题。
- MyBatis 命名规则自动映射
@Results@ResultMap手动映射和
就个人而言,为属性命名以便自动映射可用,并且仅在它偏离规则时才进行手动映射是一个好主意。
自动映射
如果下划线分隔的列名与驼峰式的属性名匹配,则可以通过 MyBatis 的命名规则进行自动映射。
将以下设置添加到 Spring Boot 配置文件中。
src/main/resources/application.yml
mybatis:
configuration:
map-underscore-to-camel-case: true
注意
mybatis.configuration.*:您可以在属性中更改 MyBatis 设置。
手动映射
如果列名和属性名不匹配,则@Results需要@ResultMap为每个 SQL 定义手动映射。
@Results在中定义手动映射规则@Results如果要使用中定义的规则@ResultMap,@Results请指定中的 ID。
@Select("SELECT todo_id, todo_title, finished, created_at FROM todo WHERE todo_id = #{todoId}")
@Results(id = "todo", value = {
@Result(column = "todo_id", property = "todoId"),
@Result(column = "todo_title", property = "todoTitle"),
@Result(column = "finished", property = "finished"),
@Result(column = "created_at", property = "createdAt") })
Optional<Todo> findById(String todoId);
@Select("SELECT todo_id, todo_title, finished, created_at FROM todo")
@ResultMap("todo")
Collection<Todo> findAll();
与动态 SQL 通用
使用 Mapper XML 可能实现的动态 SQL ( <if>) 和通用性()<sql>现在通过 SqlProvider 实现。
// (2)
@SelectProvider(type = TodoSqlProvider.class, method = "find")
Optional<Todo> findById(String todoId);
@SelectProvider(type = TodoSqlProvider.class, method = "find")
Collection<Todo> findAll();
// (1)
public class TodoSqlProvider {
public String find(String todoId) {
return new SQL() {{
SELECT("todo_id", "todo_title", "finished", "created_at");
FROM("todo");
if (todoId != null) {
WHERE("todo_id = #{todoId}");
}
}}.toString();
}
}
(1) 实现SqlProvider类,并new SQL()在方法中使用组装SQL。例子中使用了实例初始化器( new SQL() {{ココ}}),当然你也可以正常写在方法链中。
注意
:您可以直接在 WHERE 子句中嵌入参数,但一定#{}要使用。#{}防止 SQL 注入。
(2)通过赋值@Select而不是@SelectProvider方法来指定实现的SqlProvider类和方法。
注意
:接口默认方法不能是 SqlProvider 方法。你需要上课。
这是因为当您使用 SqlProvider 方法时,会创建一个 SqlProvider 类的实例。
mybatis-spring-boot-starter-test
使用 Spring Boot 测试 MyBatis 的入门者。
通过使用 Spring Boot Auto Configuration 机制,Spring Boot 应用会自动定义一个 bean 用于测试 MyBatis Mapper。开发者只需要在自己的依赖中加入 mybatis-spring-boot-starter-test 并做一些设置即可。
pom.xml
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter-test</artifactId>
<version>2.0.1</version>
</dependency>
</dependencies>
JUnit 测试用例
在 JUnit 测试用例中,您所要做的就是提供类并@MyBatisTest制作要测试的存储库@Autowired。
src/test/java/*/repository/TodoRepositoryTest.java
@MybatisTest
class TodoRepositoryTest {
@Autowired
TodoRepository todoRepository;
@Test
@Sql(statements = "INSERT INTO todo (todo_title, finished, created_at) VALUES ('sample todo', false, '2019-01-01')")
void testFindAll() {
// execute
Collection<Todo> todos = todoRepository.findAll();
// assert
assertThat(todos)
.hasSize(1)
.extracting(Todo::getTodoTitle, Todo::isFinished, Todo::getCreatedAt)
.containsExactly(tuple("sample todo", false, LocalDate.of(2019, 1, 1).atStartOfDay()));
}
@MyBatisTestDataSource会自动定义使用 MyBatis、访问 DB 等的 bean ,但@Transactional也会添加更多。
@Transactional@Sql测试完成后会回滚测试中执行的SQL。这是安全的,因为即使在访问和测试不在内存中的实际数据库时,也可以保持测试的独立性。
Spring Boot 实践 :Spring Boot + MyBatis的更多相关文章
- Spring Boot实践——Spring AOP实现之动态代理
Spring AOP 介绍 AOP的介绍可以查看 Spring Boot实践——AOP实现 与AspectJ的静态代理不同,Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改 ...
- Spring Boot实践——Spring Boot 2.0 新特性和发展方向
出自:https://mp.weixin.qq.com/s/EWmuzsgHueHcSB0WH-3AQw 以Java 8 为基准 Spring Boot 2.0 要求Java 版本必须8以上, Jav ...
- spring boot 实践
二.实践 一些说明: 项目IDE采用Intellij(主要原因在于Intellij颜值完爆Eclipse,谁叫这是一个看脸的时代) 工程依赖管理采用个人比较熟悉的Maven(事实上SpringBoot ...
- 《深入实践Spring Boot》阅读笔记之三:核心技术源代码分析
刚关注的朋友,可以回顾前两篇文章: 基础应用开发 分布式应用开发 上篇文章总结了<深入实践Spring Boot>的第二部分,本篇文章总结第三部分,也是最后一部分.这部分主要讲解核心技术的 ...
- 《深入实践Spring Boot》阅读笔记之一:基础应用开发
上上篇「1718总结与计划」中提到,18年要对部分项目拆分,进行服务化,并对代码进行重构.公司技术委员会也推荐使用spring boot,之前在各个技术网站中也了解过,它可以大大简化spring配置和 ...
- 《深入实践Spring Boot》阅读笔记之二:分布式应用开发
上篇文章总结了<深入实践Spring Boot>的第一部分,这篇文章介绍第二部分:分布式应用开发,以及怎么构建一个高性能的服务平台. 主要从以下几个方面总结: Spring Boot SS ...
- Spring Boot实践——AOP实现
借鉴:http://www.cnblogs.com/xrq730/p/4919025.html https://blog.csdn.net/zhaokejin521/article/detai ...
- spring boot 2.0.0 + mybatis 报:Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required
spring boot 2.0.0 + mybatis 报:Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required 无法启动 ...
- spring boot打印sql语句-mybatis
spring boot打印sql语句-mybatis 概述 当自己编写的程序出现了BUG等等,找了很久 调试运行了几遍到mapper层也进去调试进了源码,非常麻烦 我就想打印出sql语句,好进行解决B ...
随机推荐
- 攻防世界——stegano
分析 1. 一个pdf,里边都是英文. 打开pdf "ctrl + F",检查flag 然活这里边直接告诉你,flag不在这里,一般都这么说了那就是真的不在了. 2. txt打开, ...
- FinClip 黑客马拉松正式开赛,码力集结,等你来战!
从2017到2022,小程序已经走过了5年的光景.从无人问津到互联网巨头纷纷入局,短短数年间,小程序已然发展成为超级 App 的标配!微信.支付宝.百度.抖音.今日头条--这些超级app的背后都有巨量 ...
- 实现深拷贝还在用JSON.parse(JSON.stringify(obj))?带你用JS实现一个完整版深拷贝函数
使用JavaScript实现深拷贝 1.JSON序列化实现深拷贝 在JS中,想要对某一个对象(引用类型)进行一次简单的深拷贝,可以使用JSON提供给我们的两个方法. JSON.stringfy():可 ...
- Codeforces Round #716 (Div. 2), problem: (B) AND 0, Sum Big位运算思维
& -- 位运算之一,有0则0 原题链接 Problem - 1514B - Codeforces 题目 Example input 2 2 2 100000 20 output 4 2267 ...
- android软件简约记账app开发day04-记账页面条目的代码书写
android软件简约记账app开发day04-记账页面条目的代码书写 在前三天我们完成了基本的界面展示,从今天开始,我们进入到后台逻辑代码的编写中,今天开发记账条目的代码 我们在主页面点击记一笔图标 ...
- 2021.08.09 P7238 迷失森林(树的直径)
2021.08.09 P7238 迷失森林(树的直径) P7238 「DCOI」迷失森林 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 重点: 1.树的直径两种求法:两次dfs.树 ...
- 论文翻译:2020_TinyLSTMs: Efficient Neural Speech Enhancement for Hearing Aids
论文地址:TinyLSTMs:助听器的高效神经语音增强 音频地址:https://github.com/Bose/efficient-neural-speech-enhancement 引用格式:Fe ...
- PDCA循环——快速提升软件质量的必备工具
近年来,软件项目的规模及其复杂性正在以空前的速度增长,互联网用户市场庞大,互联网公司和相应的软件产品层出不穷.快速响应需求变化往往是互联网行业的常态,软件产品的快速开发迭代对于公司迅速占领市场.抢占商 ...
- JAVA 基础(1)开发环境的搭建以及开发工具的选择
我们现在还是在学习阶段因此我们不用配置那么多的jdk,配置一个jdk8就够应付日常的学习了.前面的文章我尽量写详细一些照顾刚入坑的朋友.后文还有教大家怎么使用企业版的idea. 一.开发环境的搭 ...
- fxksmdb.exe 是什么进程?
今天打开电脑应用进程发现fxksmdb.exe.fxksmpl.exe.fxksmW.exe三个进程,经过查看文件路径发现原来是施乐打印机的驱动程序自带的应用,平时都没注意到这个,这下放心了. 我这里 ...