使用Slick的Spring事务

时间:2015-09-03 23:01:25

标签: spring scala slick

如何设置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在其他地方调用某些侦听器,而无法访问在此范围内声明的会话。

1 个答案:

答案 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()手动)。