【问题标题】:How to manage DB connection in Scala using functional programming style?如何使用函数式编程风格在 Scala 中管理数据库连接?
【发布时间】:2018-07-10 10:56:44
【问题描述】:

我有一段使用 DB 连接的 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 块中。

【问题讨论】:

  • 您能否使用scala.util.Try 发布您的失败代码,以便我们帮助您查看哪里出错了?
  • @JamesWhiteley 实际上我没有失败代码的示例,因为我只是在弄清楚如何实现它。我认为它应该类似于scalerablog.wordpress.com/2016/05/16/… 但是当我必须关闭连接时我被卡住了,然后明白所有与连接有关的东西都应该放在 Try... 然后返回变体“尝试-catch-finally”,仅在 Try 块内 :)

标签: scala functional-programming database-connection


【解决方案1】:

我从来没有玩过 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 的 try-catch-finally 块,一种类似 Scala 的做事方式是将可能爆炸的东西放在 Try 块中,并使用 case Success(out) 和 @ 将响应分配给一个值987654325@.

【讨论】:

    【解决方案2】:

    只需将连接拉到尝试之外:

     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
     }
    

    【讨论】:

      猜你喜欢
      • 2022-11-30
      • 2010-12-15
      • 1970-01-01
      • 1970-01-01
      • 2020-08-23
      • 2010-09-25
      • 2019-05-11
      • 1970-01-01
      • 2013-01-24
      相关资源
      最近更新 更多