Ktor Exposed报错No transaction in context:返回Query失败转List正常
为什么返回Exposed的Query类型会报"No transaction in context"错误?
我用PostgreSQL、Exposed与Hikari CP搭建Ktor服务器,按官方文档开发时遇到问题:getAllUsers方法返回Query类型时执行报错java.lang.IllegalStateException: No transaction in context;但改为返回List<User>类型时可正常运行。
错误代码
override suspend fun getAllUsers(): Query = dbQuery { UserDao.selectAll() }
正常代码
override suspend fun getAllUsers(): List<User> = dbQuery { UserDao.selectAll().map { it.asUser() } }
问题原因
核心在于Exposed的Query延迟执行特性和dbQuery的事务生命周期限制:
UserDao.selectAll()并没有立即执行SQL查询,只是生成了查询逻辑的描述对象,真正的数据库交互要等到遍历Query(比如调用map、toList)时才触发。dbQuery会在其lambda代码块内维护一个数据库事务,当lambda执行完毕(也就是getAllUsers返回Query对象时),事务会自动提交/回滚,对应的事务上下文也会被销毁。- 返回
List<User>时,map { it.asUser() }会立刻触发SQL查询,整个结果转换过程都在dbQuery的事务上下文内完成,所以不会报错;但返回Query后,后续在事务外部遍历Query时,已经没有可用的事务上下文,就会抛出异常。
解决方案
如果确实需要返回Query对象,必须确保后续执行Query的代码也处于事务上下文之内:
- 把调用
getAllUsers后的遍历逻辑也包裹在dbQuery块中; - 或者在
getAllUsers的dbQuery块内提前触发Query执行(比如调用query.toList()),但这种方式本质上和直接返回List没有区别。
内容的提问来源于stack exchange,提问作者Yehezkiel L
相关产品推荐
相关产品推荐

