如何设置Slick(使用2.1)以便它使用与Spring配置相关联的相同事务管理器?
更多上下文:我们有一个依赖Slick进行数据库工作的应用程序,并使用一个由Spring提供事务管理的库(Activiti)。我们在Spring事务中包含对该lib的调用,如下所示,我们希望每当Activiti一方的事务失败时,我们的Slick调用发出的查询也会被回滚。
def withSpringTransaction[T](f: TransactionStatus => T)(implicit transactionTemplate: TransactionTemplate) =
transactionTemplate.execute(new TransactionCallback[T] {
protected def doInTransaction(status: TransactionStatus) = f(status)
})
withSpringTransaction { transactionStatus =>
db.withTransaction { session =>
// Activiti API calls
// Slick API calls
}
}
我知道如果出现问题,我们可以在前面的代码中同时调用transactionStatus.setRollbackOnly()
和session.rollBack()
,但我们的问题在于更复杂的情况,其中Activiti在其他地方调用某些侦听器,而无法访问在此范围内声明的会话。
答案 0 :(得分:0)
我终于通过让Spring完全处理事务来解决这个问题。如果事件由Activiti回滚,或者我们使用transactionStatus.setRollbackOnly()
在我们的代码中手动回滚,那么我们通过Slick完成的数据库查询将被回滚,只要我们配置Slick指向与Spring相同的数据源,包含在TransactionAwareDataSourceProxy中。因此,Spring的应用程序上下文应该具有类似
<bean id="dataSourceRaw" class="com.example.spring.DataSourceProvider" factory-method="getDataSource" />
<bean id="dataSourceTx" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
<property name="targetDataSource" ref="dataSourceRaw" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceRaw" />
</bean>
因此需要对数据源的引用的Spring bean指向dataSourceRaw
,并且我们创建了一个新的bean dataSourceTx
,它包含了与TransactionAwareDataSourceProxy
相同的数据源,由Slick使用
然后问题中的例子就像
def withSpringAndSlickTransaction[T](f: TransactionStatus => Session => T)(implicit transactionTemplate: TransactionTemplate, dataSourceTx: TransactionAwareDataSourceProxy) = {
transactionTemplate.execute(new TransactionCallback[T] {
protected def doInTransaction(status: TransactionStatus) = {
val proxiedDb: scala.slick.driver.PostgresDriver.simple.Database = Database.forDataSource(dataSourceTx)
val session = proxiedDb.createSession()
f(status)(session)
}
})
}
withSpringAndSlickTransaction { transactionStatus => session =>
// Activiti API calls
// Slick API calls
}
注意我们应该在Slick中手动创建会话,因为对db.withSession
的调用将尝试将基础连接设置为自动提交模式,这会引发异常,因为Spring已将其设置为不自动提交。当然我们也被禁止用S {session.rollback
手动回滚交易,而是让Spring自动执行(或者我自己用transactionStatus.setRollbackOnly()
手动)。