Slick中如何将FixedSqlAction转换为StreamingDBIO
问题原因
Alpakka Slick 提供的 Slick.source() 方法仅接收支持流式返回的 StreamingDBIO 类型参数,而你使用的 TableQuery[Tables.Invoice].length.result 是聚合查询,Slick 对这类只会返回单条结果的查询,默认会生成不带流能力的 FixedSqlAction 类型,标记为 NoStream,因此类型不匹配编译失败。
解决方案
方案1:直接将查询结果转为Akka Stream Source(更推荐,适合单值返回场景)
你不需要强行使用 Slick.source() 来包裹单值聚合查询,直接用Slick会话执行查询,再把Future结果包装为Source即可:
def getTotal(implicit session: SlickSession) = { import session.profile.api._ val query = TableQuery[Tables.Invoice].length.result // 执行查询拿到Future[Int],转成发射单个元素的Source Source.fromFuture(session.db.run(query)) }
该方案得到的是 Source[Int, NotUsed],完全符合akka-stream的使用要求,和Slick.source()返回的流后续操作完全兼容,且底层走的是数据库原生聚合查询,性能最优。
方案2:将查询改造为流式查询(仅适合需同时处理明细+统计的场景)
如果你必须使用Slick.source()的API,可以将聚合查询改写为支持流式的明细查询,再在流中做聚合计算:
def getTotal(implicit session: SlickSession) = { import session.profile.api._ // 仅查询主键字段,减少不必要的数据传输,拿到流式查询结果 val streamingQuery = TableQuery[Tables.Invoice].map(_.id).result // 用Slick.source拿到流,再折叠统计总条数 Slick.source(streamingQuery).fold(0)((count, _) => count + 1) }
注意该方案需要拉取全表主键数据再做计算,性能远低于方案1,不推荐仅做计数时使用。
内容的提问来源于stack exchange,提问作者tonicebrian
相关产品推荐
相关产品推荐

