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

 2019-10-17 21:33  阅读(1540)
文章分类:Spring boot

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的账号和密码


来源:[]()

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> spring-boot中初始化sql讲解及分析

相关推荐