首页 > 解决方案 > Scala Play Framework 2.6、Guice、Slick 3.2.3 根据请求动态更改数据库

问题描述

我有一个应用程序这些是堆栈

我正在尝试根据请求参数动态查询不同的数据库。

例如在application.conf

slick.dbs.default.profile = "slick.jdbc.H2Profile$"
slick.dbs.default.db.driver="org.h2.Driver"
slick.dbs.default.db.url="jdbc:h2:mem:test;MODE=MYSQL;DATABASE_TO_UPPER=false;DB_CLOSE_DELAY=-1;"

play.evolutions.db.default.enabled = true

slick.dbs.mydb2.profile = "slick.jdbc.H2Profile$"
slick.dbs.mydb2.db.driver="org.h2.Driver"
slick.dbs.mydb2.db.url="jdbc:h2:mem:test;MODE=MYSQL;DATABASE_TO_UPPER=false;DB_CLOSE_DELAY=-1;"

play.evolutions.db.mydb2.enabled = true

存储库

@Singleton
class UserRepositoryImpl @Inject() (@NamedDatabase("mydb2") dbConfigProvider: DatabaseConfigProvider)
  (implicit ec: ExecutionContext) extends UserRepository {

  val dbConfig = dbConfigProvider.get[JdbcProfile]

  import dbConfig._
  import profile.api._

  override def all: EitherT[Future, String, Seq[User]] = EitherT {
    db.run(UserTable.UserQuery.result.asTry).map {
      case Success(result) => {
        logger.debug(s"all success: $result")
        Right(result)
      }
      case Failure(error) => {
        val str = s"all error: ${error.getMessage}"
        logger.error(str, error)
        Left(str)
      }
    }
  }

}

有没有办法改变dbConfigProvider每个请求?我想@NamedDatabase根据请求参数更改参数

标签: scalaplayframeworkguiceslick

解决方案


这是可能的解决方案。

配置数据库

class Module(environment: Environment, configuration: Configuration) extends AbstractModule {

  def configure(): Unit = {
    bind(classOf[Config])
      .annotatedWith(Names.named("dbConfig"))
      .toInstance(configuration.underlying.getConfig("slick.dbs"))

    bind(classOf[String])
      .annotatedWith(Names.named("dbSchema1"))
      .toInstance("default")

    bind(classOf[String])
      .annotatedWith(Names.named("dbSchema2"))
      .toInstance("mydb2")
  }
}

创建助手类

@Named("databaseService")
@Singleton
class DatabaseService @Inject()(@Named("dbConfig") dbConfig: Config,
                                @Named("dbSchema1") schema1: String,
                                @Named("dbSchema2") schema2: String) extends Logging {

  lazy val db1: JdbcBackend#DatabaseDef = {
    info("Init DB1")
    val database = DatabaseConfig.forConfig[MySQLProfile](schema1, dbConfig).db
    info("DB1 is ready")
    database
  }

  lazy val db2: JdbcBackend#DatabaseDef = {
    info("Init DB2")
    val database = DatabaseConfig.forConfig[MySQLProfile](schema2, dbConfig).db
    info("DB2 is ready")
    database
  }

  def run[R](action: DBIOAction[R, NoStream, Nothing])(implicit db: JdbcBackend#DatabaseDef): Future[R] = {
    import scala.concurrent.ExecutionContext.Implicits.global
    db.run(action).recoverWith {
      case exception: Throwable => {
        error("query failed", exception)
        Future.failed[R](exception)
      }
    }
  }

  def runDb1[R](action: DBIOAction[R, NoStream, Nothing]): Future[R] = {
    implicit val db = db1
    run(action)
  }

  def runDb2[R](action: DBIOAction[R, NoStream, Nothing]): Future[R] = {
    run(action)(db2)
  }
}

注入依赖并选择db运行

@Singleton
class UserRepositoryImpl @Inject() (databaseService: DatabaseService)
                                   (implicit ec: ExecutionContext) extends UserRepository {

  def all(param: Param): EitherT[Future, String, Seq[User]] = EitherT {
    val db = param match {
      case db1 => databaseService.db1
      case db2 => databaseService.db2
    }
    databaseService.run(UserTable.UserQuery.result.asTry)(db).map {
      case Success(result) => {
        logger.debug(s"all success: $result")
        Right(result)
      }
      case Failure(error) => {
        val str = s"all error: ${error.getMessage}"
        logger.error(str, error)
        Left(str)
      }
    }
  }
}

推荐阅读