spring(六):事务
事务特性ACID
- 原子性(Atomicity):即事务是不可分割的最小工作单元,事务内的操作要么全做,要么全不做;
- 一致性(Consistency):在事务执行前数据库的数据处于正确的状态,而事务执行完成后数据库的数据还是处于正确的状态,即数据完整性约束没有被破坏。
- 隔离性(Isolation):并发事务执行之间无影响,在一个事务内部的操作对其他事务是不产生影响,这需要事务隔离级别来指定隔离性;
- 持久性(Durability):事务一旦执行成功,它对数据库的数据的改变必须是永久的,不会因比如遇到系统故障或断电造成数据不一致或丢失。
常见的问题
- 丢失更新:两个事务同时更新一行数据,最后一个事务的更新会覆盖掉第一个事务的更新,从而导致第一个事务更新的数据丢失,这是由于没有加锁造成的
- 脏读:一个事务看到了另一个事务未提交的更新数据
- 不可重复读:在同一事务中,多次读取同一数据却返回不同的结果(也就是有其他事务更改了这些数据)
- 幻读:一个事务在执行过程中读取到了另一个事务已提交的插入数据(即在第一个事务开始时读取到一批数据,但此后另一个事务又插入了新数据并提交,此时第一个事务又读取这批数据但发现多了一条,即好像发生幻觉一样)
事务隔离级别
- 未提交读(Read Uncommitted):最低隔离级别,一个事务能读取到别的事务未提交的更新数据,很不安全,可能出现丢失更新、脏读、不可重复读、幻读;
- 提交读(Read Committed):一个事务能读取到别的事务提交的更新数据,不能看到未提交的更新数据,不可能可能出现丢失更新、脏读,但可能出现不可重复读、幻读;
- 可重复读(Repeatable Read):保证同一事务中先后执行的多次查询将返回同一结果,不受其他事务影响,可能可能出现丢失更新、脏读、不可重复读,但可能出现幻读;
- 序列化(Serializable):最高隔离级别,不允许事务并发执行,而必须串行化执行,最安全,不可能出现更新、脏读、不可重复读、幻读。
隔离级别越高,数据库事务并发执行性能越差,能处理的操作越少。在实际项目开发中为了考虑并发性能一般使用提交读隔离级别,它能避免丢失更新和脏读,尽管不可重复读和幻读不能避免,但可以在可能出现的场合使用悲观锁或乐观锁来解决这些问题。
事务管理器
Spring框架支持事务管理的核心是事务管理器,通过实现策略接口PlatformTransactionManager支持各种数据访问框架的事务管理。
Spring 支持两种类型的事务管理:
- 编程式事务管理 :这意味着你在编程的帮助下有管理事务。这给了你极大的灵活性,但却很难维护。
- 声明式事务管理 :这意味着你从业务代码中分离事务管理。你仅仅使用注释或 XML 配置来管理事务。
public interface PlatformTransactionManager {
// 根据给定的TransactionDefinition类型参数获取一个已经激活的事务或创建一个新的事务
// 返回值TransactionStatus对象代表了当前事务的状态
TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
// 提交TransactionStatus参数代表的事务
void commit(TransactionStatus var1) throws TransactionException;
// 回滚TransactionStatus参数代表的事务
void rollback(TransactionStatus var1) throws TransactionException;
}
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(); // 获取事务是否是只读的
@Nullable
String getName(); // 获取事务名字
}
public interface TransactionStatus extends SavepointManager, Flushable {
boolean isNewTransaction(); // 当前事务状态是否是新事务
boolean hasSavepoint(); // 当前事务是否有保存点
void setRollbackOnly(); // 设置当前事务应该回滚
boolean isRollbackOnly(); // 当前事务是否应该回滚
void flush(); // 刷新底层会话中的修改到数据库
boolean isCompleted(); // 当前事务否已经完成
}
声明式事务处理的实现分析
声明式事务的实现就是通过环绕增强的方式,在目标方法执行之前开启事务,在目标方法执行之后提交或者回滚事务。
- 读取和处理在IoC容器中配置的事务处理属性,并转化为事务处理幼的数据结构(TransactionAttribute)(使用通知器TransactionAttributeSourceAdvisor来完成事务处理属性的处理,和TransactionProxyFactoryBean拦截下来的事务方法的处理结合起来)
- 实现统一的事务处理过程,包含处理事务配置属性和与线程绑定完成事务处理的过程。(TransactionInfo和TransactionStatus记录和传递相关执行场景)
- 底层的事务处理实现。即PlatformTransactionManager接口的具体实现。
事务处理拦截器的配置
// TransactionProxyFactoryBean
@Override
// 在IoC容器完成bean的依赖注入时,通过bean的初始化方法被调用
// 自此,transactionInterceptor配置被启动并成为通知器Advisor的一部分
protected Object createMainInterceptor() {
...
if (this.pointcut != null) {
return new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);
}
else {
// Rely on default pointcut.
return new TransactionAttributeSourceAdvisor(this.transactionInterceptor);
}
}
// AbstractSingletonProxyFactoryBean
// 是事务处理完成aop配置的地方
public void afterPropertiesSet() {
// 检测bean
...else {
...
// 创建代理工厂对象
ProxyFactory proxyFactory = new ProxyFactory();
// 为ProxyFactory生成代理对象、配置通知器、设置代理接口
// 自此,拦截器被配置进代理对象中
proxyFactory.addAdvisor(...);
...
proxyFactory.setInterfaces(...);
this.postProcessProxyFactory(proxyFactory);
this.proxy = proxyFactory.getProxy(this.proxyClassLoader);
}
}
事务处理配置的读入
在TransactionInterceptor进行依赖注入时,其父类TransactionAspectSupport设置TransactionAttribute。
public void setTransactionAttributes(Properties transactionAttributes) {
NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();
tas.setProperties(transactionAttributes);
this.transactionAttributeSource = tas;
}
public void setProperties(Properties transactionAttributes) {
TransactionAttributeEditor tae = new TransactionAttributeEditor();
Enumeration<?> propNames = transactionAttributes.propertyNames();
while (propNames.hasMoreElements()) {
String methodName = (String) propNames.nextElement();
String value = transactionAttributes.getProperty(methodName);
tae.setAsText(value);
TransactionAttribute attr = (TransactionAttribute) tae.getValue();
addTransactionalMethod(methodName, attr);
}
}
事务处理拦截器的设计与实现
// TransactionInterceptor
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
// TransactionAspectSupport
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// 根据事务属性决定采用的事务处理器
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
// 创建事务 ★
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
// 沿着拦截器链进行
retVal = invocation.proceedWithInvocation();
}...
finally {
// 事务信息更新
cleanupTransactionInfo(txInfo);
}
// 提交事务<<PlatformTransactionManager>>
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
final ThrowableHolder throwableHolder = new ThrowableHolder();
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
try {
return invocation.proceedWithInvocation();
}
catch (Throwable ex) {
if (txAttr.rollbackOn(ex)) {
// A RuntimeException: will lead to a rollback.
...
}
else {
// A normal return value: will lead to a commit.
...
}
}
finally {
cleanupTransactionInfo(txInfo);
}
});
// Check result state: It might indicate a Throwable to rethrow.
...
return result;
}
...
}
}
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
// If no name specified, apply method identification as transaction name.
if (txAttr != null && txAttr.getName() == null) {
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
public String getName() {
return joinpointIdentification;
}
};
}
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
// 获取事务对象,创建TransactionStatus对象
status = tm.getTransaction(txAttr);
}
...
}
// 把TransactionStatus设置到TransactionInfo中,并绑定到当前线程
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
本文来自博客园,作者:白芷呀,转载请注明原文链接:https://www.cnblogs.com/angelica-duhurica/p/11195133.html