版本
spring-boot-starter-parent ---- 2.2.6.RELEASE
druid ---- 1.1.10
mysql-connector-java ---- 8.0.19
问题

我在sql文件夹下放几个sql文件用于创建数据表
然后启动springboot
结果发现表并没有创建,并且控制台也没用报错

# application.yml配置
spring:
datasource:
# 数据源基本配置
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/mybatis?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
type: com.alibaba.druid.pool.DruidDataSource
# 数据源其他配置
schema:
- classpath:sql/department.sql
- classpath:sql/employee.sql
解决方案
在 application.yml中加入initialization-mode: always即可
spring:
datasource:
# 数据源基本配置
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/mybatis?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
type: com.alibaba.druid.pool.DruidDataSource
# 数据源其他配置
schema:
- classpath:sql/department.sql
- classpath:sql/employee.sql
# Initialize the datasource with available DDL and DML scripts.
initialization-mode: always
原因
(由于实力不够,看不懂源码,只能大概看看然后猜一下)
由于springboot在启动时会AutoConfiguration,因此对于jdbc,就需要进入对应的DataSourceAutoConfiguration
点开DataSourceAutoConfiguration 注解中import了两个类,其中一个是 DataSourceInitializationConfiguration 顾名思义 数据源初始化配置的类,点进去
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class, DataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {
...
}
同样 数据源初始化配置的类import了 DataSourceInitializerInvoker(数据源初始化程序调用程序),继续点进
@Configuration(proxyBeanMethods = false)
@Import({ DataSourceInitializerInvoker.class, DataSourceInitializationConfiguration.Registrar.class })
class DataSourceInitializationConfiguration {}
这个类中有一个字段,他的数据类型是 DataSourceInitializer ,继续点入
class DataSourceInitializerInvoker implements ApplicationListener<DataSourceSchemaCreatedEvent>, InitializingBean {
private DataSourceInitializer dataSourceInitializer;
}
在DataSourceInitializer 这个类中,我挑选了受影响的方法
class DataSourceInitializer {
boolean createSchema() {
List<Resource> scripts = getScripts("spring.datasource.schema", this.properties.getSchema(), "schema");
if (!scripts.isEmpty()) {
if (!isEnabled()) {
logger.debug("Initialization disabled (not running DDL scripts)");
return false;
}
String username = this.properties.getSchemaUsername();
String password = this.properties.getSchemaPassword();
runScripts(scripts, username, password);
}
return !scripts.isEmpty();
}
private boolean isEnabled() {
DataSourceInitializationMode mode = this.properties.getInitializationMode();
if (mode == DataSourceInitializationMode.NEVER) {
return false;
}
if (mode == DataSourceInitializationMode.EMBEDDED && !isEmbedded()) {
return false;
}
return true;
}
}
DataSourceInitializer
接下来看一下一下DataSourceInitializer 这个类内部
看createSchema()这个方法
boolean createSchema() {
List<Resource> scripts = getScripts("spring.datasource.schema", this.properties.getSchema(), "schema");
if (!scripts.isEmpty()) {
if (!isEnabled()) {
logger.debug("Initialization disabled (not running DDL scripts)");
return false;
}
String username = this.properties.getSchemaUsername();
String password = this.properties.getSchemaPassword();
runScripts(scripts, username, password);
}
return !scripts.isEmpty();
}
- 先说目标方法,要想创建数据的脚本成功执行,需要执行
runScripts()方法 - 这个方法中,首先执行
getScripts()方法,内部会调用getResources()获得一系列的脚本资源文件,如果获得成功,说明scripts变量不为空,进入if语句,否则函数返回 false - 当进入循环后,会去执行
isEnabled()方法,判断数据库的初始化模型,模型的数据一共有三个,分别是always, embedded,enver,只有当模型为always时,才会返回 false,如果返回true,取反,自然不会执行到runScripts()方法
private boolean isEnabled() {
DataSourceInitializationMode mode = this.properties.getInitializationMode();
if (mode == DataSourceInitializationMode.NEVER) {
return false;
}
if (mode == DataSourceInitializationMode.EMBEDDED && !isEmbedded()) {
return false;
}
return true;
}
public enum DataSourceInitializationMode {
/**
* Always initialize the datasource.
*/
ALWAYS,
/**
* Only initialize an embedded datasource.
*/
EMBEDDED,
/**
* Do not initialize the datasource.
*/
NEVER
}
我在这个方法上设置了断点,debug运行发现进入了最内层循环,原因是我一开始并没有指定数据库初始化模型,因此初始化模型默认为embedded,从而isEnabled()返回false,取反返回true,导致了目标方法没有执行到

而且debug信息中也说了,Initialization disabled (not running DDL scripts)禁用初始化(不运行DDL脚本)
因此,如果需要运行DDL脚本,需要配置spring.datasource.initialization-mode: always
spring:
datasource:
# 数据源基本配置
username: root
password: Root123!
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/mybatis?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
type: com.alibaba.druid.pool.DruidDataSource
# 数据源其他配置
schema:
- classpath:sql/department.sql
- classpath:sql/employee.sql
# Initialize the datasource with available DDL and DML scripts.
initialization-mode: always