莫那·鲁道

惯于闲看花飞花落, 心念天际云卷云舒.

Coder, 欢迎留言 😆.


GitHub

Spring-声明式事务(三)——其余属性

前言

众所周知,Spring 的事务属性众多,楼主今天将对 Spring 最常用的事务 —— 声明式事务,进行彻底的解释,包括楼主也写了很多的测试例子。代码地址: 使用 tk-mybatis 的 demo 测试了 Spring 的事务

readOnly 属性

该属性的文档中说道:这不是一个百分百限制读操作之外的属性。

什么意思呢?虽然从字面意思看,是只读,但具体看数据库的实现。

mysql 数据库中,如果设置了这个属性,那么驱动将返回一个异常。 oracle 和 sqlServer 则不会,他们会忽略错误。

因此,在不同的数据库下使用要注意这点。

timeout

该属性单位是秒,不是毫秒。

从字面上看,是定义这个事务的超时时间。

我们会想当然的认为这是从事务的方法开始到方法的结束。

但,不是这样的。

是从事务方法的开始,到 SQL 语句执行的结束,因此,SQL 语句后面的代码执行时间都不算在 timeout 中的。

这点非常重要。

这样将导致下面的代码可能无法达到你想要的结果:

@Transactional(timeout = 3)
public void timeOut() {
  userInfoMapper
      .insert(new UserInfo().setUsername("timeout").setPassword("timeout"));
    Thread.sleep(3100);
}

代码中,我们想让这个事务耗时超过 3 秒,那么就可以触发 timeout ,让 insert 无法提交。然而这时不可能的。因为,我们刚刚说,Sql 执行结束后,超时的计时就结束了。

而下面的例子则可以正确的触发 timeout:

@Transactional(timeout = 3)
public void timeOut() {
  Thread.sleep(3100);
  userInfoMapper
      .insert(new UserInfo().setUsername("timeout").setPassword("timeout"));
}

代码中,从事务的开始到 sql 执行结束的总时间超过了 timeout 设定的时间。成功触发 timeout 机制 —— 抛出异常。

rollbackFor 和 noRollbackFor

定义一个 Class 数组,需要继承自 Throwable,也就是异常。

事务需要回滚,那么什么样的异常才能让事务回滚?

默认是 RuntimeException 和 Error。代码如下:

用户可以自定义回滚类似和反回滚类型。

上面的两个属性是相反的。

rollbackForClassName 和 noRollbackForClassName

这两个其实和上面的是一样的功能,只是这里使用了字符串,在某些类加载器不同的场合,也许有用武之地。注意,这里只需要写简单类名即可,无需写全类名。