包装器捕获在db.run调用上获得的异常

时间:2016-04-02 12:54:07

标签: scala playframework playframework-2.0 slick

在我们的项目中,我们始终在bean对象中注入dbConfigProvider: DatabaseConfigProvider,然后使用db.run(some query)进行数据库操作,它返回Future。如何为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
  }
}

注意: 如果我在每个.onFailure电话上添加db.run,那么我的代码会非常糟糕。这就是我需要为所有db.run次调用编写此包装器的原因。

如果我将db.run包含在具有不同签名的某个函数中,我必须在很多地方更改它,这不是最好的选择。我怎么能隐含地做到这一点?

2 个答案:

答案 0 :(得分:1)

您不需要显式创建新的包装类,您可以使用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

答案 1 :(得分:-1)

创建一个新课程:

  case class DBWrapper(db: DatabaseComponent) {
     def run(query: String) = db.run(query).onFailure { case e => logger.error(e) } 
  }

并使用dbDBWrapper(db)替换为初始化的Id。 你也可以隐式地来回转换,虽然在这种情况下我不推荐它。