SpringBoot-默认数据源HikariDataSource对数据库操作及自动装配原理

x33g5p2x  于2022-05-18 转载在 Spring  
字(8.5k)|赞(0)|评价(0)|浏览(869)

默认数据源HikariDataSource对数据库操作

  1. 在创建项目时选择JDBC以及MySQL驱动,让SpringBoot自动装配所需组件

创建完成后默认的pom.xml文件如下

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>2.1.7.RELEASE</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>com.guih</groupId>
  12. <artifactId>spring-boot-data-jdbc</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>spring-boot-data-jdbc</name>
  15. <description>JDBC Demo project for Spring Boot</description>
  16. <properties>
  17. <java.version>1.8</java.version>
  18. </properties>
  19. <dependencies>
  20. <!-- SpringBoot集成的JDBC以及数据库连接包 -->
  21. <dependency>
  22. <groupId>org.springframework.boot</groupId>
  23. <artifactId>spring-boot-starter-jdbc</artifactId>
  24. </dependency>
  25. <dependency>
  26. <groupId>mysql</groupId>
  27. <artifactId>mysql-connector-java</artifactId>
  28. <scope>runtime</scope>
  29. </dependency>
  30. <dependency>
  31. <groupId>org.springframework.boot</groupId>
  32. <artifactId>spring-boot-starter-web</artifactId>
  33. </dependency>
  34. <dependency>
  35. <groupId>org.springframework.boot</groupId>
  36. <artifactId>spring-boot-starter-test</artifactId>
  37. <scope>test</scope>
  38. </dependency>
  39. </dependencies>
  40. <build>
  41. <plugins>
  42. <plugin>
  43. <groupId>org.springframework.boot</groupId>
  44. <artifactId>spring-boot-maven-plugin</artifactId>
  45. </plugin>
  46. </plugins>
  47. </build>
  48. </project>
  1. 创建 application.yml 文件,配置连接数据库的参数
  1. spring:
  2. datasource:
  3. username: root
  4. password: 123456
  5. driver-class-name: com.mysql.cj.jdbc.Driver
  6. url: jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=false
  1. 测试是否能获取到数据源
  1. // 单元测试代码
  2. @RunWith(SpringRunner.class)
  3. @SpringBootTest
  4. public class SpringBootDataJdbcApplicationTests {
  5. @Autowired
  6. private DataSource dataSource;
  7. @Test
  8. public void test() throws SQLException {
  9. Connection data = dataSource.getConnection();
  10. System.out.println("------" + data.getClass());
  11. System.out.println("------" + dataSource.getClass());
  12. data.close();
  13. }
  14. }

输出结果如下,数据源获取成功,说明SpringBoot2.1.7默认使用的是Hikari连接池**(SpringBoot2.0之前使用的是tomcat连接池)**

  1. ------class com.zaxxer.hikari.pool.HikariProxyConnection
  2. ------class com.zaxxer.hikari.HikariDataSource
  1. 使用数据源对数据库进行操作

  2. 为了方便测试,这里使用的数据库是本机上的数据库

  1. 编写代码测试访问数据库
  1. @Controller
  2. public class JDBCTest {
  3. @Autowired
  4. private JdbcTemplate jdbcTemplate;
  5. @RequestMapping("/query")
  6. @ResponseBody
  7. public Map<String, Object> query() {
  8. List<Map<String, Object>> list = jdbcTemplate.queryForList("SELECT * FROM test1");
  9. return list.get(0);
  10. }
  11. }
  1. 启动SpringBoot程序并使用Postman进行测试

SpringBoot默认数据源自动装配原理

  1. 参考org.springframework.boot.autoconfigure.jdbc包下的DataSourceConfigration类
  1. package org.springframework.boot.autoconfigure.jdbc;
  2. import javax.sql.DataSource;
  3. import com.zaxxer.hikari.HikariDataSource;
  4. import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
  5. import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
  6. import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  7. import org.springframework.boot.context.properties.ConfigurationProperties;
  8. import org.springframework.boot.jdbc.DatabaseDriver;
  9. import org.springframework.context.annotation.Bean;
  10. import org.springframework.context.annotation.Configuration;
  11. import org.springframework.util.StringUtils;
  12. abstract class DataSourceConfiguration {
  13. @SuppressWarnings("unchecked")
  14. protected static <T> T createDataSource(DataSourceProperties properties, Class<? extends DataSource> type) {
  15. return (T) properties.initializeDataSourceBuilder().type(type).build();
  16. }
  17. // 根据容器中的情况来进行逻辑判断,添加不同的数据源
  18. @Configuration
  19. @ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
  20. @ConditionalOnMissingBean(DataSource.class)
  21. @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.tomcat.jdbc.pool.DataSource",
  22. matchIfMissing = true)
  23. static class Tomcat {
  24. @Bean
  25. @ConfigurationProperties(prefix = "spring.datasource.tomcat")
  26. public org.apache.tomcat.jdbc.pool.DataSource dataSource(DataSourceProperties properties) {
  27. org.apache.tomcat.jdbc.pool.DataSource dataSource = createDataSource(properties,
  28. org.apache.tomcat.jdbc.pool.DataSource.class);
  29. DatabaseDriver databaseDriver = DatabaseDriver.fromJdbcUrl(properties.determineUrl());
  30. String validationQuery = databaseDriver.getValidationQuery();
  31. if (validationQuery != null) {
  32. dataSource.setTestOnBorrow(true);
  33. dataSource.setValidationQuery(validationQuery);
  34. }
  35. return dataSource;
  36. }
  37. }
  38. @Configuration
  39. @ConditionalOnClass(HikariDataSource.class)
  40. @ConditionalOnMissingBean(DataSource.class)
  41. @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource",
  42. matchIfMissing = true)
  43. static class Hikari {
  44. @Bean
  45. @ConfigurationProperties(prefix = "spring.datasource.hikari")
  46. public HikariDataSource dataSource(DataSourceProperties properties) {
  47. HikariDataSource dataSource = createDataSource(properties, HikariDataSource.class);
  48. if (StringUtils.hasText(properties.getName())) {
  49. dataSource.setPoolName(properties.getName());
  50. }
  51. return dataSource;
  52. }
  53. }
  54. // 也可以指定其他的数据源
  55. @Configuration
  56. @ConditionalOnClass(org.apache.commons.dbcp2.BasicDataSource.class)
  57. @ConditionalOnMissingBean(DataSource.class)
  58. @ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.commons.dbcp2.BasicDataSource",
  59. matchIfMissing = true)
  60. static class Dbcp2 {
  61. @Bean
  62. @ConfigurationProperties(prefix = "spring.datasource.dbcp2")
  63. public org.apache.commons.dbcp2.BasicDataSource dataSource(DataSourceProperties properties) {
  64. return createDataSource(properties, org.apache.commons.dbcp2.BasicDataSource.class);
  65. }
  66. }
  67. @Configuration
  68. @ConditionalOnMissingBean(DataSource.class)
  69. @ConditionalOnProperty(name = "spring.datasource.type")
  70. static class Generic {
  71. @Bean
  72. public DataSource dataSource(DataSourceProperties properties) {
  73. // 使用DataSourceBuilder创建数据源,利用反射创建响应type的数据源,并且绑定相关属性
  74. return properties.initializeDataSourceBuilder().build();
  75. }
  76. }
  77. }

从代码中可以看出SpringBoot是根据用户的配置来自动配置不同的数据源,目前支持的数据源有以下三种

  1. com.zaxxer.hikari.HikariDataSource Spring Boot 2.0 以上,默认使用此数据源)
  2. org.apache.tomcat.jdbc.pool.DataSource
  3. org.apache.commons.dbcp2.BasicDataSource

还可以在配置文件中使用 “spring.datasource.type” 属性来配置用户指定的数据源

  1. 在同一个包下的另一个类 DataSourceInitializer,当我们要在SpringBoot启动时运行sql建表语句或插入数据时就会用得上
  1. // DataSourceInitializer类部分代码
  2. public boolean createSchema() {
  3. List<Resource> scripts = getScripts("spring.datasource.schema", this.properties.getSchema(), "schema");
  4. if (!scripts.isEmpty()) {
  5. if (!isEnabled()) {
  6. logger.debug("Initialization disabled (not running DDL scripts)");
  7. return false;
  8. }
  9. String username = this.properties.getSchemaUsername();
  10. String password = this.properties.getSchemaPassword();
  11. runScripts(scripts, username, password);
  12. }
  13. return !scripts.isEmpty();
  14. }
  15. public void initSchema() {
  16. List<Resource> scripts = getScripts("spring.datasource.data", this.properties.getData(), "data");
  17. if (!scripts.isEmpty()) {
  18. if (!isEnabled()) {
  19. logger.debug("Initialization disabled (not running data scripts)");
  20. return;
  21. }
  22. String username = this.properties.getDataUsername();
  23. String password = this.properties.getDataPassword();
  24. runScripts(scripts, username, password);
  25. }
  26. }
  27. private void runScripts(List<Resource> resources, String username, String password) {
  28. if (resources.isEmpty()) {
  29. return;
  30. }
  31. ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
  32. populator.setContinueOnError(this.properties.isContinueOnError());
  33. populator.setSeparator(this.properties.getSeparator());
  34. if (this.properties.getSqlScriptEncoding() != null) {
  35. populator.setSqlScriptEncoding(this.properties.getSqlScriptEncoding().name());
  36. }
  37. for (Resource resource : resources) {
  38. populator.addScript(resource);
  39. }
  40. DataSource dataSource = this.dataSource;
  41. if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
  42. dataSource = DataSourceBuilder.create(this.properties.getClassLoader())
  43. .driverClassName(this.properties.determineDriverClassName()).url(this.properties.determineUrl())
  44. .username(username).password(password).build();
  45. }
  46. DatabasePopulatorUtils.execute(populator, dataSource);
  47. }

从代码中可以看出SpringBoot会从配置文件中读取 “spring.datasource.schema” 属性用于数据库建表,读取 “spring.datasource.data” 属性用于写入数据,所以在需要程序在创建时运行sql文件可以通过这个参数来配置

相关文章