Kotlin Exposed无connect/Transaction从DSL和DAO生成SQL与预编译SQL
解决方案
1. 无实际数据库连接生成SQL的实现方案
Exposed的连接校验仅要求存在初始化的Database实例和上下文绑定的Transaction对象,不会强制校验数据库连接的可用性,你可以通过伪造无操作的依赖实现需求,整个过程不会产生实际的数据库连接,资源消耗可忽略:
- 第一步:实现无操作的Dummy DataSource
仅需实现JDBC DataSource接口的最少必要方法,无需提供实际的连接能力:
object DummyDataSource : DataSource { override fun getConnection(): Connection = throw UnsupportedOperationException("仅用于SQL生成,不需要实际连接") override fun getConnection(username: String?, password: String?): Connection = throw UnsupportedOperationException("仅用于SQL生成,不需要实际连接") override fun getLogWriter(): PrintWriter? = null override fun setLogWriter(out: PrintWriter?) = Unit override fun setLoginTimeout(seconds: Int) = Unit override fun getLoginTimeout(): Int = 0 override fun getParentLogger(): Logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME) override fun <T : Any?> unwrap(iface: Class<T>?): T = throw UnsupportedOperationException() override fun isWrapperFor(iface: Class<*>?): Boolean = false }
- 第二步:初始化Exposed Database实例
调用Database.connect传入上述Dummy DataSource和你实际使用的数据库方言,该调用仅初始化内存元数据,不会发起任何网络请求或创建连接池:
// 根据实际使用的数据库替换方言,比如MySQLDialect、PostgreSQLDialect等 Database.connect(DummyDataSource, dialect = PostgreSQLDialect())
- 第三步:封装SQL生成工具方法
构造最小Transaction上下文,统一封装SQL生成逻辑,同时可直接提取对应的参数列表:
data class GeneratedSQL(val sql: String, val args: List<Any?>) fun <T : Statement<*>> T.generateSQL(): GeneratedSQL { return transaction(transactionIsolation = Connection.TRANSACTION_NONE) { val sql = this@generateSQL.prepareSQL(this) val args = this@generateSQL.arguments?.flatten() ?: emptyList() GeneratedSQL(sql, args) } }
使用时直接对任意Query、InsertStatement、DeleteStatement、UpdateStatement实例调用generateSQL()即可拿到符合方言规范的预编译SQL和对应参数,直接传入Vert.x SQL Client执行即可。
2. DAO API生成SQL的可行性
可以通过DAO API生成SQL。DAO层的所有CRUD操作本质都会生成对应的Statement子类实例,你只需要拿到操作对应的Statement对象,调用上述封装的generateSQL()方法即可获得对应SQL,和直接使用DSL的效果完全一致。
内容的提问来源于stack exchange,提问作者Shreck Ye
相关产品推荐
相关产品推荐

