Spring-Boot-MyBatis整合

什么是Spring Boot

Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can “just run”.
We take an opinionated view of the Spring platform and third-party libraries so you can get started with minimum fuss. Most Spring Boot applications need very little Spring configuration.

什么是 MyBatis ?

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

配置pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.0</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<!--<optional>true</optional>-->
</dependency>

</dependencies>

开始配置

application.properties

1
2
3
4
spring.datasource.jdbc-url=jdbc:mysql://127.0.0.1:3306/data
spring.datasource.username=root
spring.datasource.password=123
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

mapper

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.example.demo;

import com.example.demo.domain.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface UserMapper {
@Select("SELECT * FROM t_sys_user;")
List<User> findAll();
}

实体

1
2
3
4
5
6
7
8
@Data
public class User {
private Integer id;
private String username;
private String password;
private String nickname;
private Integer available;
}

Controller

1
2
3
4
5
6
7
8
9
10
11
12
@RestController
public class UserController {

//This is also expected - UserDao is an interface and Spring can't make a bean from an interface
@Autowired
private UserMapper userMapper;

@RequestMapping("/list")
public ResponseEntity<Collection> findAll() {
return new ResponseEntity<>(userMapper.findAll(), HttpStatus.OK);
}
}

遇到的问题

userMapper 注入失败

1
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userMapper' defined in file...

解决:试过多种mapper没扫描到,似乎@Mapper没起作用,尝试换成@MapperScan(“com.example.demo.domain.User”)

报SqlSessionFactory 和 SqlSessionTemplate 没有注入,按道理SpringBoot应该自动注册和注入,事实上没有。查阅文档,发现一开始导入的包有问题,应该导入的是mybatis-spring-boot-starter,下面是正确的导包

1
2
3
4
5
6
7
8
9
10
11
<!--		<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.0</version>
</dependency>-->

<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>

mapper的注入方式

官网示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@SpringBootApplication
public class SampleMybatisApplication implements CommandLineRunner {

private final CityMapper cityMapper;

public SampleMybatisApplication(CityMapper cityMapper) {
this.cityMapper = cityMapper;
}

public static void main(String[] args) {
SpringApplication.run(SampleMybatisApplication.class, args);
}

@Override
public void run(String... args) throws Exception {
System.out.println(this.cityMapper.findByState("CA"));
}

}

示例上Mapper的注入是通过构造方法注入的,而不是常见用注解的方式注入的,这样做的好处:

  • 保证依赖不可变(final关键字)
  • 保证依赖不为空(省去了我们对其检查)
  • 保证返回客户端(调用)的代码的时候是完全初始化的状态
  • 避免了循环依赖
  • 提升了代码的可复用性

运行报错

1
Caused by: java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required

看来只能自己动手配置数据源了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Configuration
public class DataSourceConfiguration {

@Bean(name="dataSource")
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSourceConfig(){
DataSource dataSource = DataSourceBuilder.create().build();
return dataSource;
}

@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSourceConfig());
return sessionFactory.getObject();
}
}

MyBatis-Spring-Boot-Starter文档

MyBatis-Spring-Boot-Starter will:

  • Autodetect an existing DataSource.
  • Will create and register an instance of a SqlSessionFactory passing that DataSource as an input using the SqlSessionFactoryBean.
  • Will create and register an instance of a SqlSessionTemplate got out of the SqlSessionFactory.
  • Autoscan your mappers, link them to the SqlSessionTemplate and register them to Spring context so they can be injected into your beans.

文档介绍发现应该是第一步DataSource没有注入,所以sqlSessionFactory()可以注掉同样可以运行,不过在多数据源的时候可以通过setDataSource()来设置数据源,通过getObject()获取sqlSessionFactory实例。

DataSource没有注入

@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class
})
将括号里面的exclude去掉 就可以自动注入了

application.properties
当自动注入时里面url必须是spring.datasource.url
如果是自定义数据源时则必须是spring.datasource.jdbc-url

文档

SpringBoot Documentation
mybatis
mybatis blog