一、spring支持的事务声明方式

  1. 编程式事务 当系统需要明确的,细粒度的控制各个事务的边界,应选择编程式事务。
  2. 声明式事务 当系统对于事务的控制粒度较粗时,应该选择声明式事务

    二、spring支持7种事务传播行为

    | 传播行为 | 含义 | | —- | —- | | propagation_required(xml文件中为required) | 表示当前方法必须在一个具有事务的上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新开启一个事务。(如果被调用端发生异常,那么调用端和被调用端事务都将回滚 | | propagation_supports(xml文件中为supports) | 表示当前方法不必需要具有一个事务上下文,但是如果有一个事务的话,它也可以在这个事务中运行 | | propagation_mandatory(xml文件中为mandatory) | 表示当前方法必须在一个事务中运行,如果没有事务,将抛出异常 | | propagation_nested(xml文件中为nested) | 表示如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中,被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。如果封装事务不存在,则同propagation_required的一样 | | propagation_never(xml文件中为never) | 表示当方法务不应该在一个事务中运行,如果存在一个事务,则抛出异常 | | propagation_requires_new(xml文件中为requires_new) | 表示当前方法必须运行在它自己的事务中。一个新的事务将启动,而且如果有一个现有的事务在运行的话,则这个方法将在运行期被挂起,直到新的事务提交或者回滚才恢复执行 | | propagation_not_supported(xml文件中为not_supported) | 表示该方法不应该在一个事务中运行。如果有一个事务正在运行,它将在运行期被挂起,直到这个事务提交或者回滚才恢复执行 |

嵌套事务和新事务:
propagation_requires_new 和 propagation_nested是容易混淆的两个传播行为。
propagation_requires_new 启动一个新的、和外层事务无关的“内部”事务。该事务拥有自己的独立隔离级别和锁,不依赖于外部事务,独立地提交和回滚。当内部事务开始执行时,外部事务将被挂起,内务事务结束时,外部事务才继续执行。
由此可见, propagation_requires_new 和 propagation_nested 的最大区别在于:
propagation_requires_new 将创建一个全新的事务,它和外层事务没有任何关系,
而propagation_nested 将创建一个依赖于外层事务的子事务,当外层事务提交或回滚时,子事务也会连带提交和回滚。

  1. 当业务方法被设置为propagation_mandatory时,它就不能被非事务的业务方法调用。
    如将ForumService#addTopic ()设置为propagation_mandatory,如果展现层的Action直接调用addTopic()方法,将引发一个异常
    正确的情况是: addTopic()方法必须被另一个带事务的业务方法调用
    所以 propagation_mandatory的方法一般都是被其它业务方法间接调用的。
  2. 当业务方法被设置为propagation_never时,它将不能被拥有事务的其它业务方法调用。假设UserService#addCredits ()设置为propagation_never,当ForumService# addTopic()拥有一个事务时,addCredits()方法将抛出异常。所以propagation_never方法一般是被直接调用的
  3. 当方法被设置为propagation_not_supported时,外层业务方法的事务会被挂起,当内部方法运行完成后,外层方法的事务重新运行。如果外层方法没有事务,直接运行,不需要做任何其它的事

    三、spring中的事务隔离级别

    | 隔离级别 | 含义 | | —- | —- | | isolation_default | 使用数据库默认的事务隔离级别 | | isolation_read_uncommitted | 允许读取尚未提交的修改,可能导致脏读、幻读和不可重复读 | | isolation_read_committed | 允许从已经提交的事务读取,可防止脏读、但幻读,不可重复读仍然有可能发生 | | isolation_repeatable_read | 对相同字段的多次读取的结果是一致的,除非数据被当前事务自生修改。可防止脏读和不可重复读,但幻读仍有可能发生 | | isolation_serializable | 完全服从acid隔离原则,确保不发生脏读、不可重复读、和幻读,但执行效率最低 |

四、spring事务只读属性


声明式事务的第三个特性是它是否是一个只读事务。如果一个事务只对后端数据库执行读操作,那么该数据库就可能利用那个事务的只读特性,采取某些优化措施。通过把一个事务声明为只读,可以给后端数据库一个机会来应用那些它认为合适的优化措施。由于只读的优化措施是在一个事务启动时由后端数据库实施的, 因此,只有对于那些具有可能启动一个新事务的传播行为(PROPAGATION_REQUIRES_NEW、PROPAGATION_REQUIRED、 ROPAGATION_NESTED)的方法来说,将事务声明为只读才有意义。

五、spring的事务超时


为了使一个应用程序很好地执行,它的事务不能运行太长时间。因此,声明式事务的下一个特性就是它的超时。
假设事务的运行时间变得格外的长,由于事务可能涉及对后端数据库的锁定,所以长时间运行的事务会不必要地占用数据库资源。这时就可以声明一个事务在特定秒数后自动回滚,不必等它自己结束。
由于超时时钟在一个事务启动的时候开始的,因此,只有对于那些具有可能启动一个新事务的传播行为(PROPAGATION_REQUIRES_NEW、PROPAGATION_REQUIRED、ROPAGATION_NESTED)的方法来说,声明事务超时才有意义。

六、事务回滚规则


事务五边形的最后一个边是一组规则,它们定义哪些异常引起回滚,哪些不引起。在默认设置下,事务只在出现运行时异常(runtime exception)时回滚,而在出现受检查异常(checked exception)时不回滚。不过,也可以声明在出现特定受检查异常时像运行时异常一样回滚。同样,也可以声明一个事务在出现特定的异常时不回滚,即使那些异常是运行时异常。

org.springframework.transaction
public interface TransactionDefinition
定义符合 Spring 的事务属性的接口。基于类似于 EJB CMT 属性的传播行为定义。‎
‎注意,除非启动实际的新事务,否则不会应用隔离级别和超时设置。‎ ‎仅‎ PROPAGATION_REQUIRED, PROPAGATION_REQUIRES_NEW and PROPAGATION_NESTED ‎可能导致这种情况,在其他情况下指定这些设置通常没有意义。此外,并非所有事务管理器都支持这些高级功能,因此在给定非默认值时可能会引发相应的异常。‎
read-only flag ‎适用于任何事务上下文,无论是由实际资源事务支持还是在资源级别以非事务方式运行。在后一种情况下,该标志将仅适用于应用程序中的托管资源,‎ ‎例如‎ Hibernate Session.

隔离级别

隔离级别 描述‎
ISOLATION_DEFAULT 使用基础数据存储的默认隔离级别。
ISOLATION_READ_COMMITTED 指示防止脏读;可能发生非可重复读取和幻像读取。
ISOLATION_READ_UNCOMMITTED ‎指示可能发生脏读、非可重复读取和幻像读取。‎
ISOLATION_REPEATABLE_READ ‎指示防止脏读和非可重复读;可能会发生幻像读取。‎
ISOLATION_SERIALIZABLE ‎指示防止脏读、非可重复读取和幻像读取。‎

ISOLATION_READ_COMMITTED

表示防止脏读;可能发生非可重复读取和幻像读取。‎
‎此级别仅禁止事务读取包含未提交更改的行。‎

ISOLATION_READ_UNCOMMITTED

表示可能发生脏读、非可重复读取和幻像读取。‎
‎此级别允许一个事务更改的行在提交该行中的任何更改之前由另一个事务读取(“脏读取”)。如果回滚任何更改,则第二个事务将检索到无效行。

ISOLATION_REPEATABLE_READ

‎表示防止脏读和非可重复读;可能会发生幻像读取。‎
‎此级别禁止事务读取包含未提交更改的行,并且还禁止以下情况:一个事务读取行,第二个事务更改行,第一个事务重新读取行,第二次获取不同的值(“不可重复读取”)。‎

ISOLATION_SERIALIZABLE

‎表示防止脏读、非可重复读取和幻像读取。‎
‎此级别包括‎‎ISOLATION_REPEATABLE_READ‎‎中的禁止,并进一步禁止以下情况:一个事务读取满足某个条件的所有行,第二个事务插入满足该条件的行,第一个事务针对同一条件重新读取,在第二次读取中检索其他“幻像”行

传播行为

传播行为 就是对事务的管理,而事务不仅仅是单个方法上进行操作,很有可能是一个方法嵌套一个方法,一个方法调用另一个方法,但是如果这个方法使用了事务,而它调用的方法没有事务,这种情况怎么办?是创建一个新的事务还是停止当前方法的进行? 这就是事务的传播行为

传播行为 描述‎
PROPAGATION_REQUIRED 支持当前事务;如果不存在,请创建一个新。‎
PROPAGATION_REQUIRES_NEW ‎创建新事务,暂停当前事务(如果存在)。‎
PROPAGATION_NESTED 如果当前事务存在,则在嵌套事务中执行,否则行为‎‎类似于PROPAGATION_REQUIRED‎‎。‎
PROPAGATION_NEVER 不支持当前事务;如果当前事务存在,则引发异常。‎
PROPAGATION_SUPPORTS ‎支持当前事务;如果不存在,则以非事务方式执行。‎
PROPAGATION_NOT_SUPPORTED 不支持当前事务;而是始终以非事务性方式执行。‎
PROPAGATION_MANDATORY 支持当前事务;如果当前事务不存在,则引发异常。‎

PROPAGATION_REQUIRED

‎支持当前事务;如果不存在,请创建一个新。类似于同名的 EJB 事务属性。‎
‎这通常是事务定义的默认设置,通常定义事务同步作用域。‎

PROPAGATION_REQUIRES_NEW

‎创建新事务,暂停当前事务(如果存在)。类似于同名的 EJB 事务属性。‎
‎注意:‎‎实际的事务暂停不会在所有事务管理器上开箱即用。这尤其适用于‎‎JtaTransactionManager‎‎,它要求将其提供给它(在标准Java EE中是特定于服务器的)。‎javax.transaction.TransactionManager
‎作用域始终定义自己的事务同步。现有同步将被挂起并相应地恢复。

PROPAGATION_NESTED

‎如果当前事务存在,则在嵌套事务中执行,否则行为‎‎类似于PROPAGATION_REQUIRED‎‎。EJB 中没有类似的功能。‎
‎注意:‎‎实际创建嵌套事务仅适用于特定的事务管理器。开箱即用,这仅适用于在处理 JDBC 3.0 驱动程序时的 JDBC ‎‎DataSourceTransactionManager‎‎。某些 JTA 提供程序可能也支持嵌套事务。

PROPAGATION_NEVER

‎不支持当前事务;如果当前事务存在,则引发异常。类似于同名的 EJB 事务属性。‎
‎请注意,事务同步在某个范围内‎‎不可用‎‎。

PROPAGATION_SUPPORTS

‎支持当前事务;如果不存在,则以非事务方式执行。类似于同名的 EJB 事务属性。‎
‎注意:对于具有事务同步功能的事务管理器‎, PROPAGATION_SUPPORTS ‎与完全没有事务略有不同,因为它定义了同步可能适用的事务范围。因此,相同的资源‎ (a JDBC Connection, a Hibernate Session, etc) ‎将在整个指定范围内共享。注意,确切的行为取决于事务管理器的实际同步配置!‎
‎一般而言,使用‎ PROPAGATION_SUPPORTS ‎用心!特别是,不要依赖‎ PROPAGATION_REQUIRED or PROPAGATION_REQUIRES_NEW ‎在‎ PROPAGATION_SUPPORTS‎作用域(这可能会导致运行时的同步冲突)。如果这种嵌套是不可避免的,请确保适当地配置事务管理器(通常切换到“实际事务上的同步”)。‎

PROPAGATION_NOT_SUPPORTED

‎不支持当前事务;而是始终以非事务性方式执行。类似于同名的 EJB 事务属性。‎
‎注意:‎‎实际的事务暂停不会在所有事务管理器上开箱即用。这尤其适用于‎‎JtaTransactionManager‎‎,它要求将其提供给它(在标准Java EE中是特定于服务器的)。‎javax.transaction.TransactionManager
‎请注意,事务同步在某个范围内‎‎不可用‎‎。现有同步将被挂起并相应地恢复。

PROPAGATION_MANDATORY

‎支持当前事务;如果当前事务不存在,则引发异常。类似于同名的 EJB 事务属性。‎
‎请注意,作用域内的事务同步将始终由周围的事务驱动