如何从Vert.x JDBCClient的SQLConnection获取底层java.sql.Connection?
在Vert.x中获取底层java.sql.Connection用于Liquibase
刚好我之前在Vert.x项目里集成Liquibase时也碰到过这个问题——Vert.x的SQLConnection是封装后的连接对象,没法直接给Liquibase用,必须拿到原生的java.sql.Connection才行。这里有两种靠谱的解决办法:
方案一:使用SQLConnection的unwrap方法(推荐)
Vert.x的SQLConnection接口其实提供了unwrap方法,这是JDBC标准的解包操作,可以直接获取底层的原生连接。这种方法通用性强,不需要耦合具体的连接池实现(比如C3P0)。
普通回调风格示例
JDBCClient jdbcClient = JDBCClient.createShared(vertx, config); jdbcClient.getConnection(res -> { if (res.succeeded()) { SQLConnection vertxConn = res.result(); // 调用unwrap获取底层JDBC连接 vertxConn.unwrap(java.sql.Connection.class, unwrapResult -> { if (unwrapResult.succeeded()) { java.sql.Connection jdbcConn = unwrapResult.result(); // 这里执行Liquibase操作 try { Database database = DatabaseFactory.getInstance() .findCorrectDatabaseImplementation(new JdbcConnection(jdbcConn)); Liquibase liquibase = new Liquibase( "db/changelog.xml", new ClassLoaderResourceAccessor(), database ); liquibase.update(new Contexts()); System.out.println("Liquibase更新完成"); } catch (LiquibaseException e) { e.printStackTrace(); } finally { // 务必关闭连接,避免泄漏 try { jdbcConn.close(); } catch (SQLException e) { e.printStackTrace(); } vertxConn.close(); } } else { System.err.println("解包底层连接失败:" + unwrapResult.cause().getMessage()); unwrapResult.cause().printStackTrace(); } }); } else { System.err.println("获取Vert.x连接失败:" + res.cause().getMessage()); res.cause().printStackTrace(); } });
RxJava风格示例
如果你用的是RxJava版本的Vert.x SQL客户端,代码可以更简洁:
JDBCClient jdbcClient = JDBCClient.createShared(vertx, config); jdbcClient.rxGetConnection() .flatMap(vertxConn -> vertxConn.rxUnwrap(java.sql.Connection.class) .doOnSuccess(jdbcConn -> { try { Database database = DatabaseFactory.getInstance() .findCorrectDatabaseImplementation(new JdbcConnection(jdbcConn)); Liquibase liquibase = new Liquibase( "db/changelog.xml", new ClassLoaderResourceAccessor(), database ); liquibase.update(new Contexts()); System.out.println("Liquibase更新完成"); } catch (LiquibaseException e) { throw new RuntimeException("Liquibase执行失败", e); } finally { // 关闭连接 try { jdbcConn.close(); vertxConn.close(); } catch (SQLException e) { e.printStackTrace(); } } }) ) .subscribe( () -> {}, error -> System.err.println("操作失败:" + error.getMessage()) );
方案二:直接从C3P0数据源获取连接(不推荐)
如果你确定Vert.x底层用的是C3P0连接池,也可以直接创建并持有ComboPooledDataSource实例,然后从数据源直接获取原生连接。不过这种方法耦合了C3P0的实现,一旦换了连接池就会失效,所以不推荐。
// 创建C3P0数据源并配置 ComboPooledDataSource cpds = new ComboPooledDataSource(); try { cpds.setDriverClass("com.mysql.cj.jdbc.Driver"); cpds.setJdbcUrl("jdbc:mysql://localhost:3306/test"); cpds.setUser("root"); cpds.setPassword("password"); } catch (PropertyVetoException e) { e.printStackTrace(); } // 创建Vert.x的JDBC客户端 JDBCClient jdbcClient = JDBCClient.create(cpds); // 直接从数据源获取原生连接用于Liquibase try { java.sql.Connection jdbcConn = cpds.getConnection(); // 执行Liquibase操作... jdbcConn.close(); } catch (SQLException e) { e.printStackTrace(); }
关键注意事项
- 连接关闭:无论是哪种方案,用完后一定要关闭原生的
java.sql.Connection和Vert.x的SQLConnection,避免连接池泄漏。 - 异常处理:Liquibase操作可能抛出多种异常,务必做好捕获和处理。
- 依赖检查:确保项目中已经引入了Liquibase的依赖,以及对应数据库的JDBC驱动。
内容的提问来源于stack exchange,提问作者Cristiano
相关产品推荐
相关产品推荐

