前言
事务 - transaction,指在数据库操作中,将几个操作视作一个整体,要么全部完成,要么全不完成。
本文简单介绍在 Spring
中如何使用事务。
使用事务的两种方式
声明式
使用注解 @Transactional
,对业务代码入侵小。
Spring
负责事务的开启、提交、回滚以及资源管理,我们只需关注业务逻辑。
粒度:方法。
编程式
注入 TransactionTemplate
,或者 PlatformTransactionManager
。
可以实现更细粒度的事务控制,比如对某个代码块加上事务。
粒度:代码块。
两个抽象
对事务动作的抽象
PlatformTransactionManager
抽象了事务的三个动作:
- 获取事务
- 提交事务
- 回滚事务
public interface PlatformTransactionManager {
TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
对事务属性的抽象
抽象了事务的七个属性:
- 传播行为
- 隔离级别
- 超时时间
- 是否只读
- 事务名称
- 事务管理器的名称
- 需要回滚的异常
public interface TransactionDefinition {
int getPropagationBehavior();
int getIsolationLevel();
int getTimeout();
boolean isReadOnly();
String getName();
}
public interface TransactionAttribute extends TransactionDefinition {
String getQualifier();
boolean rollbackOn(Throwable ex);
}
两个注解
@EnableTransactionManagement
- 开启Spring
事务管理,加在启动类上@Transactional
- 标记需要事务管理的 类/接口/方法,加在需要事务管理的 类/接口/方法 上
@EnableTransactionManagement
@EnableTransactionManagement
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
// 是否代理类,只有 mode == AdviceMode.PROXY 该属性有意义。
//(1)proxyTargetClass == true, 实现 subclass-based CGLIB;
//(2)proxyTargetClass == false, 实现 interface-based JDK dynamic proxy;
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
}
AutoProxyRegistrar
注册了一个 AbstractAutoProxyCreator
:
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/**
* Register, escalate, and configure the standard auto proxy creator (APC) against the
* given registry. Works by finding the nearest annotation declared on the importing
* {@code @Configuration} class that has both {@code mode} and {@code proxyTargetClass}
* attributes. If {@code mode} is set to {@code PROXY}, the APC is registered; if
* {@code proxyTargetClass} is set to {@code true}, then the APC is forced to use
* subclass (CGLIB) proxying.
* <p>Several {@code @Enable*} annotations expose both {@code mode} and
* {@code proxyTargetClass} attributes. It is important to note that most of these
* capabilities end up sharing a {@linkplain AopConfigUtils#AUTO_PROXY_CREATOR_BEAN_NAME
* single APC}. For this reason, this implementation doesn't "care" exactly which
* annotation it finds -- as long as it exposes the right {@code mode} and
* {@code proxyTargetClass} attributes, the APC can be registered and configured all
* the same.
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
for (String annType : annTypes) {
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (candidate == null) {
continue;
}
Object mode = candidate.get("mode");
Object proxyTargetClass = candidate.get("proxyTargetClass");
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
Boolean.class == proxyTargetClass.getClass()) {
candidateFound = true;
if (mode == AdviceMode.PROXY) {
// 向容器注册了 InfrastructureAdvisorAutoProxyCreator
// InfrastructureAdvisorAutoProxyCreator 会向容器注册类型为 Infrastructure 的 advisor
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
}