如何将Anorm结果转换为Iterator?或获取底层JDBC ResultSet?
将Anorm结果转换为Iterator(含自定义类型迭代器)
别担心,你的需求完全可以实现!不管是要Iterator[Row]还是Iterator[MyTypeAfterDeser],都有可行的方案,甚至能复用你现有的RowParser代码。
1. 直接生成Iterator[Row]
Anorm提供了withResult方法,能直接拿到原生JDBC的ResultSet,我们可以基于它封装成Iterator[Row]:
import anorm._ import java.sql.ResultSet // 定义你的SQL查询 val query = SQL("SELECT id, name FROM your_table") // 生成Row迭代器 val rowIterator: Iterator[Row] = query.withResult { rsOpt => rsOpt.map { rs => new Iterator[Row] { // 每次调用hasNext时移动ResultSet游标 override def hasNext: Boolean = rs.next() // 将当前ResultSet行转换为Anorm的Row对象 override def next(): Row = Row(rs, query.resultSetOnFirstRow) } }.getOrElse(Iterator.empty) // 处理ResultSet为空的情况 }
这里要注意:ResultSet是有状态的,迭代器的next()会不断移动游标,所以不要在迭代过程中手动操作原ResultSet,同时要确保JDBC连接在迭代器遍历完成前保持打开状态。
2. 转换为Iterator[MyTypeAfterDeser](复用RowParser)
如果已经有现成的RowParser,可以在上面的Iterator[Row]基础上直接映射解析,生成自定义类型的迭代器:
// 假设你的自定义类型和对应的RowParser case class User(id: Int, name: String) val userParser: RowParser[User] = SqlParser.int("id") ~ SqlParser.str("name") map { case id ~ name => User(id, name) } // 生成自定义类型的迭代器(包含解析错误的情况) val userIterator: Iterator[Either[SqlRequestError, User]] = rowIterator.map(row => userParser(row)) // 如果只需要成功解析的结果,可以过滤掉错误项 val validUsers: Iterator[User] = userIterator.collect { case Right(user) => user }
获取原生JDBC ResultSet并复用RowParser
如果更倾向于先拿到原生ResultSet再处理,同样可以用withResult方法,然后手动将ResultSet的行转换为Row,再用你的RowParser解析:
query.withResult { rsOpt => rsOpt.foreach { rs => while (rs.next()) { // 将当前ResultSet行转为Anorm Row val row = Row(rs, query.resultSetOnFirstRow) // 复用已有的RowParser解析 userParser(row) match { case Right(user) => // 处理成功解析的用户 case Left(error) => // 处理解析错误 } } } }
这种方式完全复用了你现有的解析逻辑,同时保留了对原生ResultSet的控制权,适合你需要基于迭代器实现自动关联的场景。
小提示:如果是在事务中使用,一定要保证迭代器遍历完成后再提交/回滚事务,否则
ResultSet会因为连接关闭而失效。
内容的提问来源于stack exchange,提问作者eugen
相关产品推荐
相关产品推荐

