一、事务的相关概念
事务的四大特性 (ACID)
1.1、原子性:对于事务所进行的数据修改等操作,要么全部执行,要么全部不执行。
1.2、一致性:事务在完成时,必须使所有的数据都保持一致状态,而且在相关数据中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构都应该是正确的。
1.3、隔离性: 并发访问数据库时,一个用户的事物不被其他事物所干扰,各并发事务之间数据库是独立的。
1.4、持久性: 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
二、Spring 事务管理的核心接口
1、PlatformTransactionManager
通过上图可以看到,Spring并不直接管理实务,而是提供多种事务管理器,将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。
进入到PlatformTransactionManager接口:
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition var1) throws TransactionException; // 由TransactionDefinition得到TransactionStatus对象,事务管理器 通过TransactionDefinition,获得“事务状态”,从而管理事务。
void commit(TransactionStatus var1) throws TransactionException; //提交事务
void rollback(TransactionStatus var1) throws TransactionException; //回滚事务
}
2、TransactionStatus
上面的getTransaction方法返回的是TransactionStatus对象,这个接口用来记录事务的状态,该接口定义了一组方法,用来获取或判断事务的相应状态信息,查看TransactionStatus源码:
public interface TransactionStatus extends SavepointManager, Flushable {
boolean isNewTransaction(); //是否是新的事务
boolean hasSavepoint(); //是否有保存点
void setRollbackOnly(); //设置回滚
boolean isRollbackOnly(); //是否回滚
void flush(); //刷新
boolean isCompleted(); //是否完成
}
这个接口描述的是一些处理事务提供简单的控制事务执行和查询事务状态的方法,在回滚或提交的时候需要应用对应的事务状态。
3、TransactionDefinition
上面的事务管理器接口PlatformTransactionManager通过getTransaction(TransactionDefinition definition)方法来得到事务,这个方法里面的参数是TransactionDefinition类,这个类就定义了一些基本的事务属性。
事务属性可以理解成事务的一些基本配置,描述了事务策略如何应用到方法上。事务属性包含了5个方面,
观察源码:
public interface TransactionDefinition {
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = 1;
int ISOLATION_READ_COMMITTED = 2;
int ISOLATION_REPEATABLE_READ = 4;
int ISOLATION_SERIALIZABLE = 8;
int TIMEOUT_DEFAULT = -1;
int getPropagationBehavior();// 返回事务的传播行为
int getIsolationLevel();// 返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据
int getTimeout();// 返回事务必须在多少秒内完成
boolean isReadOnly();// 返回是否优化为只读事务。
String getName(); //返回事务的名字
}
3.1、传播行为
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
这7种是传播行为,具体使用场景如下
①、PROPAGATION_REQUIRED :required ,必须。默认值,A如果有事务,B将使用该事务;如果A没有事务,B将创建一个新的事务。
②、PROPAGATION_SUPPORTS:supports ,支持。A如果有事务,B将使用该事务;如果A没有事务,B将以非事务执行。
③、PROPAGATION_MANDATORY:mandatory ,强制。A如果有事务,B将使用该事务;如果A没有事务,B将抛异常。
④、PROPAGATION_REQUIRES_NEW :requires_new,必须新的。如果A有事务,将A的事务挂起,B创建一个新的事务;如果A没有事务,B创建一个新的事务。
⑤、PROPAGATION_NOT_SUPPORTED :not_supported
,不支持。如果A有事务,将A的事务挂起,B将以非事务执行;如果A没有事务,B将以非事务执行。
⑥、PROPAGATION_NEVER:never,从不。如果A有事务,B将抛异常;如果A没有事务,B将以非事务执行。
⑦、PROPAGATION_NESTED:nested ,嵌套。A和B底层采用保存点机制,形成嵌套事务。
3.2、事务隔离级别:定义了一个事务可能受其他并发事务影响的程度
并发事务带来的问题:
脏读: 所谓脏读就是一个事务A读取了另一个事务B尚未提交的数据,并且B事务可能发生回滚,这样A事务就放声脏读。
不可重复读: 一个事务多次读取的结果不一致,导致这种现象的原因是另一个并发事务在两次查询时进行了更新。
幻读: 幻读与不可重复读类似。它发生在一个事务(A)读取了几行数据,接着另一个并发事务(B)插入了一些数据时。在随后的查询中,第一个事务(A)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。幻读与不可重复读的区别在于:不可重复读的重点是修改,幻读的重点在于新增或者删除。
TransactionDefination中定义的事务隔离级别:
①、ISOLATION_DEFAULT:使用后端数据库默认的隔离级别
②、ISOLATION_READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
③、ISOLATION_READ_COMMITTED:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
④、ISOLATION_REPEATABLE_READ:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生
⑤、ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从ACID的隔离级别,确保阻止脏读、不可重复读以及幻读,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的
3.3、事务只读
事务的只读属性是指,对事务性资源进行只读操作或者是读写操作。所谓事务性资源就是指那些被事务管理的资源,比如数据源、 JMS 资源,以及自定义的事务性资源等等。如果确定只对事务性资源进行只读操作,那么我们可以将事务标志为只读的,以提高事务处理的性能。在 TransactionDefinition 中以 boolean 类型来表示该事务是否只读。
3.4、事务超时
所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。
3.5、回滚规则
这些规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚(这一行为与EJB的回滚行为是一致的)。
但是你可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。
Spring 编程式事务和声明式事务的区别
编程式事务处理:所谓编程式事务指的是通过编码方式实现事务,允许用户在代码中精确定义事务的边界。即类似于JDBC编程实现事务管理。管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。
声明式事务处理:管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。
简单地说,编程式事务侵入到了业务代码里面,但是提供了更加详细的事务管理;而声明式事务由于基于AOP,所以既能起到事务管理的作用,又可以不影响业务代码的具体实现。