如何使用函数式编程风格在 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)
.
响应值
我有一段使用数据库连接的 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)
.