Flyway的Context/JavaMigrationExecutor是否线程安全?可多线程调用吗
Flyway Context使用与线程安全问题解答
示例代码
public class MyMigration extends BaseJavaMigration { private static ExecutorService executorService; @Override public void migrate(Context context) throws Exception { // some code executorService.execute(() -> process(context, listOfIds)); } private void process(Context context, List<Long> listOfIds) { context.getConnection() .prepareStatement(buildSql(listOfIds)) .executeUpdate(); } }
结论:你给出的用法是错误的,不能跨线程传递使用Context
具体原因
- 生命周期不匹配
Context和migrate()方法的主线程执行周期强绑定,migrate()方法执行完成后Flyway会立刻回收Context持有的数据库连接、释放相关资源。异步线程执行时大概率会拿到已关闭的连接,直接抛出SQLException。 - JDBC连接非线程安全
即便Context资源未被回收,getConnection()返回的JDBC连接本身就不支持多线程操作,JDBC规范明确要求Connection实例只能在单线程中使用,多线程共享会导致事务混乱、数据异常、资源泄漏等问题。
相关组件线程安全说明
Context:非线程安全,Flyway官方未声明其线程安全,内部持有大量单次迁移的临时状态,设计上仅支持单次迁移的单线程使用,禁止跨线程共享。JavaMigrationExecutor:本身是线程安全的,作为迁移调度器它需要支持多场景下的迁移调度,但它的线程安全不代表绑定的Context可以跨线程使用,二者无关联。
优化建议
Flyway的迁移默认按版本顺序串行执行,不建议在迁移中开启异步线程,很容易出现后续迁移依赖当前异步修改的数据、但异步未执行完成的依赖问题。如果需要优化批量操作性能,直接在主线程中分批执行SQL即可,不要额外开线程处理。
如果确实有特殊场景必须异步执行,不要复用Context里的连接,自行从数据源获取独立的新连接处理逻辑。
内容的提问来源于stack exchange,提问作者Ilia
相关产品推荐
相关产品推荐

