美文网首页
spring事务和mybatis是如何使用同一个连接

spring事务和mybatis是如何使用同一个连接

作者: 念䋛 | 来源:发表于2022-07-28 10:17 被阅读0次

    我们知道事务是针对同一个connection来说的,先将connection自动提交设置为false,再和数据库交互结束后commit提交事务,spring中提供了简便的注解方式实现事务,事务的源码可以找到connection的自动提交设置为false,但是mybatis真正执行sql语句的时候,如何保证和事务的连接是同一个connection的,如果不是同一个,则不能保证事务.
    事务源码
    org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction


    image.png

    org.springframework.transaction.support.TransactionSynchronizationManager#bindResource
    --org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin
    开始事务的时候会创建connection,将connection自动提交false,后续的bindResource方法中将ConnectionHolder存放到ThreadLocal中


    image.png

    将ConnectionHolder对象,放到TransactionSynchronizationManager的resources成员变量中
    org.springframework.transaction.support.TransactionSynchronizationManager#bindResource

        public static void bindResource(Object key, Object value) throws IllegalStateException {
            Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
            Assert.notNull(value, "Value must not be null");
            Map<Object, Object> map = resources.get();
            // set ThreadLocal Map if none found
            if (map == null) {
                map = new HashMap<>();
                resources.set(map);
            }
    //存储ConnectionHolder
            Object oldValue = map.put(actualKey, value);
            // Transparently suppress a ResourceHolder that was marked as void...
            if (oldValue instanceof ResourceHolder && ((ResourceHolder) oldValue).isVoid()) {
                oldValue = null;
            }
            if (oldValue != null) {
                throw new IllegalStateException(
                        "Already value [" + oldValue + "] for key [" + actualKey + "] bound to thread");
            }
        }
    

    在TransactionSynchronizationManager#doGetResource方法获取ConnectionHolder

        private static Object doGetResource(Object actualKey) {
    //private static final ThreadLocal<Map<Object, Object>> resources =new NamedThreadLocal<>("Transactional resources");
    //resources是ThreadLocal
            Map<Object, Object> map = resources.get();
            if (map == null) {
                return null;
            }
            Object value = map.get(actualKey);
            // Transparently remove ResourceHolder that was marked as void...
            if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
                map.remove(actualKey);
                // Remove entire ThreadLocal if empty...
                if (map.isEmpty()) {
                    resources.remove();
                }
                value = null;
            }
            return value;
        }
    

    执行mybatis执行sql的时候是如何调用TransactionSynchronizationManager#doGetResource方法,从TheadLocal中获取ConnectionHolder的


    image.png

    这里不讲解mybatis的源码,贴出来调用链,可以看到如何从ThreadLocal获取到了ConnectionHolder的
    分析到这可知,从开启事务到sql的执行需要同一个线程,如果执行sql的代码放在多线程中,该sql不能保证在事务里.

    相关文章

      网友评论

          本文标题:spring事务和mybatis是如何使用同一个连接

          本文链接:https://www.haomeiwen.com/subject/jjntwrtx.html