将数据库方法从服务层注入存储层

时间:2014-02-27 15:39:51

标签: scala dependency-injection slick

我们的应用程序在存储层之上有一个服务层 - 服务层方法将创建一个新的数据库会话(我们在MySql之上使用Slick)并将会话作为隐式参数传递给存储层方法

trait Service1 {
  def serviceLayerMethod(params) = {
    db withSession {
      implicit session: Session =>
        storageLayerMethod1(params)
        storageLayerMethod2(params)
}}}

object DAO1 {
  def storageLayerMethod1(params)(implicit session: Session)
}

object DAO2 {
 def storageLayerMethod2(params)(implicit session: Session)
}

我们希望能够从服务层向存储层注入不同的方法实现,例如我们有一个multiGet方法来检索多个记录,我们希望有不同的实现方式这种方法,例如一个与multiGet并行执行,另一个在从数据库中提取数据之前尝试从Redis缓存中检索数据。我可以将这些方法作为隐式参数传递,但我希望有一种方法可以用更少的样板来做到这一点。

trait MultiGet {
  def multiGet(params)(implicit session: Session)
}

object MultiGetDefault extends MultiGet
object MultiGetParallel extends MultiGet
object MultiGetCached extends Multiget

trait Servic1 {
  def serviceLayerMethod1(params) = {
    db withSession {
      implicit session: Session =>
        storageLayerMethod1(params)(MultiGetDefault)
  }}

  def serviceLayerMethod2(params) = {
    db withSession {
      implicit session: Session =>
        storageLayerMethod1(params)(MultiGetParallel)
}}}

object DAO1 {
  def storageLayerMethod1(params)(implicit session: Session, multiGetImpl: MultiGet) {
    multiGetImpl.multiGet(params)
}}

大多数存储层方法都是单例对象,因此如果没有重要的重构,我就无法混合不同的MultiGet实现。服务层特征通过蛋糕模式在控制器层实例化/注入。

1 个答案:

答案 0 :(得分:0)

我们将尝试使用实现Session等的版本扩展/包装multiGet

trait MySession extends Session {
  private val session: Session

  def capabilities = session.capabiliites
  def close = session.close
  def conn = session.conn
  ...

  def multiGet(tableName: String, ids: Seq[Int])
}

class DefaultSession(private val session: Session) extends MySession {
  def multiGet(tableName: String, ids: Seq[Int]) // default implementation
}

class ConcurrentSession(private val session: Session) extends MySession {
  def multiGet(tableName: String, ids: Seq[Int]) // concurrent implementation
}

def defaultExecute[T](fun: (MySession) => T): T = db withSession {
  _session: Session =>
    fun(new DefaultSession(_session))
}

def concurrentExecute[T](fun: (MySession) => T): T = db withSession {
  _session: Session =>
    fun(new ConcurrentSession(_session))
}