我使用数据库连接有一段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块中。
答案 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
}