导入JDBC场景
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
接着导入数据库驱动包(MySQL为例)
<!--默认版本:-->
<mysql.version>8.0.22</mysql.version>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<!--<version>5.1.49</version>-->
</dependency>
<!--
想要修改版本
1、直接依赖引入具体版本(maven的就近依赖原则)
2、重新声明版本(maven的属性的就近优先原则)
-->
<properties>
<java.version>1.8</java.version>
<mysql.version>5.1.49</mysql.version>
</properties>
数据库驱动?
为什么导入JDBC场景,官方不导入驱动?官方不知道我们接下要操作什么数据库。
数据库版本和驱动版本对应
相关数据源配置类
DataSourceAutoConfiguration
: 数据源的自动配置。
/**
* {@link EnableAutoConfiguration Auto-configuration} for {@link DataSource}.
*
* @author Dave Syer
* @author Phillip Webb
* @author Stephane Nicoll
* @author Kazuki Shimizu
* @since 1.0.0
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@Conditional(EmbeddedDatabaseCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import(EmbeddedDataSourceConfiguration.class)
protected static class EmbeddedDatabaseConfiguration {
}
@Configuration(proxyBeanMethods = false)
@Conditional(PooledDataSourceCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class,
DataSourceJmxConfiguration.class })
protected static class PooledDataSourceConfiguration {
}
/**
* {@link AnyNestedCondition} that checks that either {@code spring.datasource.type}
* is set or {@link PooledDataSourceAvailableCondition} applies.
*/
static class PooledDataSourceCondition extends AnyNestedCondition {
PooledDataSourceCondition() {
super(ConfigurationPhase.PARSE_CONFIGURATION);
}
@ConditionalOnProperty(prefix = "spring.datasource", name = "type")
static class ExplicitType {
}
@Conditional(PooledDataSourceAvailableCondition.class)
static class PooledDataSourceAvailable {
}
}
/**
* {@link Condition} to test if a supported connection pool is available.
*/
static class PooledDataSourceAvailableCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
ConditionMessage.Builder message = ConditionMessage.forCondition("PooledDataSource");
if (DataSourceBuilder.findType(context.getClassLoader()) != null) {
return ConditionOutcome.match(message.foundExactly("supported DataSource"));
}
return ConditionOutcome.noMatch(message.didNotFind("supported DataSource").atAll());
}
}
/**
* {@link Condition} to detect when an embedded {@link DataSource} type can be used.
* If a pooled {@link DataSource} is available, it will always be preferred to an
* {@code EmbeddedDatabase}.
*/
static class EmbeddedDatabaseCondition extends SpringBootCondition {
private static final String DATASOURCE_URL_PROPERTY = "spring.datasource.url";
private final SpringBootCondition pooledCondition = new PooledDataSourceCondition();
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
ConditionMessage.Builder message = ConditionMessage.forCondition("EmbeddedDataSource");
if (hasDataSourceUrlProperty(context)) {
return ConditionOutcome.noMatch(message.because(DATASOURCE_URL_PROPERTY + " is set"));
}
if (anyMatches(context, metadata, this.pooledCondition)) {
return ConditionOutcome.noMatch(message.foundExactly("supported pooled data source"));
}
EmbeddedDatabaseType type = EmbeddedDatabaseConnection.get(context.getClassLoader()).getType();
if (type == null) {
return ConditionOutcome.noMatch(message.didNotFind("embedded database").atAll());
}
return ConditionOutcome.match(message.found("embedded database").items(type));
}
private boolean hasDataSourceUrlProperty(ConditionContext context) {
Environment environment = context.getEnvironment();
if (environment.containsProperty(DATASOURCE_URL_PROPERTY)) {
try {
return StringUtils.hasText(environment.getProperty(DATASOURCE_URL_PROPERTY));
}
catch (IllegalArgumentException ex) {
// Ignore unresolvable placeholder errors
}
}
return false;
}
}
}
- 修改数据源相关的配置:
spring.datasource
。
/**
* Base class for configuration of a data source.
*
* @author Dave Syer
* @author Maciej Walkowiak
* @author Stephane Nicoll
* @author Benedikt Ritter
* @author Eddú Meléndez
* @author Scott Frederick
* @since 1.1.0
*/
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
...
- 数据库连接池的配置,是自己容器中没有DataSource才自动配置的。
public class DataSourceAutoConfiguration {
...
@Configuration(proxyBeanMethods = false)
@Conditional(PooledDataSourceCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class,
DataSourceJmxConfiguration.class })
protected static class PooledDataSourceConfiguration {
}
- 底层配置好的连接池是:
HikariDataSource
。
/**
* Actual DataSource configurations imported by {@link DataSourceAutoConfiguration}.
*
* @author Dave Syer
* @author Phillip Webb
* @author Stephane Nicoll
*/
abstract class DataSourceConfiguration {
@SuppressWarnings("unchecked")
protected static <T> T createDataSource(DataSourceProperties properties, Class<? extends DataSource> type) {
return (T) properties.initializeDataSourceBuilder().type(type).build();
}
/**
* Tomcat Pool DataSource configuration.
*/
@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 {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.tomcat")
org.apache.tomcat.jdbc.pool.DataSource dataSource(DataSourceProperties properties) {
org.apache.tomcat.jdbc.pool.DataSource dataSource = 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;
}
}
/**
* Hikari DataSource configuration.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(HikariDataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource",
matchIfMissing = true)
static class Hikari {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.hikari")
HikariDataSource dataSource(DataSourceProperties properties) {
HikariDataSource dataSource = createDataSource(properties, HikariDataSource.class);
if (StringUtils.hasText(properties.getName())) {
dataSource.setPoolName(properties.getName());
}
return dataSource;
}
}
/**
* DBCP DataSource configuration.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(org.apache.commons.dbcp2.BasicDataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.commons.dbcp2.BasicDataSource",
matchIfMissing = true)
static class Dbcp2 {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.dbcp2")
org.apache.commons.dbcp2.BasicDataSource dataSource(DataSourceProperties properties) {
return createDataSource(properties, org.apache.commons.dbcp2.BasicDataSource.class);
}
}
/**
* Generic DataSource configuration.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class Generic {
@Bean
DataSource dataSource(DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().build();
}
}
}
DataSourceTransactionManagerAutoConfiguration
: 事务管理器的自动配置。
/**
* {@link EnableAutoConfiguration Auto-configuration} for
* {@link DataSourceTransactionManager}.
*
* @author Dave Syer
* @author Stephane Nicoll
* @author Andy Wilkinson
* @author Kazuki Shimizu
* @since 1.0.0
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ JdbcTemplate.class, PlatformTransactionManager.class })
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceTransactionManagerAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnSingleCandidate(DataSource.class)
static class DataSourceTransactionManagerConfiguration {
@Bean
@ConditionalOnMissingBean(PlatformTransactionManager.class)
DataSourceTransactionManager transactionManager(DataSource dataSource,
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
return transactionManager;
}
}
}
JdbcTemplateAutoConfiguration
:JdbcTemplate
的自动配置,可以来对数据库进行CRUD。
/**
* {@link EnableAutoConfiguration Auto-configuration} for {@link JdbcTemplate} and
* {@link NamedParameterJdbcTemplate}.
*
* @author Dave Syer
* @author Phillip Webb
* @author Stephane Nicoll
* @author Kazuki Shimizu
* @since 1.4.0
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, JdbcTemplate.class })
@ConditionalOnSingleCandidate(DataSource.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(JdbcProperties.class)
@Import({ JdbcTemplateConfiguration.class, NamedParameterJdbcTemplateConfiguration.class })
public class JdbcTemplateAutoConfiguration {
}
- 可以修改前缀为
spring.jdbc
的配置项来修改JdbcTemplate
。
/**
* Configuration properties for JDBC.
*
* @author Kazuki Shimizu
* @author Stephane Nicoll
* @since 2.0.0
*/
@ConfigurationProperties(prefix = "spring.jdbc")
public class JdbcProperties {
...
@Bean @Primary JdbcTemplate
:Spring容器中有这个JdbcTemplate
组件,使用@Autowired
。JndiDataSourceAutoConfiguration
: JNDI的自动配置。
/**
* {@link EnableAutoConfiguration Auto-configuration} for a JNDI located
* {@link DataSource}.
*
* @author Phillip Webb
* @author Andy Wilkinson
* @since 1.2.0
*/
@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore({ XADataSourceAutoConfiguration.class, DataSourceAutoConfiguration.class })
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnProperty(prefix = "spring.datasource", name = "jndi-name")
@EnableConfigurationProperties(DataSourceProperties.class)
public class JndiDataSourceAutoConfiguration {
@Bean(destroyMethod = "")
@ConditionalOnMissingBean
public DataSource dataSource(DataSourceProperties properties, ApplicationContext context) {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
DataSource dataSource = dataSourceLookup.getDataSource(properties.getJndiName());
excludeMBeanIfNecessary(dataSource, "dataSource", context);
return dataSource;
}
private void excludeMBeanIfNecessary(Object candidate, String beanName, ApplicationContext context) {
for (MBeanExporter mbeanExporter : context.getBeansOfType(MBeanExporter.class).values()) {
if (JmxUtils.isMBean(candidate.getClass())) {
mbeanExporter.addExcludedBean(beanName);
}
}
}
}
XADataSourceAutoConfiguration
: 分布式事务相关的。
/**
* {@link EnableAutoConfiguration Auto-configuration} for {@link DataSource} with XA.
*
* @author Phillip Webb
* @author Josh Long
* @author Madhura Bhave
* @since 1.2.0
*/
@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(DataSourceProperties.class)
@ConditionalOnClass({ DataSource.class, TransactionManager.class, EmbeddedDatabaseType.class })
@ConditionalOnBean(XADataSourceWrapper.class)
@ConditionalOnMissingBean(DataSource.class)
public class XADataSourceAutoConfiguration implements BeanClassLoaderAware {
...
修改配置项
spring:
datasource:
url: jdbc:mysql://localhost:3306/db_account?serverTimezone=UTC
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
# type: com.zaxxer.hikari.HikariDatasource
单元测试数据源
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;
@SpringBootTest
class Boot05WebAdminApplicationTests {
@Autowired
JdbcTemplate jdbcTemplate;
@Test//用@org.junit.Test会报空指针异常,可能跟JUnit新版本有关
void contextLoads() {
// jdbcTemplate.queryForObject("select * from account_tbl")
// jdbcTemplate.queryForList("select * from account_tbl",)
Long aLong = jdbcTemplate.queryForObject("select count(*) from account_tbl", Long.class);
log.info("记录总数:{}",aLong);
}
}