Method for Spring to Execute sql Script File

  • 2021-07-01 07:30:49
  • OfStack

This article solves the problem that Spring executes SQL scripts (files).

Scene description can be ignored.

Scene description:

When I run the single test, that is, when the Spring project starts, Spring will execute classpath: schema. sql (explained later). I want to use this one point to solve a problem:

Run multiple test files at a time, and each file runs independently. The data created by the previous file will affect the runtime of the next file, so I want to reset the database after the execution of each file, not just delete the data, but there are drop table and create table in schema. sql.

Solution:


//Schema  Processor 
@Component
public class SchemaHandler {
  private final String SCHEMA_SQL = "classpath:schema.sql";
  @Autowired
  private DataSource datasource;
  @Autowired
  private SpringContextGetter springContextGetter;

  public void execute() throws Exception {
    Resource resource = springContextGetter.getApplicationContext().getResource(SCHEMA_SQL);
    ScriptUtils.executeSqlScript(datasource.getConnection(), resource);
  }
}

//  Get  ApplicationContext
@Component
public class SpringContextGetter implements ApplicationContextAware {

  private ApplicationContext applicationContext;

  public ApplicationContext getApplicationContext() {
    return applicationContext;
  }

  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.applicationContext = applicationContext;
  }
}

Remarks:

For why Spring executes classpath: schema. sql, please refer to the source code

org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer#runSchemaScripts


private void runSchemaScripts() {
    List<Resource> scripts = getScripts("spring.datasource.schema",
        this.properties.getSchema(), "schema");
    if (!scripts.isEmpty()) {
      String username = this.properties.getSchemaUsername();
      String password = this.properties.getSchemaPassword();
      runScripts(scripts, username, password);
      try {
        this.applicationContext
            .publishEvent(new DataSourceInitializedEvent(this.dataSource));
        // The listener might not be registered yet, so don't rely on it.
        if (!this.initialized) {
          runDataScripts();
          this.initialized = true;
        }
      }
      catch (IllegalStateException ex) {
        logger.warn("Could not send event to complete DataSource initialization ("
            + ex.getMessage() + ")");
      }
    }
  }

/**
 *  Take by default  classpath*:schema-all.sql  And  classpath*:schema.sql
 */
private List<Resource> getScripts(String propertyName, List<String> resources,
      String fallback) {
    if (resources != null) {
      return getResources(propertyName, resources, true);
    }
    String platform = this.properties.getPlatform();
    List<String> fallbackResources = new ArrayList<String>();
    fallbackResources.add("classpath*:" + fallback + "-" + platform + ".sql");
    fallbackResources.add("classpath*:" + fallback + ".sql");
    return getResources(propertyName, fallbackResources, false);
  }

Reference: https://github.com/spring-projects/spring-boot/issues/9048


Related articles: