大家好,又见面了,我是你们的朋友全栈君。
目录
2.1.1、@Import和[@ImportSelector + @ImportBeanDefinitionRegistor ]
2.1.2、InfrastructureAdvisorAutoProxyCreator组件
2.1.3、ProxyTransactionManagementConfiguration组件
前言
事务不会跨线程传播,事务不能跨数据源。
1、@Transactional的使用
- 导入相关依赖,数据源、数据库驱动、Spring-jdbc模块;
- 事务操作加@Transactional;
- 打开事务管理功能,对datasource进行控制;
- 注册事务管理器;
- 配置数据源、JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据;
1.1、实践
//第一步:导入相关数据库依赖;
//第二步:加事务注解;
@Transactional(rollbackFor = {Exception.class})
public void updateAccount(int id) {
int rows = accounMapper.deduction(id);
if (rows > 0) {
System.out.println("秒杀库存修改成功");
insertGoodOrder();
} else {
System.out.println("秒杀修改失败");
}
}
开启事务管理器并注册事务管理器
@Configuration
@ComponentScan("com.king.db")
@EnableTransactionManagement //第三步:开启事务管理功能,让@Transactional生效
public class DataSourceConfig {
//创建数据源 这个c3p0封装了JDBC, dataSource 接口的实现
@Bean
public DataSource dataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("kongyin");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql//localhost:3306/order");
return dataSource;
}
@Bean //第四步:注册事务管理器bean
public PlatformTransactionManager platformTransactionManager() throws PropertyVetoException {
return new DataSourceTransactionManager(dataSource());
}
@Bean //第五步:jdbcTemplate能简化增查改删的操作
public JdbcTemplate jdbcTemplate() throws PropertyVetoException {
return new JdbcTemplate(dataSource());
}
}
或者在spring的xml中配置:
<!--事务管理器配置,market中对双数据源的配置-->
<tx:annotation-driven transaction-manager="transactionManager"/>
//注册事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
<qualifier value="settleTransactionManager"/>
</bean>
可以看到@Transactional的使用非常简单,那么它是如何实现的呢?下面来看一下它的实现原理。
2、@Transactional原理分析
- 思考一:
为什么在方法上加了@Transactional就有了事务能力? - 思考二:
为什么有时候加了@Transactional却不起作用?
@Transactional
public void doInvokeWithTransactional(){
doBusiness()
}
如果在上述方法上添加一个@transactional后的等价操作:
public void doInvokeWithTransactional(){
transactionalManager.beginTranscation; //事务管理器-开启事务-拿到一个事务
autoCommit=false; //关闭事务自动提交,需要手动提交
public void invoke(){
try{
doBusiness(); //执行业务逻辑处理
}cache(Exception e){
Rollback(); //回滚
}
commit(); //提交
}
}
@Transactional的实现我把它大致分为两个阶段:
- 第一阶段:目标方法增强的初始化阶段;
- 第二阶段:目标方法的执行阶段;
2.1、初始化阶段
@
EnableTransactionManagement
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class) //利用Import给容器添加一个Selector组件;
public @interface EnableTransactionManagement {
//使用JDK或者是Cglib动态代理
boolean proxyTargetClass() default false;
//默认事务增强器是什么模式:代理
AdviceMode mode() default AdviceMode.PROXY;
//最低的优先级
int order() default Ordered.LOWEST_PRECEDENCE;
}
2.1.1、@Import和[@ImportSelector + @ImportBeanDefinitionRegistor ]
TransactionManagementConfigurationSelector;
@Import和[ @ImportSelector + @ImportBeanDefinitionRegistor ] 的组合来为容器动态批量添加组件的套路实现。
- ImportSelector是一个接口,只需要实现selectImport()方法,返回的是一个数组,即可给容器批量的注册Bean实例;
- ImportBeanDefinitionRegistor也是一个接口,只需要实现registorBeanDefinition()方法就可以实现给容器添加bean实例;
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
//利用ImportSelector开始往容器中注册2个组件;
return new String[] {
AutoProxyRegistrar.class.getName(), //注册的第一个组件;
ProxyTransactionManagementConfiguration.class.getName()}; //注册的第二个组件
case ASPECTJ:
return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
//AdviceModeImportSelector继承了ImportSelector,说明具有了向容器注册组件的能力;
public abstract class AdviceModeImportSelector<A extends Annotation> implements ImportSelector {
/**
* The default advice mode attribute name.
*/
public static final String DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME = "mode";
protected String[] selectImports(AdviceMode adviceMode) {}
}
从上面可以看出,主要是利用@Import(TransactionManagementConfigurationSelector.class) 给容器导入两个重要的组件:
AutoProxyRegistrar – 创建事务动态代理创建器,给容器创建一个动态代理创建器:InfrastructureAdvisorAutoProxyCreator;
ProxyTransactionManagementConfiguration– 获取事务管理器生成事务拦截器,解析保存事务注解(传播属性-回滚方式)等等;
2.1.2、InfrastructureAdvisorAutoProxyCreator组件
InfrastructureAdvisorAutoProxyCreator
事务动态代理创建器
//通过ImportBeanDefinitionRegistrar给容器中添加组件:InfrastructureAdvisorAutoProxyCreator
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
private final Log logger = LogFactory.getLog(getClass());
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
for (String annoType : annoTypes) {
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
Boolean.class == proxyTargetClass.getClass()) {
candidateFound = true;
if (mode == AdviceMode.PROXY) {//看它给容器中注册了什么组件
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
@Nullable //给容器中添加InfrastructureAdvisorAutoProxyCreator组件
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,Object source) {
//这里开始给容器注册:InfrastructureAdvisorAutoProxyCreator 事务动态代理创建器组件
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
那么InfrastructureAdvisorAutoProxyCreator主要做了什么呢?
InfrastructureAdvisorAutoProxyCreator其实就是实现了spring的后置处理器postProcessor接口,用来
创建增强的实例bean,也就是让doInvokeWithTransaction()方法具备事务的能力。
利用后置处理器机制在对象创建以后,包装对象Bean,返回
一个增强的代理对象,之后通过拦截链来完成调用。
InfrastructureAdvisorAutoProxyCreator这个类的继承关系,最终实现了BeanPostProcessor接口,就是一个后置处理器,用来对我们的业务bean实现增强。
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {}
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
@Nullable //Bean实例前置增强
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable //Bean实例后置增强
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
2.1.3、ProxyTransactionManagementConfiguration组件
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
//开始事务的元数据属性解析
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
//对属性元信息的一些增强,比如在注解中设置的一些参数:传播属性propagation,回滚的条件rollbackFor等等
//@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
//对我们的事务进行属性增强;
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource());
advisor.setAdvice(transactionInterceptor());
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
@Bean//主要用于保存事务属性的信息,封装成一个TransactionInterceptor
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
//开始解析事务的属性值,会发现很多事务属性在这里都有:propagation/isolation/timeout等等
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
//事务传播属性的设置
Propagation propagation = attributes.getEnum("propagation");
rbta.setPropagationBehavior(propagation.value());
//事务的隔离属性的设置
Isolation isolation = attributes.getEnum("isolation");
rbta.setIsolationLevel(isolation.value());
//事务的超时时间设置
rbta.setTimeout(attributes.getNumber("timeout").intValue());
rbta.setReadOnly(attributes.getBoolean("readOnly"));
rbta.setQualifier(attributes.getString("value"));
ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<>();
//事务的回滚条件设置
Class<?>[] rbf = attributes.getClassArray("rollbackFor");
for (Class<?> rbRule : rbf) {
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
//设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚
String[] rbfc = attributes.getStringArray("rollbackForClassName");
for (String rbRule : rbfc) {
RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
Class<?>[] nrbf = attributes.getClassArray("noRollbackFor");
for (Class<?> rbRule : nrbf) {
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
//设置不回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,事务不回滚
String[] nrbfc = attributes.getStringArray("noRollbackForClassName");
for (String rbRule : nrbfc) {
NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
rollBackRules.add(rule);
}
rbta.getRollbackRules().addAll(rollBackRules);
return rbta;
}
到这里:第一就阶段的初始化任务就完成了,核心任务:
2.2、调用执行阶段
//这里拦截后封装成 MethodInterceptor,保存了事务的信息,和aop的逻辑一样
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
@Override
@Nullable //动态代理的调用
public Object invoke(final 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);
}
@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.
//(1):获取(实践第二步中)设置的事务属性信息(propagation = Propagation.REQUIRED, rollbackFor = Exception.class),直接从内存中加载;
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
//(2):获取(实践第四步中)注册的事务管理器-PlatformTransactionManager,加载到容器中;
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.
//(3):得到事务管理器,关闭事务自动提交;
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
//(4): 开始执行目标方法本身doBusiness();
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
//(4.1): 如果执行过程中抛出异常则回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
//(4.2) 如果执行成功,则提交事务;
commitTransactionAfterReturning(txInfo);
return retVal;
}
// (4.1) :回滚事务
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
}
Spring拿到数据库连接池的连接connection后,事务管理器关闭自动提交,通过方法执行的结果的成功和失败判断该事务是提交还是会滚。至此,我们的声明式事务@Transactional就完成了对方法的事务增强,使其具备了事务的能力。
3、事务失效原因分析
为什么有时候加了@Transactional却不起作用?
public class TransactionalTest{
@Transactional
public void doInvokeWithTransactional(){
doBusiness();
enjoy(); //不好意,这里等价于:this.enjoy(),注意,本地调用是不会走动态代理的,不会对enjoy()方法进行增强;所以这里enjoy()的事务会失效;
}
@Transactional
public void enjoy(){
doEnjoy();
}
其他的事务失效的注意点:
final 方法 和 static 方法不能添加事务,加了也不生效
- 1、你的方法是private的话,即使加上@Transactional注解,该注解也无效,不会开启事务,发生异常时不会回滚。
- 2、即使你的方法是public的,但是如果被private的方法调用,@Transactional注解同样也会失效。
:Spring的事务管理默认只对出
现非受检运行期异常(java.lang.RuntimeException及其子类)进行回滚,
Exception:受检异常 – Checked异常
事务@transaction 不回滚
事务不能垮线程传播,否则事务也是不生效的,比如下面代码事务不生效:
@Transactional
@Override
public void save(Order orderInfo ) {
new Thread(() -> {
addOrder(orderInfo); //事务失效,不会垮线程传播;
System.out.println(1 / 0);
}).start();
}
4、小结
所有加了注解的方法都是利用spring的后置处理器,使用对应的处理类对当前的作用域的方法或者类做一个拦截增强处理,返回一个增强的代理类,实现注解的增强功能。
- 创建事务增强的后置处理器,主要用来对目标的方法和类进行增强;;
- 使用动态代理,创建具有事务能力的增强代理类;
- 2.1 通过AOP机制,调用动态增强代理对象的目标方法: CglibAoProxy.
intercept(); - 2.2 获取目标方法事务
拦截器链:也即设置的通知的方法 List<Object> chain = this.advised.getInterceptors()利用拦截器的链式机制,依次进入每一个拦截器通知进行执行;压栈的存储通知方法,再出栈调用通知方法; - 2.3 执行事务拦截器:
TransactionalInterceptor实现了methodInterceptor:调用invokeWithTransaction()函数
AnnotationTransactionAttributeSource
PlatfromTransactionMavager
interceptor().
invoke()
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/129274.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...