spring如何管理mybatis(二) ----- SqlSession的线程安全性

  在之前的文章中我们了解到最终的数据库最终操作是走的代理类的方法:

 @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      SqlSession sqlSession = getSqlSession(
          SqlSessionTemplate.this.sqlSessionFactory,
          SqlSessionTemplate.this.executorType,
          SqlSessionTemplate.this.exceptionTranslator);
      try {
        Object result = method.invoke(sqlSession, args);
        if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
          // force commit even on non-dirty sessions because some databases require
          // a commit/rollback before calling close()
          sqlSession.commit(true);
        }
        return result;
      } catch (Throwable t) {
        Throwable unwrapped = unwrapThrowable(t);
        if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
          // release the connection to avoid a deadlock if the translator is no loaded. See issue #22
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
          sqlSession = null;
          Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
          if (translated != null) {
            unwrapped = translated;
          }
        }
        throw unwrapped;
      } finally {
        if (sqlSession != null) {
          closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
        }
      }
    }

我们可以看到每次都是使用getSqlSession()来获取真是sqlsession的,而获取的sqlSession又是DefaultSqlSession,这个类我们知道他是线程不安全的,之前使用都是采用多实例模式,就是每次使用都new一个,但是spring采用了更加聪明的方式可以使它不需要每次new一个也可以保持线程安全。

public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
      SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);

    SqlSession session = sessionHolder(executorType, holder);
    if (session != null) {
      return session;
    }
    session = sessionFactory.openSession(executorType);

    registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);

    return session;
  }

我们看到

TransactionSynchronizationManager.getResource(sessionFactory)

 这个方法,他的作用主要是在当前线程的事务管理中获取一个session的持有者。

sessionHolder(executorType, holder)

 这个方法,他的作用是获取一个session资源,并进行登记。

 如果没有获取到session,就会自己创建一个并执行

registerSessionHolder

这个方法,将创建的session试图放进当前的线程上下文中。

private static void registerSessionHolder(SqlSessionFactory sessionFactory, ExecutorType executorType,
      PersistenceExceptionTranslator exceptionTranslator, SqlSession session) {
    SqlSessionHolder holder;
    if (TransactionSynchronizationManager.isSynchronizationActive()) {
      Environment environment = sessionFactory.getConfiguration().getEnvironment();
      if (environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) {
        holder = new SqlSessionHolder(session, executorType, exceptionTranslator);
        TransactionSynchronizationManager.bindResource(sessionFactory, holder);
        TransactionSynchronizationManager.registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory));
        holder.setSynchronizedWithTransaction(true);
        holder.requested();
      }
}

我们重点看看这个方法,首先

TransactionSynchronizationManager.isSynchronizationActive()
    public static boolean isSynchronizationActive() {
        return (synchronizations.get() != null);
    }

这个方法主要判断当前线程的synchronizations是不是有值的,那这个值得初始化在哪里呢,他的初始化发生在事务拦截器中,当创建一个事务时会为当前的线程添加synchronizations,当该事务结束时会将他清空。

  

        holder = new SqlSessionHolder(session, executorType, exceptionTranslator);
        TransactionSynchronizationManager.bindResource(sessionFactory, holder);
        TransactionSynchronizationManager.registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory));
        holder.setSynchronizedWithTransaction(true);
        holder.requested();

接下来的就是创建一个session的持有者,然后把他绑定到当前的事务管理中,这样只要是在该事务中的事务操作都可以使用这个sqlsession,因为他们一定是在同一线程,他们的动作一定是互斥的,这样可以保证线程的安全性。

综上所述,我们可以总结下,当我们的程序被spring的事务管理时,程序中的数据库操作可以使用同一个SqlSession,而不会产生线程安全问题。

  

原文地址:https://www.cnblogs.com/zcmzex/p/9005194.html

时间: 2024-08-10 20:17:57

spring如何管理mybatis(二) ----- SqlSession的线程安全性的相关文章

Synchronized锁在Spring事务管理下,为啥还线程不安全?

大年初二,朋友问了我一个技术的问题(朋友实在是好学,佩服!) 开启10000个线程,每个线程给员工表的money字段[初始值是0]加1,没有使用悲观锁和乐观锁,但是在业务层方法上加了synchronized关键字,问题是代码执行完毕后数据库中的money 字段不是10000,而是小于10000 问题出在哪里? Service层代码:SQL代码(没有加悲观/乐观锁):用1000个线程跑代码:简单来说:多线程跑一个使用synchronized关键字修饰的方法,方法内操作的是数据库,按正常逻辑应该最终

Java并发编程原理与实战二十:线程安全性问题简单总结

一.出现线程安全性问题的条件 •在多线程的环境下 •必须有共享资源 •对共享资源进行非原子性操作 二.解决线程安全性问题的途径 •synchronized (偏向锁,轻量级锁,重量级锁) •volatile •JDK提供的原子类 •使用Lock(共享锁,排它锁) 三.认识的“*锁” •偏向锁 Java偏向锁(Biased Locking)是Java6引入的一项多线程优化. 偏向锁,顾名思义,它会偏向于第一个访问锁的线程,如果在运行过程中,同步锁只有一个线程访问,不存在多线程争用的情况,则线程是不

spring如何管理mybatis(一) ----- 动态代理接口

问题来源 最近在集成spring和mybatis时遇到了很多问题,从网上查了也解决了,但是就是心里有点别扭,想看看到底怎么回事,所以跟了下源码,终于发现了其中的奥妙. 问题分析 首先我们来看看基本的配置. spring的配置: <!-- 数据库配置 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="

Spring事务管理(二)

声明式事务管理方式一:基于TransactionProxyFactoryBean的方式(不常用,需要对每个要进行增强的类进行配置TransactionProxyFactoryBean) 1.引入xml配置约束 2. 声明式事务管理方式二:基于AspectJ的XML方式的配置:(经常使用,一旦配置好,类上不需要添加任何东西) 1.引入xml配置约束 2.  声明式事务管理方式三:基于注解的方式(经常使用,配置简单,但是需要在业务层类上添加@Transactional的注解) 1. 2.只要在需要进

使用ThreadLocal管理Mybatis中SqlSession对象

转自http://blog.csdn.net/qq_29227939/article/details/52029065 public class MybatisUtil { private static SqlSessionFactory factory; // 解决资源争抢问题. private static ThreadLocal<SqlSession> localSessions = new ThreadLocal<SqlSession>(); static { Reader

android 进程/线程管理(二)----关于线程的迷思

一:进程和线程的由来 进程是计算机科技发展的过程的产物. 最早计算机发明出来,是为了解决数学计算而发明的.每解决一个问题,就要打纸带,也就是打点. 后来人们发现可以批量的设置命令,由计算机读取这些命令,并挨个执行. 在使用的过程中,有一个问题,如果要做I/O操作,是非常耗时的,这个时候CPU是闲着的,这对于计算机资源是一个巨大的浪费. 于是,人们发明了进程这个东西.每个程序就是一个进程,由操作系统管理,当进行复杂的耗时操作是,CPU可以调度处理其他的进程,从而是性能在整体上提高. 线程的目的:

7.Spring:整合Mybatis

MyBatis-Spring学习 引入Spring之前需要了解mybatis-spring包中的一些重要类: http://www.mybatis.org/spring/zh/index.html 什么是 MyBatis-Spring? MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中. 知识基础 在开始使用 MyBatis-Spring 之前,你需要先熟悉 Spring 和 MyBatis 这两个框架和有关它们的术语.这很重要 MyBatis-Spr

Spring Boot 结合 Mybatis 解决多数据源的问题

最近在研究Spring Cloud搭建微服务相关,对于一个庞大的系统,需要拆分为多个微服务,每个服务相当于一个模块,负责不同的事情,各司其职,当然,数据库之间也需要保持相对独立,这样就需要涉及到多个数据库,那么,如何使用Spring Boot配置多数据源呢? 首先,我们需要一个自定义注解,命名为:DataSource @Retention(RetentionPolicy.RUNTIME)//将该注解定义在运行时级别@Target(ElementType.METHOD)//将该注解应用于方法上pu

mybatis源码分析(四) mybatis与spring事务管理分析

mybatis源码分析(四) mybatis与spring事务管理分析 一丶从jdbc的角度理解什么是事务 从mysql获取一个连接之后, 默认是自动提交, 即执行完sql之后, 就会提交事务. 这种事务的范围是一条sql语句. 将该连接设置非自动提交, 可以执行多条sql语句, 然后由程序决定是提交事务, 还是回滚事务. 这也是我们常说的事务. Connection connection = dataSource.getConnection(); // connection.setTransa