【问题标题】:Using Spring transactions with Slick使用带有 Slick 的 Spring 事务
【发布时间】:2015-09-22 18:58:55
【问题描述】:

如何设置 Slick(使用 2.1)使其使用与 Spring 配置关联的相同事务管理器?

更多上下文:我们有一个应用程序依赖于 Slick 的数据库工作,并使用一个库 (Activiti),其事务管理由 Spring 提供。我们将对该库的调用包装在 Spring 事务周围,如下所示,我们希望每当 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 在其他地方调用某个侦听器,而无法访问在此声明的会话范围。

【问题讨论】:

    标签: spring scala slick


    【解决方案1】:

    我终于通过让 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 已经将其设置为不自动提交。当然我们也被禁止使用session.rollback使用Slick手动回滚事务,而是让Spring自动执行(或者我们自己手动使用transactionStatus.setRollbackOnly())。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多