1、摘记
事务的作用
事务操作包含两个目的,数据一致以及操作隔离。
- 数据一致是指事务提交时保证事务内的所有操作都成功完成,并且更改永久生效;事务回滚时,保证能够恢复到事务执行之前的状态。
- 操作隔离则是指多个同时执行的事务之间应该相互独立,互不影响。
隔离级别
MySQL的InnoDB引擎提供四种隔离级别(即ACID中的I):
- 读未提交
(READ UNCOMMITTED)
- 读已提交
(READ COMMITTED)
- 可重复读
(REPEATABLE READ)
- 串行化
(SERIALIZABLE)
InnoDB默认的隔离级别是REPEATABLE READ,其可避免脏读和不可重复读,但不能避免幻读,需要指出的是,InnoDB引擎的多版本并发控制机制(MVCC)并没有完全避免幻读
传播机制
当一个方法开启事务后,在方法中调用了其他的方法,其他方法可能也需要事务管理,此时就涉及事务该如何传播了。
TransactionDefinition.PROPAGATION_REQUIRED
:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。-
TransactionDefinition.PROPAGATION_REQUIRES_NEW
:新建事务,如果当前存在事务,则把当前事务挂起,这个方法会独立提交事务,不受调用者的事务影响,父级异常,它也是正常提交 -
TransactionDefinition.PROPAGATION_SUPPORTS
:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。 TransactionDefinition.PROPAGATION_NOT_SUPPORTED
:以非事务方式运行,如果当前存在事务,则把当前事务挂起。TransactionDefinition.PROPAGATION_NEVER
:以非事务方式运行,如果当前存在事务,则抛出异常,即父级方法必须无事务。-
TransactionDefinition.PROPAGATION_MANDATORY
:如果当前存在事务,则加入该事务;如果当前无事务,则抛出异常,也即父级方法必须有事务 TransactionDefinition.PROPAGATION_NESTED
:如果当前存在事务,它将会成为父级事务的一个子事务,方法结束后并没有提交,只有等父事务结束才提交。如果当前没有事务,则新建事务。如果它异常,父级可以捕获它的异常而不进行回滚,正常提交。但如果父级异常,它必然回滚,这就是和 REQUIRES_NEW 的区别。
保存点
事务中可以设置一些保存点(阶段标识),回滚时可以指定回滚到前面的哪个保存点。
2、事务操作
既然有事务,就少不了有事务管理者,不然用户在进行事务相关操作的时候还需要自己去处理事务,显然不合理。而一个事务管理者应该具有哪些功能呢?通过spring中的源码我们可以知道只有两个主要功能
- 提交
- 回滚
2.1、获取事务
我们要对事务进行操作,首先就是需要获取到对应的事务(也可以认为是何时创建事务)
前置知识点:事务的传播机制(具体查看摘记中对于事务传播机制的介绍)
我们在获取事务时,首先需要判断一下调用者是否已经是一个事务,例如调用者A和被调用者B,A和B同时开启事务,在A调用B时,就知道当前调用者已经有事务了。这时B的事务性如何需要根据事务的传播机制来判断,流程如下,如果A没有事务,那么B就简单多了,直接创建一个事务即可
2.2、提交
因为事务能够保证事务内的所有操作都成功完成,那么我们就应该在所有操作完成后告诉事务管理者,这个事务中的所有操作都好了,此时事务管理者就会进行提交操作。
这里就引出了事务管理者的第一个功能–提交。
在spring中事务管理者顶级抽象接口是TransactionManager
,标识这是一个事务管理者,其中没有定义任何的函数。TransactionManager
的实现接口是PlatformTransactionManager
,这个上定义了
void commit(TransactionStatus status) throws TransactionException;
AbstractPlatformTransactionManager
是定义在spring tx框架上通用的事务管理者,其中提供了很多钩子函数,在其他的框架里中可以自定义其实现类来定义特定的事务管理者。
目前实现的有org.springframework.jdbc.datasource中的DataSourceTransactionManager
,这个事务管理者可以工作在JDBC 驱动程序中
窥探spring AbstractPlatformTransactionManager中的commit函数
前置知识点:
TransactionStatus
:事务状态,其实现了TransactionExecution
和SavepointManager
接口。
其中TransactionExecution
保存的状态值有
isNewTransaction
是否是新事务-
isRollbackOnly
是否仅能回滚 -
isCompleted
是否已完结
SavepointManager
是保存点管理者,可以用来创建保存点,将当前事务回滚到保存点,释放保存点
所以我们在调用commit方法时需要传入TransactionStatus对象,这个对象上保存着当前事务的状态。
进攻源码
接下来进入到processCommit
方法中
这边回调下文再分析,主要是doCommit
函数,但是这个commit
的具体操作函数也是一个钩子函数,需要具体用的地方去进行具体实现,毕竟这里只是通用的函数。大家可以推测出在这个类的所有do字打头的具体工作函数都是需要此类的子类来实现的。
DataSourceTransactionManager
中的实现
可以看到spring实际上就是对于底层所有的事务操作就是提供了兼容性,这里具体的提交操作还是需要调用具体的服务来实现。
2.3、回滚
整体上回滚的操作和提交类似
而具体的回滚操作也是需要具体的子类去进行实现