@Transactional注解可以用在数据库事务操作的方法上并可以设置事务的相关属性:隔离属性(isolation), 超时属性(timeout), 只读属性(read-only)以及回滚条件,也可以指定事务管理器
Spring创建代理或操纵类字节码来管悝事务的创建、提交和回滚。使用代理方式Spring会忽略内部方法调用事务即使有@Transactional注解也会被忽略,代理需要通过其他类进行调用
例如,一個方法callMethod并标记了 @Transactional注解Spring会包装一些事务管理代码环绕在方法执行过程:
事务注解可以在接口、类或直接在方法上。实际会按照优先级进行覆盖从低到高优先级为:接口、父类、类、接口方法、父类方法、类方法。
对于类级别注解则Spring应用注解设置至所有没有标记注解的public方法,如果在private、protecte方法上使用注解Spring会忽略。
通常不建议在接口上设置事务但在Spring Data @Repository情况下是可行的。这里在类上增加注解覆盖接口或父类的设置:
如果在方法增加注解则覆盖类定义:
传播性定义业务逻辑的事务边界Spring根据传播性设置负责启动或暂停事务。
REQUIRED是缺省属性Spring检查是否囿活动事务,如果没有则创建新的事务否则业务逻辑追加至当前活动事务中:
缺省属性也可以不指定:
SUPPORTS属性,Spring首先检查是否有活动事务存在存在则使用,反之则无事务进行执行。
当属性设置为MANDATORY属性时如果存在活动事务,则使用之反之抛异常,即强制使用事务
NEVER属性的逻辑:如果存在活动事务则抛异常。
如果存在活动事务则Spring首先挂起当前事务然后业务逻辑在无事务下执行。
JTATransactionManager支持开箱即用的事务挂起其他方法通过持有对事务引用,然后从线程上下文中清除它来模拟挂起
REQUIRES_NEW属性,如果存在活动事务则Spring挂起当前事务然后创建新的事務。
对于NESTED属性Spring检查是否存在事务,如果存在则标记保存点意味着如果后续业务执行遇到异常,那么回滚至保存点如果没有活动事务時与REQUIRED属性一样。
隔离属性是ACID ( Atomicity, Consistency, Isolation及 Durability)其中之一隔离描述并发事务应用的更改如何对彼此可见。每种隔离级别防止事务中零个或多个并发副作用:
当Spring创建新事务时缺省隔离级别使用RDBMS,因此改变数据库时应该注意
我们吔应该考虑使用不同隔离属性调用一组方法的场景,正常流程隔离仅应用于新事务创建时因此出于某种原因,不想让一个方法在不同的隔离状态下执行我们必须将TransactionManager::setValidateExistingTransaction设置为true。伪代码如下:
下面看看其他隔离级别
READ_UNCOMMITTED是最低的隔离级别,最大化允许并发访问
它受到上述三种並发性副作用的影响。具有此隔离的事务将读取其他并发事务未提交数据此外不可重复读取和幻读都可能发生。因此我们可以在重新读取行或重新执行范围查询时获得不同的结果可以在方法或类上设置隔离级别:
第二级隔离READ_COMMITTED可以防止脏读,其他并发副作用仍可能发生並发事务的未提交改变没有影响,但已提交的改变再次查询也会改变
第三个隔离级别是REPEATABLE_READ,防止脏读和不可重复读因此不会受并发事务未提交改变影响。当重复查询行不会得到不同结果但可能获得新增记录或删除部分行。
该级别可以防止丢失更新当两个或多个并发事務读并更新相同行会发生丢失更新。REPEATABLE_READ根本不允许同时访问行因此丢失更新不会发生。
SERIALIZABLE 是最高隔离级别可以防止上述所有的问题,但也導致最低并发访问效率因为并发事务按照顺序执行。也就是并发执行一组SERIALIZABLE级别事务与顺序执行结果一样设置代码:
本文我们探讨了事務的传递与隔离属性,并详细解释了不同属性的含义及对并发事务的影响