Scala Play Framework 2.6、Guice、Slick 3.2.3 根据请求动态更改数据库
Scala Play Framework 2.6, Guice, Slick 3.2.3 change database dynamically based on requests
我有一个应用程序,这些是堆栈
- 播放 2.6
- 吉斯
- 玩 Slick 3.0.0
我正在尝试根据请求参数动态查询不同的数据库。
例如在 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
参数
这是可能的解决方案之一。
配置数据库
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")
}
}
创建助手class
@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)
}
}
注入依赖和 select 数据库到 运行
@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)
}
}
}
}
我有一个应用程序,这些是堆栈
- 播放 2.6
- 吉斯
- 玩 Slick 3.0.0
我正在尝试根据请求参数动态查询不同的数据库。
例如在 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
参数
这是可能的解决方案之一。
配置数据库
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")
}
}
创建助手class
@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)
}
}
注入依赖和 select 数据库到 运行
@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)
}
}
}
}