前面几篇博客就SpringBoot的原理以及实践的一些小技巧进行了学习,接下来的几篇Blog,我愿称之为SpringBoot对各层的整合以应对完整的开发任务,无外乎就是对数据库以及持久层的整合以及对SpringMVC的定制整合等,那么今天这篇Blog就来对数据源进行整合配置,包括各个持久层的框架。对于数据访问层,无论是 SQL(关系型数据库) 还是 NOSQL(非关系型数据库),Spring Boot 都默认采用整合 Spring Data(Spring Data 也是 Spring 中与 Spring Boot、Spring Cloud 齐名的知名项目) 的方式进行统一处理,通过大量自动配置,来简化我们对数据访问层的操作,我们只需要进行简单的设置即可实现对数据层的访问,这里提到了一个数据源的概念,其实数据源可以理解为一个代理,JDBC这套协议的具体实现,详细可以看这篇:数据库与数据源的区别
SpringBoot整合JDBC我们按照如下步骤使用JDBC整合配置:
1 导入 JDBC 场景启动器Spring Boot 将日常企业应用研发中的各种场景都抽取出来,做成一个个的场景启动器(Starter),场景启动器中整合了该场景下各种可能用到的依赖,让用户摆脱了处理各种依赖和配置的困扰。想要在 Spring Boot 中使用 JDBC 进行数据访问,第一步就是要在 pom.xml 中导入 JDBC 场景启动器:spring-boot-starter-data-jdbc,代码如下
2 导入数据库驱动org.springframework.boot spring-boot-starter-data-jdbc
JDBC 的场景启动器中并没有导入数据库驱动,我们需要根据自身的需求引入所需的数据库驱动。例如,访问 MySQL 数据库时,需要导入 MySQL 的数据库驱动:mysql-connector-java,示例代码如下
3 配置数据源mysql mysql-connector-java runtime
在导入了 JDBC 场景启动器和数据库驱动后,接下来我们就可以在配置文件(application.properties/yml)中配置数据源了,示例代码(application.yml)如下
#数据源连接信息
spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/test?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
4 JdbcTemplate 请求测试
Spring Boot 提供了一个名为 JdbcTemplate 的轻量级数据访问工具,它是对 JDBC 的封装。Spring Boot 对 JdbcTemplate 提供了默认自动配置,我们可以直接使用 @Autowired 或构造函数将它注入到 bean 中使用
package com.example.springboot;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.sql.SQLException;
@SpringBootTest
class SpringbootApplicationTests {
//数据源组件
@Resource
DataSource dataSource;
//用于访问数据库的组件
@Resource
JdbcTemplate jdbcTemplate;
@Test
void contextLoads() throws SQLException {
System.out.println("默认数据源为:" + dataSource.getClass());
System.out.println("数据库连接实例:" + dataSource.getConnection());
//访问数据库
Integer i = jdbcTemplate.queryForObject("SELECt count(*) from `person`", Integer.class);
System.out.println("user 表中共有" + i + "条数据。");
}
}
数据表如下:
返回结果为:
通过以上运行结果可以看出,Spring Boot 默认使用 HikariCP 作为其数据源,对数据库的访问,HikariDataSource 号称 Java WEB 当前速度最快的数据源,相比于传统的 C3P0 、DBCP、Tomcat jdbc 等连接池更加优秀
在数据库访问过程中,“数据源”无疑是最重要的概念之一,它不仅可以对与数据库访问相关的各种参数进行封装和统一管理,还可以管理数据库连接池,提高数据库连接性能。目前,在市面上有很多优秀的开源数据源,例如 DBCP、C3P0、Druid、HikariCP 等等。在 Spring Boot 2.x 中,则采用目前性能最佳的 HikariCP 作为其默认数据源。接下来,我们就来具体介绍下 Spring Boot 的默认数据源配置及其原理
DataSourceAutoConfiguration我们知道,Spring Boot 中几乎所有的默认配置都是通过配置类 XxxAutoConfiguration 进行配置的,Spring Boot 数据源也不例外,它的自动配置类是:DataSourceAutoConfiguration。
DataSourceAutoConfiguration 中共包括以下 5 个内部静态类:
- EmbeddedDatabaseCondition
- PooledDataSourceAvailableCondition
- PooledDataSourceCondition
- PooledDataSourceConfiguration(池化数据源自动配置类)
- EmbeddedDatabaseConfiguration(内嵌数据源自动配置类)
其中,PooledDataSourceConfiguration 和 EmbeddedDatabaseConfiguration 为使用了 @Configuration 注解的自动配置类,其余 3 个为限制条件类。
EmbeddedDatabaseConfiguration类EmbeddedDatabaseConfiguration 是内嵌数据源的自动配置类,该类中并没有任何的方法实现,它的主要功能都是通过 @import 注解引入 EmbeddedDataSourceConfiguration 类来实现的
@Configuration(
proxyBeanMethods = false
)
@Conditional({DataSourceAutoConfiguration.EmbeddedDatabaseCondition.class})
@ConditionalOnMissingBean({DataSource.class, XADataSource.class})
@import({EmbeddedDataSourceConfiguration.class})
protected static class EmbeddedDatabaseConfiguration {
protected EmbeddedDatabaseConfiguration() {
}
}
EmbeddedDataSourceConfiguration 向容器中添加了一个 Spring Boot 内嵌的数据源,该数据源支持 HSQL,H2 和 DERBY 三种数据库,其部分代码如下
@Configuration(
proxyBeanMethods = false
)
@EnableConfigurationProperties({DataSourceProperties.class})
public class EmbeddedDataSourceConfiguration implements BeanClassLoaderAware {
private ClassLoader classLoader;
public EmbeddedDataSourceConfiguration() {
}
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
//向容器中添加 Spring Boot 内嵌的数据源
@Bean(
destroyMethod = "shutdown"
)
public EmbeddedDatabase dataSource(DataSourceProperties properties) {
return (new EmbeddedDatabaseBuilder()).setType(EmbeddedDatabaseConnection.get(this.classLoader).getType()).setName(properties.determineDatabaseName()).build();
}
}
通过上面的分析,我们知道自动配置类 EmbeddedDatabaseConfiguration 的作用是向容器中添加一个内嵌的数据源(DataSource)
EmbeddedDatabaseCondition条件类向容器中添加一个内嵌的数据源是有条件限制的。在 EmbeddedDatabaseConfiguration 类上还使用一个 @Conditional 注解,该注解使用了DataSourceAutoConfiguration 的内部限制条件类 EmbeddedDatabaseCondition 来进行条件判断
static class EmbeddedDatabaseCondition extends SpringBootCondition {
private static final String DATASOURCE_URL_PROPERTY = "spring.datasource.url";
private final SpringBootCondition pooledCondition = new DataSourceAutoConfiguration.PooledDataSourceCondition();
EmbeddedDatabaseCondition() {
}
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypemetadata metadata) {
Builder message = ConditionMessage.forCondition("EmbeddedDataSource", new Object[0]);
if (this.hasDataSourceUrlProperty(context)) {
return ConditionOutcome.noMatch(message.because("spring.datasource.url is set"));
} else if (this.anyMatches(context, metadata, new Condition[]{this.pooledCondition})) {
return ConditionOutcome.noMatch(message.foundExactly("supported pooled data source"));
} else {
EmbeddedDatabaseType type = EmbeddedDatabaseConnection.get(context.getClassLoader()).getType();
return type == null ? ConditionOutcome.noMatch(message.didNotFind("embedded database").atAll()) : ConditionOutcome.match(message.found("embedded database").items(new Object[]{type}));
}
}
private boolean hasDataSourceUrlProperty(ConditionContext context) {
Environment environment = context.getEnvironment();
if (environment.containsProperty("spring.datasource.url")) {
try {
return StringUtils.hasText(environment.getProperty("spring.datasource.url"));
} catch (IllegalArgumentException var4) {
}
}
return false;
}
}
EmbeddedDatabaseCondition 主要用来检测容器中是否已经存在池化数据源(PooledDataSource)。若容器中存在池化数据源时,则 EmbeddedDatabaseConfiguration 不能被实例化。只有当容器中不存在池化数据源时,EmbeddedDatabaseConfiguration 才能被实例化,才能向容器中添加内嵌数据源(EmbeddedDataSource)
PooledDataSourceConfiguration类PooledDataSourceConfiguration 是池化数据源的自动配置类,该类上使用了一个 @Conditional 注解,该注解使用了 DataSourceAutoConfiguration 的内部限制条件类 PooledDataSourceCondition 来进行条件判断。
@Configuration(
proxyBeanMethods = false
)
@Conditional({DataSourceAutoConfiguration.PooledDataSourceCondition.class})
@ConditionalOnMissingBean({DataSource.class, XADataSource.class})
@import({Hikari.class, Tomcat.class, Dbcp2.class, OracleUcp.class, Generic.class, DataSourceJmxConfiguration.class})
protected static class PooledDataSourceConfiguration {
protected PooledDataSourceConfiguration() {
}
}
与 EmbeddedDatabaseConfiguration 一样,PooledDataSourceConfiguration 类中也没有任何的方法实现,它的所有功能都是通过 @import 注解引入其他的类实现的。PooledDataSourceConfiguration 通过 @import 注解引入了 Hikari、Tomcat、Dbcp2、OracleUcp 和 Generic 五个数据源配置类,它们都是 DataSourceConfiguration 的内部类,且它们的功能类似,都是向容器中添加指定的数据源。下面我们以 Hikari 为例进行分析,Hikari 的源码如下
@Configuration(
proxyBeanMethods = false //@Configuration:表示当前类是一个配置类
)
@ConditionalOnClass({HikariDataSource.class}) //表示必须在类路径中存在 HikariDataSource 类时,Hikari 才会实例化。而 HikariDataSource 类是由 spring- boot-starter-jdbc 默认将其引入的,因此只要我们在 pom.xml 中引入了该 starter, Hikari 就会被实例化(这也是 Spring Boot 2.x 默认使用 HikariCP 作为其数据源的原因)
@ConditionalOnMissingBean({DataSource.class}) //表示容器中没有用户自定义的数据源时,该配置类才会被实例化
@ConditionalOnProperty(
name = {"spring.datasource.type"},
havingValue = "com.zaxxer.hikari.HikariDataSource",
matchIfMissing = true
) //表示当 Spring Boot 配置文件中,配置了 spring.datasource.type = com.zaxxer.hikari.HikariDataSource(明确指定使用 Hikari 数据源)或者不配置 spring.datasource.type(即默认情况)时,Hikari 才会被实例化
static class Hikari {
Hikari() {
}
@Bean
@ConfigurationProperties(
prefix = "spring.datasource.hikari"
)
HikariDataSource dataSource(DataSourceProperties properties) {
HikariDataSource dataSource = (HikariDataSource)DataSourceConfiguration.createDataSource(properties, HikariDataSource.class);
if (StringUtils.hasText(properties.getName())) {
dataSource.setPoolName(properties.getName());
}
return dataSource;
}
}
Hikari 类通过 @Bean 注解向容器中添加了 HikariDataSource 组件,该组件的实例对象是通过调用 DataSourceConfiguration 的 createDataSource() 方法得到的,代码如下
@Bean
@ConfigurationProperties(
prefix = "spring.datasource.hikari"
)
HikariDataSource dataSource(DataSourceProperties properties) {
HikariDataSource dataSource = (HikariDataSource)DataSourceConfiguration.createDataSource(properties, HikariDataSource.class);
if (StringUtils.hasText(properties.getName())) {
dataSource.setPoolName(properties.getName());
}
return dataSource;
}
在 createDataSource() 方法中,调用 DataSourceProperties 的 initializeDataSourceBuilder() 来初始化 DataSourceBuilder,源码如下
protected staticT createDataSource(DataSourceProperties properties, Class extends DataSource> type) { return properties.initializeDataSourceBuilder().type(type).build(); }
initializeDataSourceBuilder() 方法通过调用 DataSourceBuilder 的 create() 方法创建 DataSourceBuilder 对象,并根据 Spring Boot 的配置文件(application.properties/yml)中的配置,依次设置数据源类型、驱动类名、连接 url、 用户名和密码等信息
public DataSourceBuilder> initializeDataSourceBuilder() {
return DataSourceBuilder.create(this.getClassLoader()).type(this.getType()).
driverClassName(this.determineDriverClassName()).url(this.determineUrl()).username(this.determineUsername()).password(this.determinePassword());
}
PooledDataSourceCondition条件类
PooledDataSourceConfiguration 是池化数据源的自动配置类,该类上使用了一个 @Conditional 注解,该注解使用了 DataSourceAutoConfiguration 的内部限制条件类 PooledDataSourceCondition 来进行条件判断
static class PooledDataSourceCondition extends AnyNestedCondition {
PooledDataSourceCondition() {
super(ConfigurationPhase.PARSE_CONFIGURATION);
}
@Conditional({DataSourceAutoConfiguration.PooledDataSourceAvailableCondition.class})
static class PooledDataSourceAvailable {
PooledDataSourceAvailable() {
}
}
@ConditionalOnProperty(
prefix = "spring.datasource",
name = {"type"}
)
static class ExplicitType {
ExplicitType() {
}
}
}
PooledDataSourceCondition 与 EmbeddedDatabaseCondition 一样,也是用来检测容器中是否已经存在池化数据源的,但不同的是,PooledDataSourceConfiguration 是只有当容器中存在池化数据源时, 才可以被实例化,才可以向容器中添加池化数据源
PooledDataSourceAvailableCondition条件类PooledDataSourceCondition 调用了PooledDataSourceAvailableCondition类
static class PooledDataSourceAvailableCondition extends SpringBootCondition {
PooledDataSourceAvailableCondition() {
}
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypemetadata metadata) {
Builder message = ConditionMessage.forCondition("PooledDataSource", new Object[0]);
return DataSourceBuilder.findType(context.getClassLoader()) != null ? ConditionOutcome.match(message.foundExactly("supported DataSource")) : ConditionOutcome.noMatch(message.didNotFind("supported DataSource").atAll());
}
}
数据源自动配置原理小结
通过对 Spring Boot 数据源自动配置原理的分析可知:
- 在用户没有配置数据源的情况,若容器中存在 HikariDataSource 类,则 Spring Boot 就会自动实例化 Hikari,并将其作为其数据源。
- Spring Boot 的 JDBC 场景启动器(spring-boot-starter-data-jdbc)通过 spring- boot-starter-jdbc 默认引入了 HikariCP 数据源(包含 HikariDataSource 类),因此 Spring Boot 默认使用 HikariCP 作为其数据源
Spring Boot 2.x 默认使用 HikariCP 作为数据源,我们只要在项目中导入了 Spring Boot 的 JDBC 场景启动器,便可以使用 HikariCP 数据源获取数据库连接,对数据库进行增删改查等操作。HikariCP 是目前市面上性能最好的数据源产品,但在实际的开发过程中,企业往往使用另一款数据源产品:Druid,它是目前国内使用范围最广的数据源产品。Druid 是阿里巴巴推出的一款开源的高性能数据源产品,Druid 支持所有 JDBC 兼容的数据库,包括 Oracle、MySQL、SQL Server 和 H2 等等。Druid 不仅结合了 C3P0、DBCP 和 PROXOOL 等数据源产品的优点,同时还加入了强大的监控功能。通过 Druid 的监控功能,可以实时观察数据库连接池和 SQL 的运行情况,帮助用户及时排查出系统中存在的问题。Druid 不是 Spring Boot 内部提供的技术,它属于第三方技术,我们可以通过阿里提供的 starter 整合 Druid
1 引入 druid-spring-boot-starter场景启动器在 Spring Boot 项目的 pom.xml 中添加以下依赖,引入 Druid Spring Boot Starter最新版本
com.alibaba
druid-spring-boot-starter
1.2.8
2 Druid相关配置属性
Druid Spring Boot Starter 已经将 Druid 数据源中的所有模块都进行默认配置,我们也可以通过 Spring Boot 配置文件(application.properties/yml)来修改 Druid 各个模块的配置,否则将使用默认配置。在 Spring Boot 配置文件中配置以下内容:
- JDBC 通用配置
- Druid 数据源连接池配置
- Druid 监控配置
- Druid 内置 Filter 配置
以上自动配置内容都由starter整合好了,所以不需要我们再去写自动配置类
1 JDBC 通用配置我们可以在 Spring Boot 的配置文件中对 JDBC 进行通用配置,例如,数据库用户名、数据库密码、数据库 URL 以及 数据库驱动等等,示例代码如下
#数据源连接信息
spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/test?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
我们再次请求测试:
package com.example.springboot;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.sql.SQLException;
@SpringBootTest
class SpringbootApplicationTests {
//数据源组件
@Resource
DataSource dataSource;
//用于访问数据库的组件
@Resource
JdbcTemplate jdbcTemplate;
@Test
void contextLoads() throws SQLException {
System.out.println("默认数据源为:" + dataSource.getClass());
System.out.println("数据库连接实例:" + dataSource.getConnection());
//访问数据库
Integer i = jdbcTemplate.queryForObject("SELECt count(*) from `person`", Integer.class);
System.out.println("user 表中共有" + i + "条数据。");
}
}
因为当容器中没有 DataSource(数据源类)时,Spring Boot 才会使用 HikariCP 作为其默认数据源。 也就是说,若我们向容器中添加 Druid 数据源类(DruidDataSource,继承自 DataSource)的对象时,Spring Boot 就会使用 Druid 作为其数据源,而不再使用 HikariCP,所以打印结果如下:
我们还可以在 Spring Boot 的配置文件中对 Druid 数据源连接池进行配置,示例代码如下
################################################## Druid连接池的配置 ##########################################
spring:
datasource:
druid:
initial-size: 5 #初始化连接大小
min-idle: 5 #最小连接池数量
max-active: 20 #最大连接池数量
max-wait: 60000 #获取连接时最大等待时间,单位毫秒
time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
min-evictable-idle-time-millis: 300000 #配置一个连接在池中最小生存的时间,单位是毫秒
validation-query: SELECt 1 FROM DUAL #测试连接
test-while-idle: true #申请连接的时候检测,建议配置为true,不影响性能,并且保证安全性
test-on-borrow: false #获取连接时执行检测,建议关闭,影响性能
test-on-return: false #归还连接时执行检测,建议关闭,影响性能
pool-prepared-statements: false #是否开启PSCache,PSCache对支持游标的数据库性能提升巨大,oracle建议开启,mysql下建议关闭
max-pool-prepared-statement-per-connection-size: 20 #开启poolPreparedStatements后生效
filters: stat,wall #配置扩展插件,常用的插件有=>stat:监控统计 wall:防御sql注入
connection-properties: 'druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000' #通过connectProperties属性来打开mergeSql功能;慢SQL记录
3 Druid 监控配置
我们还可以在 Spring Boot 的配置文件中对 Druid 内置监控页面、Web-JDBC 关联监控和 Spring 监控等功能进行配置,示例代码如下
###################################################### Druid 监控配置信息 ##########################################
spring:
datasource:
druid:
# StatViewServlet配置,说明请参考Druid Wiki,配置_StatViewServlet配置
stat-view-servlet:
enabled: true #是否开启内置监控页面,默认值为 false
url-pattern: '/druid
@ResponseBody
@GetMapping("/getPersonCount")
public String testSql() {
String SQL = "SELECt count(*) from `person`";
Integer integer = jdbcTemplate.queryForObject(SQL, Integer.class);
return integer.toString();
}
}
请求一下:
然后观察下监控的变化,发现SQL语句被监控到了
同时URI地址监控也监控到了请求信息:
Druid Spring Boot Starter 对以下 Druid 内置 Filter,都提供了默认配置:StatFilter,WallFilter,ConfigFilter,EncodingConvertFilter,Slf4jLogFilter,Log4jFilter,Log4j2Filter,CommonsLogFilter:
- 可以通过 spring.datasource.druid.filters=stat,wall ... 的方式来启用相应的内置 Filter
- 如果默认配置不能满足我们的需求,我们还可以在配置文件使用 spring.datasource.druid.filter.* 对这些 Filter 进行配置
示例代码如下
# ####################################################### Druid 监控配置信息 ##########################################
spring:
datasource:
druid:
# 对配置已开启的 filters 即 stat(sql 监控) wall(防火墙)
filter:
#配置StatFilter (SQL监控配置)
stat:
enabled: true #开启 SQL 监控
slow-sql-millis: 1000 #慢查询
log-slow-sql: true #记录慢查询 SQL
#配置WallFilter (防火墙配置)
wall:
enabled: true #开启防火墙
config:
update-allow: true #允许更新操作
drop-table-allow: false #禁止删表操作
insert-allow: true #允许插入操作
delete-allow: true #删除数据操作
在配置 Druid 内置 Filter 时,需要先将对应 Filter 的 enabled 设置为 true,否则内置 Filter 的配置不会生效
SpringBoot整合MyBatis我们之前在SSM框架整合中了解过如何通过Spring整合MyBatis,那么SpringBoot既然要简化,也需要整合MyBatis,MyBatis 也开发了一套基于 Spring Boot 模式的 starter:mybatis-spring-boot-starter
1 引入mybatis-spring-boot-starter场景启动器Spring Boot 整合 MyBatis 的第一步,就是在项目的 pom.xml 中引入 mybatis-spring-boot-starter 的依赖
使用当前最新版本:
2 配置 MyBatisorg.mybatis.spring.boot mybatis-spring-boot-starter 2.2.0
在 Spring Boot 的配置文件(application.properties/yml)中对 MyBatis 进行配置,例如指定 mapper.xml 的位置、实体类的位置、是否开启驼峰命名法等等
###################################### MyBatis 配置######################################
mybatis:
# 指定 mapper.xml 的位置
mapper-locations: classpath:mapper/*.xml
#扫描实体类的位置,在此处指明扫描实体类的包,在 mapper.xml 中就可以不写实体类的全路径名
type-aliases-package: com.example.model
configuration:
#默认开启驼峰命名法,可以不用设置该属性
map-underscore-to-camel-case: true
使用 MyBatis 时,必须配置数据源信息,例如数据库 URL、数据库用户型、数据库密码和数据库驱动等,也就是我们前面的数据库驱动相关配置:
#数据源连接信息
spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/test?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
3 创建实体类
我们在model包下创建Person这个实体类用来映射数据表,也就是创建PO
代码如下:
package com.example.springboot.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
private int id;
private String username;
private String password;
private int age;
private int phone;
private String email;
private String hobby;
}
4 PersonDao接口创建
在dao包下创建一个PersonDao接口,用来写接口方法:
package com.example.springboot.dao;
import com.example.springboot.model.Person;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface PersonDao {
List getPersonList();
}
5 personMapper.xml映射文件编写
在资源路径下的mapper文件夹添加personMapper.xml映射文件
6 测试访问数据库
我们写个单元测试访问下数据库:
package com.example.springboot;
import com.example.springboot.dao.PersonDao;
import com.example.springboot.model.Person;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.List;
@SpringBootTest
class SpringbootApplicationTests {
//数据源组件
@Resource
DataSource dataSource;
@Resource
PersonDao personDao;
@Test
void testMyBatis() throws SQLException {
System.out.println("默认数据源为:" + dataSource.getClass());
System.out.println("数据库连接实例:" + dataSource.getConnection());
//访问数据库
List personList=personDao.getPersonList();
System.out.println(personList);
}
}
打印结果如下:
还记得我们在之前的SSM整合中还有两个重要配置,这里没有出现,一个是MyBatis的核心配置文件
另外一个是Spring整合MyBatis的配置文件
其实可以看的出,SpringBoot做了一个大一统,数据源连接池选什么?数据库驱动信息选哪些?都是可以选配的,而在yml配置文件中由于有了自动配置,配置和容器注入也进行了分离,使我们的配置视角更加单纯,只关注配置信息,别的starter都帮我们做好了,简单看下代码:
MyBatis-Spring-Boot-Starter 将会完成以下功能:
- 自动发现存在的DataSource
- 利用SqlSessionFactoryBean创建并注册SqlSessionFactory
- 创建并注册SqlSessionTemplate
- 自动扫描Mappers,并注册到Spring上下文环境方便程序的注入使用
默认情况下,MyBatis-Spring-Boot-Starter会查找以@Mapper注解标记的映射器,所以这也就解释了为什么我们不需要那些额外的配置了,场景启动器都帮我们做好了。
整体yml文件配置清单我们一步步从JDBC到连接池Druid到MyBatis整合到了SpringBoot中,返回来看看我们全部的yml配置内容吧:
#数据源连接信息
spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/test?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
################################################## Druid连接池的配置 ##########################################
druid:
initial-size: 5 #初始化连接大小
min-idle: 5 #最小连接池数量
max-active: 20 #最大连接池数量
max-wait: 60000 #获取连接时最大等待时间,单位毫秒
time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
min-evictable-idle-time-millis: 300000 #配置一个连接在池中最小生存的时间,单位是毫秒
validation-query: SELECT 1 FROM DUAL #测试连接
test-while-idle: true #申请连接的时候检测,建议配置为true,不影响性能,并且保证安全性
test-on-borrow: false #获取连接时执行检测,建议关闭,影响性能
test-on-return: false #归还连接时执行检测,建议关闭,影响性能
pool-prepared-statements: false #是否开启PSCache,PSCache对支持游标的数据库性能提升巨大,oracle建议开启,mysql下建议关闭
max-pool-prepared-statement-per-connection-size: 20 #开启poolPreparedStatements后生效
filters: stat,wall #配置扩展插件,常用的插件有=>stat:监控统计 wall:防御sql注入
connection-properties: 'druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000' #通过connectProperties属性来打开mergeSql功能;慢SQL记录
###################################################### Druid 监控配置信息 ##########################################
# StatViewServlet配置,说明请参考Druid Wiki,配置_StatViewServlet配置
stat-view-servlet:
enabled: true #是否开启内置监控页面,默认值为 false
url-pattern: '/druid/*' #StatViewServlet 的映射路径,即内置监控页面的访问地址
reset-enable: true #是否启用重置按钮
login-username: admin #内置监控页面的登录页用户名 username
login-password: admin #内置监控页面的登录页密码 password
# WebStatFilter配置,说明请参考Druid Wiki,配置_配置WebStatFilter
web-stat-filter:
enabled: true #是否开启内置监控中的 Web-jdbc 关联监控的数据
url-pattern: '/*' #匹配路径
exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*' #排除路径
session-stat-enable: true #是否监控session
# Spring监控配置,说明请参考Druid Github Wiki,配置_Druid和Spring关联监控配置
aop-patterns: net.biancheng.www.* #Spring监控AOP切入点,如x.y.z.abc.*,配置多个英文逗号分隔
######################################################## Druid 监控配置信息 ##########################################
# 对配置已开启的 filters 即 stat(sql 监控) wall(防火墙)
filter:
#配置StatFilter (SQL监控配置)
stat:
enabled: true #开启 SQL 监控
slow-sql-millis: 1000 #慢查询
log-slow-sql: true #记录慢查询 SQL
#配置WallFilter (防火墙配置)
wall:
enabled: true #开启防火墙
config:
update-allow: true #允许更新操作
drop-table-allow: false #禁止删表操作
insert-allow: true #允许插入操作
delete-allow: true #删除数据操作
###################################### MyBatis 配置######################################
mybatis:
# 指定 mapper.xml 的位置
mapper-locations: classpath:mapper/*.xml
#扫描实体类的位置,在此处指明扫描实体类的包,在 mapper.xml 中就可以不写实体类的全路径名
type-aliases-package: com.example.springboot.model
configuration:
#默认开启驼峰命名法,可以不用设置该属性
map-underscore-to-camel-case: true
总结一下
其实本篇Blog涉及了三个数据相关的整合:JDBC+Druid+MyBatis,那么这三个有什么区别呢?我们平时是如何组合使用呢?
- JDBC:其实是一套标准和规范,最原始的数据库操作方式,负责:加载数据库驱动,创建连接,写原生语句,执行,关闭连接
- Druid:光有JDBC太简单了,我们需要连接池来解决高并发场景下的性能问题,这个时候就需要一些数据源工具,例如Druid,它是对JDBC的一些简单封装,最主要的就是连接池的加入,Druid可以创建很多的数据库连接放到连接池里供MyBatis使用
- MyBatis:MyBatis是对JDBC的封装,一个半自动的ORM框架,和JDBC的对比我在之前的Blog详细提到过,说白了就是一个方便我们使用的框架,MyBatis在让JDBC更好用的基础上还可以灵活驱动Druid提供的连接去进行操作。
那么这三者是如何配合工作的呢?
- 项目启动时Druid就已经使用JDBC创建好一堆连接留待后用
- 当请求到mapper(Dao)时,MyBatis框架创建临时类,并且将动态sql进行替换重写变成原始的native sql
- MyBatis从Druid拿到一个连接,将sql通过连接交给数据库执行,获取执行结果,最终将结果进行映射并返回数据
也就是MyBatis替我们选好了数据源(Druid),并且实际上最终调用JDBC原生方法执行数据操作。



