spring-boot中初始化sql讲解及分析

spring-boot版本1中初始化sql语句

application.properties配置:

spring.datasource.initialize=true spring.datasource.schema=classpath:schema-mysql.sql spring.datasource.data=classpath:data-mysql.sql

再在resource目录下添加schema-mysql.sql和data-mysql.sql的文件,schema中主要用于创建表的语句,data中主要存放插入数据及更新操作

现在开始源码分析:

这个方法在DataSourceInitializer

private void runSchemaScripts() {
 //获取schema位置并转化为Resource对象
   List<Resource> scripts = getScripts(this.properties.getSchema(), "schema");
   if (!scripts.isEmpty()) {
    //这里执行获取的schema
      runScripts(scripts);
      try {
         this.applicationContext
               .publishEvent(new DataSourceInitializedEvent(this.dataSource));
         if (!this.initialized) {
          //这里执行data.sql文件
            runDataScripts();
            this.initialized = true;
         }
      }
      catch (IllegalStateException ex) {
        
      }
   }
}

从这里可以看出它是先进运行schema中语句再运行data中的内容

private void runScripts(List<Resource> resources) {
   if (resources.isEmpty()) {
      return;
   }
  //下面主要是把schema中的resource对象封装为popluator对象
   ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
   populator.setContinueOnError(this.properties.isContinueOnError());
   populator.setSeparator(this.properties.getSeparator());
   if (this.properties.getSqlScriptEncoding() != null) {
      populator.setSqlScriptEncoding(this.properties.getSqlScriptEncoding().name());
   }
   for (Resource resource : resources) {
      populator.addScript(resource);
   }
  //执行sql语句方法
   DatabasePopulatorUtils.execute(populator, this.dataSource);
}

public static void execute(DatabasePopulator populator, DataSource dataSource) throws DataAccessException {
    try {
        //获取数据库连接
        Connection connection = DataSourceUtils.getConnection(dataSource);
        try {
           //执行创建表语句也就是schema中的sql语句
            populator.populate(connection);
        } finally {
            if (connection != null) {
                DataSourceUtils.releaseConnection(connection, dataSource);
            }
        }
    } catch (Exception var7) {
   }
}

public void populate(Connection connection) throws ScriptException {
   //从这里可以看出schema文件可以为多个
    Iterator var2 = this.getScripts().iterator();
    while(var2.hasNext()) {
        Resource script = (Resource)var2.next();
        ScriptUtils.executeSqlScript(connection, this.encodeScript(script), this.continueOnError, this.ignoreFailedDrops, this.commentPrefix, this.separator, this.blockCommentStartDelimiter, this.blockCommentEndDelimiter);
    }

}

public static void executeSqlScript(Connection connection, EncodedResource resource, boolean continueOnError, boolean ignoreFailedDrops, String commentPrefix, String separator, String blockCommentStartDelimiter, String blockCommentEndDelimiter) throws ScriptException {
    try {
        long startTime = System.currentTimeMillis();
        String script;
        try {
          //这里获取schema中的内容
            script = readScript(resource, commentPrefix, separator);
        } catch (IOException var27) {
            throw new CannotReadScriptException(resource, var27);
        }
        //这里获取每句的分割符号
        if (separator == null) {
            separator = ";";
        }

        if (!"^^^ END OF SCRIPT ^^^".equals(separator) && !containsSqlScriptDelimiters(script, separator)) {
            separator = "\n";
        }

         //这里是执行切割操作把schema中内容切割成单独的sql语句
        List<String> statements = new LinkedList();
        splitSqlScript(resource, script, separator, commentPrefix, blockCommentStartDelimiter, blockCommentEndDelimiter, statements);
        int stmtNumber = 0;
        Statement stmt = connection.createStatement();

        try {
            Iterator var14 = statements.iterator();

            while(var14.hasNext()) {
                String statement = (String)var14.next();
                ++stmtNumber;

                try {
                    //遍历执行每条sql语句(schema中的)
                    stmt.execute(statement);
                    int rowsAffected = stmt.getUpdateCount();
                    if (logger.isDebugEnabled()) {
                        logger.debug(rowsAffected + " returned as updateCount for SQL: " + statement);
                    }
                } catch (SQLException var28) {
                    boolean dropStatement = StringUtils.startsWithIgnoreCase(statement.trim(), "drop");
                    if (!continueOnError && (!dropStatement || !ignoreFailedDrops)) {
                        throw new ScriptStatementFailedException(statement, stmtNumber, resource, var28);
                    }
                }
            }
        } finally {
            try {
                stmt.close();
            } catch (Throwable var26) {
                logger.debug("Could not close JDBC Statement", var26);
            }

        }

        long elapsedTime = System.currentTimeMillis() - startTime;
   

    } catch (Exception var30) {
      
    }
}

看到这里就已经知道schema的只需流程,data执行也类型;

补充:我们可以看下它是如何获取schema路径

private List<Resource> getScripts(String locations, String fallback) {
   if (locations == null) {
      String platform = this.properties.getPlatform();
      locations = "classpath*:" + fallback + "-" + platform + ".sql,";
      locations += "classpath*:" + fallback + ".sql";
   }
   return getResources(locations);
}

这里可以看出如果你配置spring.datasource.schema也就是locations的位置它会直接用你配置东西,如果没有配置它会加载俩个东西一个是看你是否配置spring.datasource.platform如果没配置默认为all和直接使用schema.sql所有如果你的名称为schema.sql不需要指定位置。如果你的为schema-test.sql你也可以只需制定spring.datasource.platform=test

spring-boot版本2如何加载sql

application.properties:

spring.datasource.schema=classpath:schema.sql spring.datasource.data=classpath:data.sql spring.datasource.initialization-mode=alawys
源码分析

public void afterPropertiesSet() {
   DataSourceInitializer initializer = getDataSourceInitializer();
   if (initializer != null) {
      //下面这句是进行schema中的初始化
      boolean schemaCreated = this.dataSourceInitializer.createSchema();
      if (schemaCreated) {
        //下面这句是进行data中的初始化
         initialize(initializer);
      }
   }
}

/**
 * Create the schema if necessary.
 * @return {@code true} if the schema was created
 * @see DataSourceProperties#getSchema()
 */
public boolean createSchema() {
   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);
   }
   return !scripts.isEmpty();
}
private void runScripts(List<Resource> resources, String username, String password) {
   if (resources.isEmpty()) {
      return;
   }
   ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
   populator.setContinueOnError(this.properties.isContinueOnError());
   populator.setSeparator(this.properties.getSeparator());
   if (this.properties.getSqlScriptEncoding() != null) {
      populator.setSqlScriptEncoding(this.properties.getSqlScriptEncoding().name());
   }
   for (Resource resource : resources) {
      populator.addScript(resource);
   }
   DataSource dataSource = this.dataSource;
   //这里可以看出如果单独配置schema执行的用户名和密码就会产生一个新的datasource
   if (StringUtils.hasText(username) && StringUtils.hasText(password)) {
      dataSource = DataSourceBuilder.create(this.properties.getClassLoader())
            .driverClassName(this.properties.determineDriverClassName())
            .url(this.properties.determineUrl()).username(username)
            .password(password).build();
   }
   DatabasePopulatorUtils.execute(populator, dataSource);
}

其他的就会版本1差不多了,到这来我们可以知道那个spring-boot版本2可以单独指定初始化schema和data的账号和密码

    原文作者:Spring Boot
    原文地址: https://blog.csdn.net/yinbucheng/article/details/80164395
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞