springboot情操陶冶-web配置(六)
本文則針對資料庫的連線配置作下簡單的分析,方便筆者理解以及後續的查閱
栗子當先
以我們經常用的mybatis資料庫持久框架來操作mysql服務為例
環境依賴
1.JDK v1.8+
2.springboot v2.0.3.RELEASE
3.mybatis v3.4.6
4.mysql v10.2.8-MarialDB
配置類步驟
1.pom.xml
<!--mybatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.40</version> </dependency>
2.springboot配置 application-datasource.properties
#datasource config spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://127.0.0.1:3306/boot?useSSL=false&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&serverTimeZone=GMT%2B8 spring.datasource.username=root spring.datasource.password=123456 #mybatis config mybatis.check-config-location=false mybatis.mapper-locations=classpath*:database/mybatis/mapper/*.xml mybatis.executor-type=reuse
程式碼栗子步驟
1.實體類User.java
package com.example.demo.database.entity; /** * @author nanco * ------------- * demo-springboot * ------------- * @create 2018/10/17 16:52 **/ public class User { private Long id ; private String name ; private Integer age ; private String email ; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", email='" + email + '\'' + '}'; } }
2.mapper配置檔案 UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.example.demo.database.mysql.dao.UserDao">
<insert id="saveUser" parameterType="com.example.demo.database.entity.User">
insert into tbl_user(name,age,email)
values(#{name},#{age},#{email})
</insert>
</mapper>
3.為了使上述配置生效,則須定義掃描入口(@MapperScan
)
package com.example.demo.database.config;
import com.mysql.jdbc.Driver;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
/**
* @author nanco
* -------------
* demo-springboot
* -------------
* @create 2018/10/17 17:09
**/
@Configuration
public class DatabaseConfig {
@Configuration
@ConditionalOnClass(Driver.class)
@MapperScan("com.example.demo.database.mysql.dao")
static class MysqlInterfaceScanner {
}
}
4.來一個測試類
package com.example.demo.database.mysql;
import com.example.demo.database.DatabaseApplication;
import com.example.demo.database.entity.User;
import com.example.demo.database.mysql.dao.UserDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.Assert;
import javax.annotation.Resource;
/**
* @author nanco
* -------------
* demo-springboot
* -------------
* @create 2018/10/17 17:13
**/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {DatabaseApplication.class})
public class MysqlDaoTest {
@Resource
private UserDao userDao;
@Test
public void testSave() {
User user = new User();
user.setName("nanco");
user.setAge(18);
user.setEmail("[email protected]");
System.out.println(userDao.saveUser(user));
}
}
執行上述的測試案例便完成了簡單的插入功能,其他的功能讀者可自行編寫
原始碼層
查閱了spring-boot-autoconfigure包下的spring.factories,發現對於資料來源的配置是通過DataSourceAutoConfiguration類來進行的,由此簡單的展開下
DataSourceAutoConfiguration
本類的註冊是有條件的,其類上的註解是
@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class,
DataSourceInitializationConfiguration.class })
其中DataSource類是JDK自帶的,EmbeddedDatabaseType類則是依賴spring-jdbc包,本例中引入mybatis則預設帶入了上述包。筆者按照@Configuration
的載入順序來對此類作下簡單的分析
1.靜態內部類註冊解析
資料來源檢測
@Configuration
@Conditional(EmbeddedDatabaseCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import(EmbeddedDataSourceConfiguration.class)
protected static class EmbeddedDatabaseConfiguration {
}
具體的程式碼讀者可翻閱相應的文件,這裡作下總結
使用者配置了spring.datasource.type屬性或者classpath下存在springboot預設支援的資料來源則該配置略過 1) com.zaxxer.hikari.HikariDataSource 2) org.apache.tomcat.jdbc.pool.DataSource 3) org.apache.commons.dbcp2.BasicDataSource
如果上述的條件不滿足則會在classpath下找尋springboot預設支援的資料庫驅動,存在則會建立SimpleDriverDataSource資料來源用來建立資料庫連線 1) H2 Database 2) Derby Database 3) HSQL Database
本例中引入mybatis-spring-boot-starter便會引入spring-jdbc包,則會採用HikariDataSource資料來源來獲取資料庫連線
資料來源建立
@Configuration
@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 {
}
根據使用者配置的spring.datasource.type屬性或者springboot預設支援的資料來源(見上)來進行資料來源物件的建立,具體的讀者可自行閱讀,本例中則會採取HikariDataSource資料來源,並注入至bean工廠中
2.匯入類解析
資料庫連線池狀態類初始化
@Configuration
public class DataSourcePoolMetadataProvidersConfiguration {
@Configuration
@ConditionalOnClass(HikariDataSource.class)
static class HikariPoolDataSourceMetadataProviderConfiguration {
@Bean
public DataSourcePoolMetadataProvider hikariPoolDataSourceMetadataProvider() {
return (dataSource) -> {
if (dataSource instanceof HikariDataSource) {
return new HikariDataSourcePoolMetadata(
(HikariDataSource) dataSource);
}
return null;
};
}
}
}
以HikariDataSource為例,則會建立HikariDataSourcePoolMetadata物件,主要是用來獲取連線池的相關資訊,看下DataSourcePoolMetadata介面就行,具體如下
public interface DataSourcePoolMetadata {
/**
* Return the usage of the pool as value between 0 and 1 (or -1 if the pool is not
* limited).
* <ul>
* <li>1 means that the maximum number of connections have been allocated</li>
* <li>0 means that no connection is currently active</li>
* <li>-1 means there is not limit to the number of connections that can be allocated
* </li>
* </ul>
* This may also return {@code null} if the data source does not provide the necessary
* information to compute the poll usage.
* @return the usage value or {@code null}
*/
Float getUsage();
/**
* Return the current number of active connections that have been allocated from the
* data source or {@code null} if that information is not available.
* @return the number of active connections or {@code null}
*/
Integer getActive();
/**
* Return the maximum number of active connections that can be allocated at the same
* time or {@code -1} if there is no limit. Can also return {@code null} if that
* information is not available.
* @return the maximum number of active connections or {@code null}
*/
Integer getMax();
/**
* Return the minimum number of idle connections in the pool or {@code null} if that
* information is not available.
* @return the minimum number of active connections or {@code null}
*/
Integer getMin();
/**
* Return the query to use to validate that a connection is valid or {@code null} if
* that information is not available.
* @return the validation query or {@code null}
*/
String getValidationQuery();
/**
* The default auto-commit state of connections created by this pool. If not set
* ({@code null}), default is JDBC driver default (If set to null then the
* java.sql.Connection.setAutoCommit(boolean) method will not be called.)
* @return the default auto-commit state or {@code null}
*/
Boolean getDefaultAutoCommit();
}
sql指令碼執行載入
@Configuration
@Import({ DataSourceInitializerInvoker.class,
DataSourceInitializationConfiguration.Registrar.class })
class DataSourceInitializationConfiguration {
}
主要通過DataSourceInitializerInvoker類來進行sql指令碼的執行載入,具體筆者就不貼程式碼了,作下簡單的總結
1) 如果spring.datasource.schema屬性已指定相應的sql檔案,則優先讀取,並支援classpath路徑查詢
2) 如果上述無配置,則預設讀取classpath*:schema.sql/classpath*:schema-${platform}.sql
檔案(其中${platform}可用spring.datasource.platform指定)
3) 如果沒有上述檔案,則不執行
溫馨提示:如果想在環境執行的時候執行相應的sql語句,則仍需要另外配置使用者名稱(spring.datasource.schema-username)與密碼(spring.datasource.schema-password),方可執行
小結
後續稍微講解下mybatis在springboot中的整合,算是對此篇章的延續,今天先以資料來源配置告一段落。不要問我為什麼,請移步到A股大盤你就會秒懂,心情稍稍有點小壓抑,待筆者釋放下情緒才能寫出好一點的文章~~~