如何通过Spring Boot Web应用动态创建MySQL数据库与表(含SQL文件场景)
Hey there! Let's walk through how to handle both of your requirements in a Spring Boot web app—dynamically creating MySQL databases/tables, and running a pre-written SQL file to set up schema only when it doesn't exist.
一、动态创建MySQL数据库和表
1. 配置初始数据源(连接MySQL服务器)
首先,你需要一个能连接到MySQL服务器本身的数据源(而不是目标业务库,因为目标库还没创建)。在application.properties里添加:
# 初始数据源:连接MySQL默认的mysql库 spring.datasource.url=jdbc:mysql://localhost:3306/mysql?useSSL=false&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=your-password spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
2. 编写初始化逻辑(应用启动时执行)
用ApplicationRunner来在应用启动后自动执行初始化逻辑,步骤是:
- 检查目标数据库是否存在,不存在则创建
- 切换到目标数据库,检查目标表是否存在,不存在则创建
示例代码:
import org.springframework.boot.ApplicationRunner; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; @Component public class DatabaseInitializer { private final JdbcTemplate jdbcTemplate; // 注入默认数据源的JdbcTemplate public DatabaseInitializer(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @Bean public ApplicationRunner databaseInitRunner() { return args -> { String targetDbName = "your_target_db"; String createDbSql = "CREATE DATABASE IF NOT EXISTS " + targetDbName; // 创建数据库(如果不存在) jdbcTemplate.execute(createDbSql); // 切换到目标数据库 jdbcTemplate.execute("USE " + targetDbName); // 检查表是否存在,不存在则创建 String checkTableSql = "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = ? AND table_name = ?"; Integer tableCount = jdbcTemplate.queryForObject( checkTableSql, Integer.class, targetDbName, "your_target_table" ); if (tableCount == 0) { String createTableSql = """ CREATE TABLE your_target_table ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) """; jdbcTemplate.execute(createTableSql); System.out.println("Table created successfully!"); } else { System.out.println("Table already exists."); } }; } }
注意:确保你的MySQL用户拥有
CREATE DATABASE和CREATE TABLE的权限。
二、使用SQL文件(如sql_table.sql)条件初始化库表
如果已经有写好的SQL文件,你可以读取文件内容,结合IF NOT EXISTS条件来执行,确保只在库表不存在时创建。
1. 准备SQL文件
在src/main/resources下创建sql_table.sql,里面的语句要包含IF NOT EXISTS:
-- 创建数据库(如果不存在) CREATE DATABASE IF NOT EXISTS your_target_db; -- 切换到目标库 USE your_target_db; -- 创建表(如果不存在) CREATE TABLE IF NOT EXISTS your_target_table ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
2. 读取并执行SQL文件
同样用ApplicationRunner来读取文件并执行,示例代码:
import org.springframework.boot.ApplicationRunner; import org.springframework.context.annotation.Bean; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import org.springframework.util.FileCopyUtils; import java.nio.charset.StandardCharsets; @Component public class SqlFileInitializer { private final JdbcTemplate jdbcTemplate; private final ResourceLoader resourceLoader; public SqlFileInitializer(JdbcTemplate jdbcTemplate, ResourceLoader resourceLoader) { this.jdbcTemplate = jdbcTemplate; this.resourceLoader = resourceLoader; } @Bean public ApplicationRunner sqlFileInitRunner() { return args -> { // 加载SQL文件 Resource resource = resourceLoader.getResource("classpath:sql_table.sql"); String sqlContent = new String(FileCopyUtils.copyToByteArray(resource.getInputStream()), StandardCharsets.UTF_8); // 分割SQL语句(注意:如果SQL里有分号,这个简单分割可能不够,复杂场景建议用SQL解析库) String[] sqlStatements = sqlContent.split(";"); // 逐个执行语句 for (String sql : sqlStatements) { String trimmedSql = sql.trim(); if (!trimmedSql.isEmpty()) { jdbcTemplate.execute(trimmedSql); } } System.out.println("SQL file executed successfully!"); }; } }
小提示
- 如果你的SQL文件包含复杂语句(比如带分号的字符串),建议使用专门的SQL解析库(如
org.antlr:antlr4-runtime)来正确分割语句,避免错误。 - 也可以使用Spring Boot的
DataSourceInitializer,但它默认会在每次启动时执行SQL文件,如果你想只执行一次,可以结合上面的库表存在判断逻辑来控制。
Hope these solutions fit your needs! If you hit any snags with configuration or edge cases, feel free to follow up with more details.
内容的提问来源于stack exchange,提问作者masiboo

