使用slick时如何获取play数据源实例

问题描述 投票:0回答:1

我正在使用 play-slick 和 slick进化来创建我的数据库。

我有以下配置

slick.dbs.default.profile="slick.jdbc.H2Profile$"
slick.dbs.default.db.driver="org.h2.Driver"
slick.dbs.default.db.url="jdbc:h2:mem:play;DB_CLOSE_DELAY=-1"

当我想使用 slick 本身对数据库进行操作时,这效果很好。但是,我想访问底层

javax.sql.Datasource
实例(我需要将其传递给另一个库,即 pac4js
DbProfileService
)。

我尝试添加数据库名称的配置为

dbName="play"
,然后添加

  @Provides
  def dbProfileService(dbApi: DBApi): DbProfileService = {
    new DbProfileService(dbApi.database(configuration.get[String]("dbName")).dataSource)
  }

但是,注入似乎发生在进化脚本有机会运行之前,这会导致出现异常,指出无法找到

play
数据库。 有没有更好的方法来解决这个问题?

这是堆栈跟踪

aused by: java.lang.IllegalArgumentException: Could not find database for play
    at play.api.db.slick.evolutions.internal.DBApiAdapter.$anonfun$database$1(DBApiAdapter.scala:32)
    at scala.collection.immutable.Map$Map1.getOrElse(Map.scala:248)
    at play.api.db.slick.evolutions.internal.DBApiAdapter.database(DBApiAdapter.scala:32)
    at modules.SecurityModule.dbProfileService(SecurityModule.scala:53)
    at modules.SecurityModule$$FastClassByGuice$$153731.GUICE$TRAMPOLINE(<generated>)
    at modules.SecurityModule$$FastClassByGuice$$153731.apply(<generated>)
    at com.google.inject.internal.ProviderMethod$FastClassProviderMethod.doProvision(ProviderMethod.java:260)
    at com.google.inject.internal.ProviderMethod.doProvision(ProviderMethod.java:171)
    at com.google.inject.internal.InternalProviderInstanceBindingImpl$CyclicFactory.provision(InternalProviderInstanceBindingImpl.java:185)
    at com.google.inject.internal.InternalProviderInstanceBindingImpl$CyclicFactory.get(InternalProviderInstanceBindingImpl.java:162)
    at com.google.inject.internal.SingleParameterInjector.inject(SingleParameterInjector.java:40)
    at com.google.inject.internal.SingleParameterInjector.getAll(SingleParameterInjector.java:60)
    at com.google.inject.internal.ProviderMethod.doProvision(ProviderMethod.java:171)
    at com.google.inject.internal.InternalProviderInstanceBindingImpl$CyclicFactory.provision(InternalProviderInstanceBindingImpl.java:185)
    at com.google.inject.internal.InternalProviderInstanceBindingImpl$CyclicFactory.get(InternalProviderInstanceBindingImpl.java:162)
    at com.google.inject.internal.SingleParameterInjector.inject(SingleParameterInjector.java:40)
    at com.google.inject.internal.SingleParameterInjector.getAll(SingleParameterInjector.java:60)
    at com.google.inject.internal.ProviderMethod.doProvision(ProviderMethod.java:171)
    at com.google.inject.internal.InternalProviderInstanceBindingImpl$CyclicFactory.provision(InternalProviderInstanceBindingImpl.java:185)
    at com.google.inject.internal.InternalProviderInstanceBindingImpl$CyclicFactory.get(InternalProviderInstanceBindingImpl.java:162)
    at com.google.inject.internal.SingleFieldInjector.inject(SingleFieldInjector.java:50)
    at com.google.inject.internal.MembersInjectorImpl.injectMembers(MembersInjectorImpl.java:146)
    at com.google.inject.internal.MembersInjectorImpl.injectAndNotify(MembersInjectorImpl.java:101)
    at com.google.inject.internal.Initializer$InjectableReference.get(Initializer.java:245)
    at com.google.inject.internal.Initializer.injectAll(Initializer.java:140)
    at com.google.inject.internal.InternalInjectorCreator.injectDynamically(InternalInjectorCreator.java:180)

我还添加了一个断点,果然,那里只有

default
db,而不是我期望的
play
db。

scala playframework slick pac4j
1个回答
0
投票

问题出在键

dbName
的值上。当你在做的时候

configuration.get[String]("dbName")

您正在查找配置文件中名为

dbName
的键的值。在提供的示例中,该值为
play
。现在,看看完整的生产线,您会看到这个

@Provides
def dbProfileService(dbApi: DBApi): DbProfileService = {
  new DbProfileService(
    dbApi                                   // trait play.api.db.DBApi
      .database(                            // method from `DBApi`
        configuration.get[String]("dbName") // getting the value of the key `dbName` from config file
      )
      .dataSource 
    )
}

您正在从

database
调用
DBApi
方法。有两个类混合了这种特性。一个是来自 play-slick-evolutions
DBApiAdapter
,另一个是来自 play-jdbc
DefaultDBApi
。我认为在你的情况下使用的是属于进化模块的模块。如果您查看正在调用的方法
database
的实现,两个类都具有相同的逻辑(因此,使用哪个实现并不重要)。

def database(name: String): Database = {
  databaseByName.getOrElse(name, throw new IllegalArgumentException(s"Could not find database for $name"))
}

这意味着它将查找带有前缀

slick.dbs.<db name>
的键。根据您收到的错误消息

caused by: java.lang.IllegalArgumentException: Could not find database for play
    at play.api.db.slick.evolutions.internal.DBApiAdapter.$anonfun$database$1(DBApiAdapter.scala:32)

您尝试查找带有前缀

slick.dbs.play
的数据库配置,并且 stracktrace 显示在这种情况下正在使用 evolutino 模块的实现。

要解决此问题,您有两种选择:

  • 将键
    play
    的值
    dbName
    更改为
    default
  • 将前缀
    slick.dbs.default
    更改为
    slick.dbs.play
© www.soinside.com 2019 - 2024. All rights reserved.