如何使用函数式编程风格在 Scala 中管理数据库连接?

How to manage DB connection in Scala using functional programming style?

我有一段使用数据库连接的 Scala 代码:

def getAllProviderCodes()(implicit conf : Configuration) : List[String] = {
  var conn: java.sql.Connection = null
  try {
    conn = DriverManager.getConnection(DBInfo.dbUrl(conf), DBInfo.dbUserName(conf), DBInfo.dbPassword(conf))
    return ResultSetIterator.create(
              conn.prepareStatement("SELECT pcode FROM providers").executeQuery()
           ){_.getString("pcode")}.toList
  } catch {
    case e: Exception =>
      logger.warn("Something went wrong with creating the connection: " + e.getStackTrace)
  } finally {
    if (conn != null) {
      conn.close()
    }
  }
  List()
}

它非常像 OOP-Java 风格,所以我想知道有没有办法以更实用的方式编写它?我试图成功应用 Try monad,但失败了:我最担心的是我们这里有状态,以及 finally 块。也许这种情况有某种模式?

提前致谢。

UPD: 这是来自 here 的示例,恕我直言,解决方案将是什么样子:

val connection = database.getConnection()
val data: Seq[Data] = Try{
  val results = connection.query("select whatever")
  results.map(convertToWhatIneed)
} recover {
  case t: Throwable => 
    Seq.empty[Data]
} get
connection.close()

但是正如我在评论中提到的,我必须关闭连接,然后我必须将所有与连接有关的东西放在里面尽量保持它的纯净......然后我用 "try-catch-finally" 在 Try 块中。

只需在 try 之外拉出连接:

 val conn = getConnection()
 try {
    doStuff(conn)
 } finally { 
    conn.close
 }

如果您希望整个结果是 Try,只需将其包装成 Try:

 def doDBStuff = Try {
   val conn = getConnection()
   try {
    doStuff(conn)
   } finally { 
    conn.close
   }
 }

或者少一点嵌套(但这会抛出连接异常):

 def doDBStuff = {
   val conn = getConnection()
   val result = Try { doStuff(conn) }
   conn.close
   result
 }

我从来没有玩过 Java SQL 连接库,所以我的答案的语法被写成伪代码,但如果我正确理解你的问题,我将如何实现你做了什么:

def getAllProviderCodes()(implicit conf : Configuration): List[String] = {
  val conn: Connection = DriverManager.getConnection(???) // replace ??? with parameters

  val result: List[String] = Try {
    ??? // ResultSetIterator stuff
  } match {
    case Success(output) => output // or whatever .toList thing
    case Failure(_) => List.empty // add logging here
  }

  if(conn != null) conn.close()
  result // will be whatever List you make (or an empty List if Try fails)
}

而不是 Java-like try-catch-finally 块,一种类似 Scala 的做事方式是将可能爆炸的东西放在 Try 块中并分配使用 case Success(out)case Failure(ex).

响应值