如何使用函数式编程风格管理Scala中的DB连接?
我有一段使用DB连接的Scala代码:如何使用函数式编程风格管理Scala中的DB连接?,scala,functional-programming,database-connection,Scala,Functional Programming,Database Connection,我有一段使用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)
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()
}
这是一种非常类似于面向对象Java的风格,所以我想知道是否有一种方法可以用更实用的方式编写它?我试图成功地应用monad,但失败了:我最担心的是这里有state,以及finally
块。也许这类案件有某种模式
先谢谢你
UPD:以下是解决方案的示例:
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 catch finally”的变体。只需将连接拉出try:
val conn = getConnection()
try {
doStuff(conn)
} finally {
conn.close
}
如果您希望整个过程的结果是一次尝试,只需将其包装成一次尝试:
def doDBStuff = Try {
val conn = getConnection()
try {
doStuff(conn)
} finally {
conn.close
}
}
或者使用更少的嵌套(但这将引发连接异常):
我从未使用过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)和case Failure(ex)将响应分配给一个值你能使用
scala.util发布失败的代码吗?试试看
,这样我们就可以帮助你看到哪里出了问题?@JamesWhiteley实际上我没有失败的代码,因为我只是想知道如何实现它。我以为应该是类似的东西,但当我必须关闭连接时,我被卡住了,然后明白所有与连接有关的东西都应该放在尝试中。。。然后返回带有“try catch finally”的变量,仅在try块内:)
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)
}