4.spring篇-事务

7 篇文章 0 订阅

1、spring事务理解

1.1 管理的简单api调用方式示例

maven依赖

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.0.10.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.30</version>
        </dependency>

示例代码

package com;

import com.mysql.jdbc.Driver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.sql.Connection;

/**
 * @author yinyuming
 * @date 2021-06-08 11:45
 */
public class SpringTest {
    public static void main(String[] args) throws Exception {
        //1、初始化数据源
        SimpleDriverDataSource simpleDriverDataSource = new SimpleDriverDataSource(new Driver(), "jdbc:mysql://127.0.0.1:3306/yymb?useUnicode=true&characterEncoding=utf-8");
        simpleDriverDataSource.setPassword("123456");
        simpleDriverDataSource.setUsername("root");
        //2、初始化事务管理器
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(simpleDriverDataSource);

        //开启事务
        TransactionStatus transaction = null;
        try {
            transaction = transactionManager.getTransaction(new DefaultTransactionDefinition());

            //以下代码块,就可以认为是其他地方获取的连接了,如mybatis等拿到的都是相同的连接
            {
                //通过DataSourceUtils获取连接
                Connection connection1 = DataSourceUtils.getConnection(simpleDriverDataSource);
                //通过DataSourceUtils获取连接
                Connection connection2 = DataSourceUtils.getConnection(simpleDriverDataSource);
                //上下文获取的连接,connection2和connection1获取到的是相同的连接
                System.out.println(connection2 == connection1);
            }

            //关闭事务
            transactionManager.commit(transaction);
        }catch (Exception ex){
            if(transaction !=null){
                transactionManager.rollback(transaction);
            }
        }
    }
}

1.2 上下文获取的连接为同一个的原理

主要核心类org.springframework.transaction.support.ransactionSynchronizationManager存放这ThreadLocal,线程变量,上下文中都是通过该变量获取数据

1、获取上下文连接:TransactionSynchronizationManager.getResource(dataSource)
2、绑定上下文连接:TransactionSynchronizationManager.bindResource(dataSource, txObject.getConnectionHolder());
  • DataSourceUtils.getConnection(simpleDriverDataSource)中就是通过TransactionSynchronizationManager获取的连接
  • transactionManager.getTransaction(new DefaultTransactionDefinition())中就是通过TransactionSynchronizationManager.bindResource(dataSource, txObject.getConnectionHolder()) 绑定上下文的

2 spring事务管理理解,加入mybatis 事务管理

2.1、mybatis使用spring提供的事务管理工厂

源码入口:SqlSessionFactoryBean的buildSqlSessionFactory方法
mybatis事务管理接口TransactionFactory,(mybatis初始化DefaultSqlSessionFactory会话工厂就是通过事务工厂获取事务的),通过SpringManagedTransactionFactory事务工厂继承了TransactionFactory接口,所以核心功能就是SpringManagedTransactionFactory这个spring的事务管理入口,该类生成了SpringManagedTransaction事务类,对mybatis获取的事务就是这个类,用于执行sql。
总结:SpringManagedTransactionFactory就是spring扩展mybatis事务类。

  • SpringManagedTransaction 这个类的属性
    持有,数据源,数据库连接,
    private final DataSource dataSource;
    private Connection connection;
    private boolean isConnectionTransactional;
    private boolean autoCommit;
    private void openConnection() throws SQLException {
        this.connection = DataSourceUtils.getConnection(this.dataSource);
        .....省略
    }

2.2、spring提供给mybatis的事务工厂,通过数据源中获取连接或者通过TransactionSynchronizationManager获取连接

能看到这个类获取的数据库连接是通过DataSourceUtils获取的,静态方法,通过dataSource中获取连接,然后放到TransactionSynchronizationManager的ThreadLocal线程变量中
这样一个线程中,就可以获取到相同的一个数据库连接了

public abstract class TransactionSynchronizationManager {
	private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);

	private static final ThreadLocal<Map<Object, Object>> resources =
			new NamedThreadLocal<>("Transactional resources");

	private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
			new NamedThreadLocal<>("Transaction synchronizations");

	private static final ThreadLocal<String> currentTransactionName =
			new NamedThreadLocal<>("Current transaction name");

	private static final ThreadLocal<Boolean> currentTransactionReadOnly =
			new NamedThreadLocal<>("Current transaction read-only status");

	private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
			new NamedThreadLocal<>("Current transaction isolation level");

	private static final ThreadLocal<Boolean> actualTransactionActive =
			new NamedThreadLocal<>("Actual transaction active");
....省略
}

2.3、spring 事务处理器,DataSourceTransactionManager,维护和使用TransactionSynchronizationManager的事务,aop代理后,用户开启事务,提交事务等

下面是一些核心源码,位置TransactionAspectSupport.invokeWithinTransaction ,aop切入后的方法

	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 = null;
			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();
			}
			catch (Throwable ex) {
				// target invocation exception
				//回滚事务  
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				cleanupTransactionInfo(txInfo);
			}
			//提交事务  
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}
		
		....省略		
}

源码中最终是用到事务管理器,PlatformTransactionManager这个引用值,我们用DataSourceTransactionManager这个实现类,也是维护和使用TransactionSynchronizationManager的事务的。
所以原理是通过ThreadLocal,拿到上下文的数据库连接,做一些数据库事务的提交和回滚等。

3、声明式事务

上面讲了连接如何传递上下文的,下面讲一下spring声明式事务的源码流程,核心入口@EnableTransactionManagement
下图参考:https://www.cnblogs.com/dennyzhangdd/p/9602673.html#_label2_0
在这里插入图片描述

注解配置一些相关的代理方式,

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

    //proxyTargetClass = false表示是JDK动态代理支持接口代理。true表示是Cglib代理支持子类继承代理。
    boolean proxyTargetClass() default false;

    //事务通知模式(切面织入方式),默认代理模式(同一个类中方法互相调用拦截器不会生效),可以选择增强型AspectJ
    AdviceMode mode() default AdviceMode.PROXY;

    //连接点上有多个通知时,排序,默认最低。值越大优先级越低。
    int order() default Ordered.LOWEST_PRECEDENCE;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值