java中可通过反射扫描@dbscript注解类/方法,在spring boot启动时(applicationrunner)按version→type→order排序执行sql,完成数据库初始化与升级,需确保datasource就绪后执行。

Java 中可以通过反射扫描带有自定义注解的类或方法,在 Spring Boot 应用启动阶段(如 @PostConstruct、ApplicationRunner 或 CommandLineRunner)自动执行 SQL 脚本,完成数据库初始化与版本升级。核心在于:注解标记脚本元信息 → 反射读取并排序 → JDBC 执行。
定义数据库版本控制注解
创建一个用于标记 SQL 脚本类或方法的注解,明确版本号、执行顺序和类型(init / upgrade):
-
@DbScript:保留策略为
RetentionPolicy.RUNTIME,可作用于类或方法 - 包含字段:
version()(如 "1.0.0")、type()(INIT / UPGRADE)、order()(整数,用于同版本内排序) - 示例:
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface DbScript { String version(); ScriptType type() default ScriptType.INIT; int order() default 0; } public enum ScriptType { INIT, UPGRADE }
编写带注解的 SQL 脚本载体
SQL 可以写在类的静态字段、方法返回值,或外部 SQL 文件路径中。推荐使用方法方式,便于复用与测试:
- 在
config或db/migration包下新建类,如V1_0_0_InitScript - 用
@DbScript(version = "1.0.0", type = INIT)标记该类或其某个方法 - 方法返回
List<string></string>,每条为一条可执行 SQL(支持 DDL/DML) - 示例:
@DbScript(version = "1.0.0", type = ScriptType.INIT) public class V1_0_0_InitScript { public List<string> getScripts() { return Arrays.asList( "CREATE TABLE user (id BIGINT PRIMARY KEY, name VARCHAR(50))", "INSERT INTO user VALUES (1, 'admin')" ); } } </string>
启动时扫描、解析并执行 SQL
利用 Spring 的 ApplicationRunner 在容器刷新后触发执行逻辑,结合反射读取所有 @DbScript 元素:
- 使用
ClassPathScanningCandidateComponentProvider扫描指定包下的带注解类 - 对每个匹配类,通过
Class.forName().getDeclaredMethods()或直接调用其方法获取 SQL 列表 - 按
version → type → order三级排序(INIT 总是优先于 UPGRADE;相同版本下 INIT 先于 UPGRADE;同类型按 order 升序) - 通过
JdbcTemplate或原生Connection批量执行,每条 SQL 独立 try-catch,记录失败日志但不中断整体流程 - 可选:维护一张
schema_version表,记录已执行的最高版本,避免重复执行
与 Spring Boot 生命周期安全集成
确保 SQL 执行发生在数据源就绪之后、业务 Bean 创建之前:
- 实现
ApplicationRunner,依赖注入JdbcTemplate和DataSource - 添加
@Order(Ordered.HIGHEST_PRECEDENCE + 10)控制执行顺序,略低于 DataSource 初始化但早于 Service 加载 - 若需事务控制(如多条 SQL 必须全成功),可用
TransactionTemplate包裹执行块 - 注意:不要在
@PostConstruct中执行——此时DataSource可能尚未注入完毕
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











