包装器捕获 db.run 调用中出现的异常
Wrapper catching exceptions accured on db.run call
在我们的项目中,我们总是在我们的 bean 对象中注入 dbConfigProvider: DatabaseConfigProvider
,然后使用 db.run(some query)
进行数据库操作,它 returns 未来。我如何为 db.run
编写日志包装器,它将打印所有 sql 异常。
示例:
class SomeBeanImpl @Inject()(dbConfigProvider: DatabaseConfigProvider) {
private val logger = Logger(getClass)
def someDBQuery() = {
db.run(some wrong sql query) // exception raised in future, I need to print it with logger
}
}
注:
如果我在每个 db.run
调用上添加 .onFailure
,它会把我的代码搞得一团糟。这就是为什么我需要为所有 db.run
调用编写这个包装器。
如果我将 db.run
包装在一些具有不同签名的函数中,我必须在很多地方进行更改,这不是最佳选择。我怎样才能隐含地做到这一点?
制作一个新的class:
case class DBWrapper(db: DatabaseComponent) {
def run(query: String) = db.run(query).onFailure { case e => logger.error(e) }
}
并用 DBWrapper(db)
替换你的 db
。
您也可以隐式地来回转换,但在这种情况下我不推荐这样做。
您不需要显式创建一个新的包装器 class,您可以使用 Pimp My Library 模式创建一个隐式方法来包装 db.run
的调用并附加一个onFailure
到 Future
:
object MyExtensions {
class DbExtensions(db: Db) {
def runAndLog(query: String): Future[String] = {
val result = db.run(query)
result.onFailure {
case e => Logger.getLogger("x").error(s"Exception: $e")
}
result
}
}
implicit def dbExtention(db: Db): DbExtensions = new DbExtensions(db)
}
class Db {
def run(query: String): Future[String] = Future.successful("Hello")
}
object App extends Application {
import MyExtensions._
val db = new Db
db.runAndLog("hello")
}
对于 Scala 2.10 及更高版本,可以使用 Implicit Classes:
显着缩短
implicit class DbExtensions(val db: Db) {
def runAndLog(query: String): Future[String] = {
val result = db.run(query)
result.onFailure {
case e => Logger.getLogger("x").error(s"Exception: $e")
}
result
}
}
class Db {
def run(query: String): Future[String] = Future.successful("Hello")
}
object App extends Application {
val db = new Db
db.runAndLog("hello")
}
您可以进一步使 DbExtensions
扩展 AnyVal
以进行性能优化:
implicit class DbExtensions(val db: Db) extends AnyVal
在我们的项目中,我们总是在我们的 bean 对象中注入 dbConfigProvider: DatabaseConfigProvider
,然后使用 db.run(some query)
进行数据库操作,它 returns 未来。我如何为 db.run
编写日志包装器,它将打印所有 sql 异常。
示例:
class SomeBeanImpl @Inject()(dbConfigProvider: DatabaseConfigProvider) {
private val logger = Logger(getClass)
def someDBQuery() = {
db.run(some wrong sql query) // exception raised in future, I need to print it with logger
}
}
注:
如果我在每个 db.run
调用上添加 .onFailure
,它会把我的代码搞得一团糟。这就是为什么我需要为所有 db.run
调用编写这个包装器。
如果我将 db.run
包装在一些具有不同签名的函数中,我必须在很多地方进行更改,这不是最佳选择。我怎样才能隐含地做到这一点?
制作一个新的class:
case class DBWrapper(db: DatabaseComponent) {
def run(query: String) = db.run(query).onFailure { case e => logger.error(e) }
}
并用 DBWrapper(db)
替换你的 db
。
您也可以隐式地来回转换,但在这种情况下我不推荐这样做。
您不需要显式创建一个新的包装器 class,您可以使用 Pimp My Library 模式创建一个隐式方法来包装 db.run
的调用并附加一个onFailure
到 Future
:
object MyExtensions {
class DbExtensions(db: Db) {
def runAndLog(query: String): Future[String] = {
val result = db.run(query)
result.onFailure {
case e => Logger.getLogger("x").error(s"Exception: $e")
}
result
}
}
implicit def dbExtention(db: Db): DbExtensions = new DbExtensions(db)
}
class Db {
def run(query: String): Future[String] = Future.successful("Hello")
}
object App extends Application {
import MyExtensions._
val db = new Db
db.runAndLog("hello")
}
对于 Scala 2.10 及更高版本,可以使用 Implicit Classes:
显着缩短implicit class DbExtensions(val db: Db) {
def runAndLog(query: String): Future[String] = {
val result = db.run(query)
result.onFailure {
case e => Logger.getLogger("x").error(s"Exception: $e")
}
result
}
}
class Db {
def run(query: String): Future[String] = Future.successful("Hello")
}
object App extends Application {
val db = new Db
db.runAndLog("hello")
}
您可以进一步使 DbExtensions
扩展 AnyVal
以进行性能优化:
implicit class DbExtensions(val db: Db) extends AnyVal