SpringBoot底層與數據庫打交道是基於 SpringData來操作的,今天就來簡單記錄下這其中的奧祕
這篇博客不整合其他的ORM框架,僅僅使用jdbc的方式來探究原理。
首先我們要訪問數據庫,就需要一個數據源,有關數據源的配置SpringBoot是放在DataSourceConfiguration
中
我們點進去發現這個類是和全局配置文件中的spring.datasource.type
屬性相綁定的:
@ConditionalOnMissingBean({DataSource.class})
@ConditionalOnProperty(
name = {"spring.datasource.type"}
)
同時,它下面有幾個方法,是依據我們系統引入了哪些包,而選用哪種數據源(SpringBoot2.x默認採用hikari數據源)
@ConditionalOnClass({BasicDataSource.class})
@ConditionalOnMissingBean({DataSource.class})
@ConditionalOnProperty(
name = {"spring.datasource.type"},
havingValue = "org.apache.commons.dbcp2.BasicDataSource",
matchIfMissing = true
)
static class Dbcp2 {
Dbcp2() {
}
@Bean
@ConfigurationProperties(
prefix = "spring.datasource.dbcp2"
)
BasicDataSource dataSource(DataSourceProperties properties) {
return (BasicDataSource)DataSourceConfiguration.createDataSource(properties, BasicDataSource.class);
}
}
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({HikariDataSource.class})
@ConditionalOnMissingBean({DataSource.class})
@ConditionalOnProperty(
name = {"spring.datasource.type"},
havingValue = "com.zaxxer.hikari.HikariDataSource",
matchIfMissing = true
)
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;
}
}
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({org.apache.tomcat.jdbc.pool.DataSource.class})
@ConditionalOnMissingBean({DataSource.class})
@ConditionalOnProperty(
name = {"spring.datasource.type"},
havingValue = "org.apache.tomcat.jdbc.pool.DataSource",
matchIfMissing = true
)
static class Tomcat {
Tomcat() {
}
@Bean
@ConfigurationProperties(
prefix = "spring.datasource.tomcat"
)
org.apache.tomcat.jdbc.pool.DataSource dataSource(DataSourceProperties properties) {
org.apache.tomcat.jdbc.pool.DataSource dataSource = (org.apache.tomcat.jdbc.pool.DataSource)DataSourceConfiguration.createDataSource(properties, org.apache.tomcat.jdbc.pool.DataSource.class);
DatabaseDriver databaseDriver = DatabaseDriver.fromJdbcUrl(properties.determineUrl());
String validationQuery = databaseDriver.getValidationQuery();
if (validationQuery != null) {
dataSource.setTestOnBorrow(true);
dataSource.setValidationQuery(validationQuery);
}
return dataSource;
}
}
現在我們就去全局配置中來配置,以yaml
文件爲例
spring:
datasource:
username: root
password: ***
url: jdbc:mysql://localhost:3306/demo
driver-class-name: com.mysql.jdbc.Driver
這樣就配置好了,並且它會幫我們自動注入到容器中。有數據源後,我們就來測試一下,寫個測試方法,打印出數據源和連接:
@SpringBootTest
class SpringbootDataApplicationTests {
@Autowired
private DataSource dataSource;
@Test
void contextLoads() throws SQLException {
System.out.println("i am datasource:"+dataSource.getClass().getName());
Connection connection = dataSource.getConnection();
System.out.println(connection);
}
}
運行結果
獲取連接成功
我們目光回到DatasourceConfiguration
中,如果我們想用到自己指定的數據源,它是怎麼樣的
/**
* Generic DataSource configuration.
*/
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class Generic {
@Bean
public DataSource dataSource(DataSourceProperties properties) {
//使用DataSourceBuilder創建數據源,利用反射創建響應type的數據源,並且綁定相關屬性
return properties.initializeDataSourceBuilder().build();
}
}
數據源這塊的源碼解析完畢,接着看看還有一個類DataSourceInitializer
,它就是幫我們初始化數據源的,內部有兩個方法
runSchemaScripts
和runDataScripts
,一個是幫我們運行建表語句,另外是運行插入數據庫的sql語句
runSchemaScripts
:它底層也是根據你指定的sql文件的路徑,去運行指定的sql腳本,如果沒有指定路徑,則默認去尋找schema.sql/schema-all.sql
文件並執行。(SpringBoot2.x已經默認不掃描,有興趣的話可以查看另外一篇博客)- 操作數據庫這塊,底層有一個類
JdbcTemplateConfiguration
,它幫我們自動注入了JdbcTemplate
進容器中,我們可以直接操作
@ConditionalOnMissingBean({JdbcOperations.class})
class JdbcTemplateConfiguration {
JdbcTemplateConfiguration() {
}
@Bean
@Primary
JdbcTemplate jdbcTemplate(DataSource dataSource, JdbcProperties properties) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
Template template = properties.getTemplate();
jdbcTemplate.setFetchSize(template.getFetchSize());
jdbcTemplate.setMaxRows(template.getMaxRows());
if (template.getQueryTimeout() != null) {
jdbcTemplate.setQueryTimeout((int)template.getQueryTimeout().getSeconds());
}
return jdbcTemplate;
}
}
到這裏咱們就可以在測試類直接注入jdbcTemplate
來進行操作了,這裏就略過了