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

时间:2018-07-10 10:56:44

标签: scala functional-programming database-connection

我使用数据库连接有一段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中的示例,IMHO解决方案如下:

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-最终捕获”在Try块中。

2 个答案:

答案 0 :(得分:1)

我从来没有使用过Java SQL Connection库,所以答案的语法已被编写为伪代码,但是如果我正确理解了您的问题,那么这就是我将如何实现您所做的事情:

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)
}

一种类似Scala的处理方式代替了类似Java的try-catch-finally块,而是将可能爆炸的内容放入Try块中,并使用{将响应分配给一个值{1}}和case Success(out)

答案 1 :(得分:0)

只需将连接拉出尝试:

 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
 }