遇到了这么一个问题,搜半天没有一个能解决的。因为这问题实在太见鬼,所以才记录一下。
如果急的可以直接到文章末尾看解决方法,但我不保证一定能解决你的问题。
经过
第一阶段
在使用ktorm的时候,为了方便自定义我想取出的数据,就想着用原生sql了,然后写了这么一段:
conn.prepareStatement(sql).executeQuery().let { rs ->
while(rs.next()){
//do sth
}
val count = rs.asIterable().count()
}
这里本来是想统计一下一共查询到多少数据来显示提示的,结果我惊奇的发现:完全没报错,但数据一个都没有,而count也是0。
很显然,没取到数据,铁定是sql语句有问题——然而并不,试了一下发现sql语句完全没有问题,其他地方取数据一个不漏。而且如果sql语法真的有问题话我的try也catch的到才对。
这、这不应该啊?
第二阶段
因为百度和谷歌都解决不了我的问题,所以我决定自己找错。
实际项目中我的代码结构比这复杂很多,于是我为了找到到底是哪里出问题而在代码各层都打上了log(因为框架特殊,用不了断点)。
其中为了方便我在开始取数据之前先输出一堆环境,我把代码改成了这样:
conn.prepareStatement(sql).executeQuery().let { rs ->
val count = rs.asIterable().count()
//log many variables
while(rs.next()){
//log
//do sth and log again
}
}
没错,除了添加一堆log以外,唯一的变动就是我把count的获取移到了开头以方便我输出。
结果神奇的是发生了,count居然不是0,而是取到数量了,然而我的数据依旧没取到。
what’s up?
第三阶段
经历了如上的魔法一般的经历,我隐隐之中感觉到不大对劲。于是我当场望文生义(别学我),改成了下面这样:
conn.prepareStatement(sql).executeQuery().let { rs ->
val count = rs.row
//log many variables
while(rs.next()){
//log
//do sth and log again
}
}
提醒一点: rs.row
其实是获取当前的行数,并不是获取总共的数量,在开始的时候处于before_read状态,所以自然是0。
不过当时我已经变成急急国王了,就单纯想把count改掉,没想那么多。
然后魔幻的事情发生了——这次我count是0,但是取到数据了。
count是0很合理可以理解,但是你为什么突然又取得到数据了?明明我在取数据那一块除了加log以外完全没动过?
结论
原官方文档不知道说了没有,应该是 rs.asIterable()
这个方法会直接从rs中取走所有数据,导致next()从一开始就是after_read状态,自然就返回false了。
不过第一阶段的时候为什么明明在末尾却依旧能抢我的数据这点还是无法理解,有没有大佬能够在评论区解释一下。
解决方法
不要对同一个ResultSet在任何位置调用 rs.asIterable()
方法,会被抢数据。如果要获取rs的行数的话可以在取完数据之后通过 rs.row-1
得到。