Scala Tail Recursion java.lang.StackOverflowError

时间:2016-05-24 19:36:20

标签: scala tail-recursion

我正在迭代地查询一个名为txqueue的mysql表,该表正在不断增长。

每个连续查询仅考虑在上一次迭代中执行查询后插入到txqueue表中的行。

为实现此目的,每个连续查询从表中选择主键(下例中的seqno字段)超过上一个查询中观察到的最大seqno的行。

以这种方式识别的任何新插入的行都将写入csv文件。

目的是让这个过程无限期地运行。

下面的尾递归函数可以正常工作,但过了一段时间它会遇到java.lang.StackOverflowError。每个迭代查询的结果包含两到三行,每秒左右返回一次结果。

关于如何避免java.lang.StackOverflowError的任何想法?

这实际上是可以/应该通过流媒体实现的吗?

非常感谢任何建议。

这是有效的代码:

object TXQImport {

  val driver = "com.mysql.jdbc.Driver"
  val url = "jdbc:mysql://mysqlserveraddress/mysqldb"
  val username = "username"
  val password = "password"
  var connection:Connection = null

  def txImportLoop(startID : BigDecimal) : Unit = {

      try {

        Class.forName(driver)
        connection = DriverManager.getConnection(url, username, password)
        val statement = connection.createStatement()
        val newMaxID = statement.executeQuery("SELECT max(seqno) as maxid from txqueue")

        val maxid = new Iterator[BigDecimal] {
          def hasNext = newMaxID.next()
          def next() = newMaxID.getBigDecimal(1)
        }.toStream.max

        val selectStatement = statement.executeQuery("SELECT seqno,someotherfield " +
          " from txqueue where seqno >= " + startID + " and seqno < " + maxid)

        if(startID != maxid) {

          val ts = System.currentTimeMillis
          val file = new java.io.File("F:\\txqueue " + ts + ".txt")
          val bw = new BufferedWriter(new FileWriter(file))

          // Iterate Over ResultSet
          while (selectStatement.next()) {

            bw.write(selectStatement.getString(1) + "," + selectStatement.getString(2))
            bw.newLine()

          }

          bw.close()

        }

        connection.close()
        txImportLoop(maxid)

      }

      catch {
        case e => e.printStackTrace
      }  

  }

  def main(args: Array[String]) {

    txImportLoop(0)

  }

}

1 个答案:

答案 0 :(得分:6)

你的函数不是尾递归的(因为最后是catch)。 这就是你最终堆栈溢出的原因。

你应该总是使用@scala.annotation.tailrec注释你想要尾递归的函数 - 如果不能进行尾递归,它将无法编译,这样你就不会对它在运行时感到惊讶。