转载

springboot项目初始化执行sql

使用方式

application.yml
# 数据源配置
spring:
  sql:
    init:
      # mode: always - Spring Boot应用启动时始终执行数据库初始化
      # mode: embedded - 只初始化内存数据库,比如H2数据库
      # mode: never:  - 从不执行初始化数据库
      mode: always
      # 数据库平台内容配置项,主要有mysql、postgresql、oracle等
      platform: mysql
      # 创建表sql脚本的位置
      schema-locations:
        - classpath:/db/schema.sql
      # sql数据的位置
      #data-locations:
       # - classpath:/db/data.sql
schema.sql
create table if not exists app_excel_record
(
 id bigint unsigned auto_increment comment 'ID'
 primary key,
 file_name varchar(64) default '' not null comment '文件名称',
 module varchar(64) default '' not null comment '模块',
 create_time datetime null comment '创建时间',
 update_time datetime null comment '更新时间',
 create_by int null comment '创建人',
 file_url varchar(200) null comment '文件绝对路径',
 record_status int null comment '导出状态',
 result_info int null comment '导出结果'
) comment '导出记录表';
效果:系统启动会执行app_excel_record的创表语句。 源码解析
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@ConditionalOnMissingBean(type = "io.r2dbc.spi.ConnectionFactory")
@AutoConfigureBefore(SqlInitializationAutoConfiguration.class)
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class,
 DataSourceInitializationConfiguration.InitializationSpecificCredentialsDataSourceInitializationConfiguration.class,
 DataSourceInitializationConfiguration.SharedCredentialsDataSourceInitializationConfiguration.class })
public class DataSourceAutoConfiguration {
 
}
SqlInitializationAutoConfiguration SqlInitializationAutoConfiguration该类注入会判断SqlInitializationModeCondition条件是否符合,当spring.sql.init.mode不等于never,会注入到Spring容器中。
@Configuration(proxyBeanMethods = false)
@AutoConfigureAfter({ R2dbcAutoConfiguration.class, DataSourceAutoConfiguration.class })
@EnableConfigurationProperties(SqlInitializationProperties.class)
@Import({ DatabaseInitializationDependencyConfigurer.class, R2dbcInitializationConfiguration.class,
 DataSourceInitializationConfiguration.class })
@ConditionalOnProperty(prefix = "spring.sql.init", name = "enabled", matchIfMissing = true)
@Conditional(SqlInitializationModeCondition.class)
public class SqlInitializationAutoConfiguration {

 static class SqlInitializationModeCondition extends NoneNestedConditions {

 SqlInitializationModeCondition() {
 super(ConfigurationPhase.PARSE_CONFIGURATION);
 }

 @ConditionalOnProperty(prefix = "spring.sql.init", name = "mode", havingValue = "never")
 static class ModeIsNever {

 }

 }

}
DataSourceInitializationConfiguration DataSourceInitializationConfiguration注入了SqlDataSourceScriptDatabaseInitializer
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean({ SqlDataSourceScriptDatabaseInitializer.class, SqlR2dbcScriptDatabaseInitializer.class })
@ConditionalOnSingleCandidate(DataSource.class)
@ConditionalOnClass(DatabasePopulator.class)
class DataSourceInitializationConfiguration {

 @Bean
 SqlDataSourceScriptDatabaseInitializer dataSourceScriptDatabaseInitializer(DataSource dataSource,
 SqlInitializationProperties properties) {
 return new SqlDataSourceScriptDatabaseInitializer(
 determineDataSource(dataSource, properties.getUsername(), properties.getPassword()), properties);
 }

 private static DataSource determineDataSource(DataSource dataSource, String username, String password) {
 if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
 return DataSourceBuilder.derivedFrom(dataSource).username(username).password(password)
 .type(SimpleDriverDataSource.class).build();
 }
 return dataSource;
 }

}
SqlDataSourceScriptDatabaseInitializer SqlDataSourceScriptDatabaseInitializer继承了AbstractScriptDatabaseInitializer,AbstractScriptDatabaseInitializer是实现了InitializingBean接口的。所以在启动的时候会执行AbstractScriptDatabaseInitializer#afterPropertiesSet。
 public void afterPropertiesSet() throws Exception {
 this.initializeDatabase();
 }

 public boolean initializeDatabase() {
 AbstractScriptDatabaseInitializer.ScriptLocationResolver locationResolver = new AbstractScriptDatabaseInitializer.ScriptLocationResolver(this.resourceLoader);
 boolean initialized = this.applySchemaScripts(locationResolver);
 return this.applyDataScripts(locationResolver) || initialized;
 }
AbstractScriptDatabaseInitializer#applySchemaScripts。
 private boolean applySchemaScripts(AbstractScriptDatabaseInitializer.ScriptLocationResolver locationResolver) {
 return this.applyScripts(this.settings.getSchemaLocations(), "schema", locationResolver);
 }

 private boolean applyDataScripts(AbstractScriptDatabaseInitializer.ScriptLocationResolver locationResolver) {
 return this.applyScripts(this.settings.getDataLocations(), "data", locationResolver);
 }

 private boolean applyScripts(List<String> locations, String type, AbstractScriptDatabaseInitializer.ScriptLocationResolver locationResolver) {
 List<Resource> scripts = this.getScripts(locations, type, locationResolver);
 if (!scripts.isEmpty() && this.isEnabled()) {
 this.runScripts(scripts);
 return true;
 } else {
 return false;
 }
 }

 private void runScripts(List<Resource> resources) {
 this.runScripts(resources, this.settings.isContinueOnError(), this.settings.getSeparator(), this.settings.getEncoding());
 }

 protected abstract void runScripts(List<Resource> resources, boolean continueOnError, String separator, Charset encoding);

DataSourceScriptDatabaseInitializer#runScripts,执行脚本
 protected void runScripts(List<Resource> resources, boolean continueOnError, String separator, Charset encoding) {
 ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
 populator.setContinueOnError(continueOnError);
 populator.setSeparator(separator);
 if (encoding != null) {
 populator.setSqlScriptEncoding(encoding.name());
 }

 Iterator var6 = resources.iterator();

 while(var6.hasNext()) {
 Resource resource = (Resource)var6.next();
 populator.addScript(resource);
 }

 this.customize(populator);
 DatabasePopulatorUtils.execute(populator, this.dataSource);
 }

实战

https://gitee.com/charles_ruan/easy-export
正文到此结束
Loading...