Spring事務之REQUIRES_NEW

RequiresNewPropagation: 開啓獨立的新事務mysql

/**
  * Created by caojialin
  * Date: 2019-08-15 20:09
  * Description: 獨立於原事務外, 從新開啓一個新事務, 此事務與原事務獨立互不影響
  */
@Component
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Array(classOf[Throwable]))
class RequiresNewPropagation {

  val LOGGER: Logger = LoggerFactory.getLogger(getClass)

  def invoke[A, B](req: => A)(func: => A => B): B = {
    LOGGER.debug("start a new transaction ...")
    val resp = func(req)
    LOGGER.debug("finish a new transaction .")

    resp
  }
}

PropagationUtil: 工具Beanspring

object PropagationUtil {
  private val LOGGER: Logger = LoggerFactory.getLogger(getClass)

  @Resource
  var requiresNewPropagation: RequiresNewPropagation = _

  /**
    * 從新開啓一個事務
    * @param req
    * @param func
    * @tparam A
    * @tparam B
    * @return Assert.assert 拋出的異常 被代理 最終異常爲 UndeclaredThrowableException 類型
    *         異常信息: e.getUndeclaredThrowable.getMessage
    */
  def requiresNew[A, B](req: => A)(func: => A => B): B = {
    requiresNewPropagation.invoke(req)(func)
  }

  /**
    * 異常捕獲 不影響後續事務
    * @param req
    * @param func
    * @tparam A
    * @tparam B
    */
  def requiresNewWithTry[A, B](req: => A)(func: => A => B): Unit = {
    try {
      requiresNewPropagation.invoke(req)(func)
    } catch {
      case e: Throwable => LOGGER.error(s"catch exception in a requires new transaction: ", e)
    }
  }
}
注意: 因爲scala的object不支持註解, 因此須要在配置文件配置bean, 以便於注入RequiresNewPropagation
<bean id="propagationUtil" class="com.wanbo.service.order.common.PropagationUtil$" />

PropagationUtilTest: 測試類sql

/**
  * Created by caojialin
  * Date: 2019-08-16 10:11
  * Description: 
  */
@RunWith(classOf[SpringJUnit4ClassRunner])
@ContextConfiguration(locations = Array("classpath:META-INF/spring/services.xml"))
@Transactional
@Rollback(false) //事物不回滾
class PropagationUtilTest {

  // 1-4成功插入數據庫, 5失敗回滾, 後續再也不執行
  @Test
  def requiresNewTest(): Unit = {
    1.to(9).foreach {
      PropagationUtil.requiresNew(_)( id =>
        mysqlData.executeUpdate(sql"insert into test set id = $id")
        if (id % 5 == 0) {
          Assert.assert(assertion = false, OrderException.bizFault("異常數據"))
        }
      )
    }
  }
  
  // 10,15插入失敗, 但異常被捕獲, 不影響其餘事務, 11-14,16-19成功插入
  @Test
  def requiresNewWithTryTest(): Unit = {
    10.to(19).foreach {
      PropagationUtil.requiresNewWithTry(_)( id =>
        mysqlData.executeUpdate(sql"insert into test set id = $id")
        if (id % 5 == 0) {
          Assert.assert(assertion = false, OrderException.bizFault("異常數據"))
        }
      )
    }
  }

}
相關文章
相關標籤/搜索