Spring Boot對 embbeded的H2資料庫的datasource自動配置預設如下。
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
以上預設值是由Spring Boot的org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
、org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
及org.springframework.boot.jdbc.EmbeddedDatabaseConnection
而來。
系統啟動時會透過DataSourceAutoConfiguration
進行自動配置,讀取DataSourceProperties
的配置資訊。
在Spring Boot的EmbeddedDatabaseConnection
中設定有H2資料庫預設的連線資訊,節錄原始碼(2.2.x
)如下:
EmbeddedDatabaseConnection
public enum EmbeddedDatabaseConnection {
/**
* No Connection.
*/
NONE(null, null, null),
/**
* H2 Database Connection.
*/
H2(EmbeddedDatabaseType.H2, "org.h2.Driver", "jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"),
/**
* Derby Database Connection.
*/
DERBY(EmbeddedDatabaseType.DERBY, "org.apache.derby.jdbc.EmbeddedDriver", "jdbc:derby:memory:%s;create=true"),
/**
* HSQL Database Connection.
*/
HSQL(EmbeddedDatabaseType.HSQL, "org.hsqldb.jdbcDriver", "jdbc:hsqldb:mem:%s");
...
/**
* Returns the URL for the connection using the specified {@code databaseName}.
* @param databaseName the name of the database
* @return the connection URL
*/
public String getUrl(String databaseName) {
Assert.hasText(databaseName, "DatabaseName must not be empty");
return (this.url != null) ? String.format(this.url, databaseName) : null;
}
}
而jdbc:h2:mem:%s
後面的%s
會透過格式化字串為資料庫名稱,預設為testdb
。
注意Spring Boot 2.3.0開始spring.datasource.generate-unique-name
預設為true
,因此H2資料庫名稱是亂數產生,不再為預設的testdb
,所以設定spring.datasource.url=jdbc:h2:mem:testdb
指定資料庫名稱為testdb
。
不設定資料庫名稱的話可在啟動時的log找到產生的亂術資料庫名稱,例如下面的ec6b9859-df9f-48ca-8dd4-2a4eb3b21bab
。
2020-12-31 14:25:04.360 INFO 10640 --- [ main] c.z.h.HikariDataSource : HikariPool-1 - Starting...
2020-12-31 14:25:04.588 INFO 10640 --- [ main] c.z.h.HikariDataSource : HikariPool-1 - Start completed.
2020-12-31 14:25:04.595 INFO 10640 --- [ main] o.s.b.a.h.H2ConsoleAutoConfiguration : H2 console available at '/h2-console'. Database available at 'jdbc:h2:mem:ec6b9859-df9f-48ca-8dd4-2a4eb3b21bab'
DataSourceProperties
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {
...
/**
* Name of the datasource. Default to "testdb" when using an embedded database.
*/
private String name;
...
/**
* Determine the driver to use based on this configuration and the environment.
* @return the driver to use
* @since 1.4.0
*/
public String determineDriverClassName() {
if (StringUtils.hasText(this.driverClassName)) {
Assert.state(driverClassIsLoadable(), () -> "Cannot load driver class: " + this.driverClassName);
return this.driverClassName;
}
String driverClassName = null;
if (StringUtils.hasText(this.url)) {
driverClassName = DatabaseDriver.fromJdbcUrl(this.url).getDriverClassName();
}
if (!StringUtils.hasText(driverClassName)) {
driverClassName = this.embeddedDatabaseConnection.getDriverClassName(); // 取得Driver Class名稱
}
if (!StringUtils.hasText(driverClassName)) {
throw new DataSourceBeanCreationException("Failed to determine a suitable driver class", this,
this.embeddedDatabaseConnection);
}
return driverClassName;
}
...
/**
* Determine the name to used based on this configuration.
* @return the database name to use or {@code null}
* @since 2.0.0
*/
public String determineDatabaseName() {
if (this.generateUniqueName) {
if (this.uniqueName == null) {
this.uniqueName = UUID.randomUUID().toString();
}
return this.uniqueName;
}
if (StringUtils.hasLength(this.name)) {
return this.name;
}
if (this.embeddedDatabaseConnection != EmbeddedDatabaseConnection.NONE) {
return "testdb"; // 預設embedded資料庫名稱
}
return null;
}
...
/**
* Determine the username to use based on this configuration and the environment.
* @return the username to use
* @since 1.4.0
*/
public String determineUsername() {
if (StringUtils.hasText(this.username)) {
return this.username;
}
if (EmbeddedDatabaseConnection.isEmbedded(determineDriverClassName())) {
return "sa"; // 預設使用者名稱
}
return null;
}
...
/**
* Determine the password to use based on this configuration and the environment.
* @return the password to use
* @since 1.4.0
*/
public String determinePassword() {
if (StringUtils.hasText(this.password)) {
return this.password;
}
if (EmbeddedDatabaseConnection.isEmbedded(determineDriverClassName())) {
return ""; // 預設密碼
}
return null;
}
...
}
沒有留言:
張貼留言