Mybatis-Spring SqlSesion单例模式处理源码分析

Mybatis-Spring SqlSesion单例模式处理源码分析

概述

之前在读取大量数据操作的数据碰到了一个问题,在同一个线程中读取Mycat中的数据导致Mycat 内存溢出,原因可能是因为资源没能释放,Mybatis执行SQL需要开启一个SqlSesion会话,完成JDBC连接和执行和关闭,而在Spring容器下,同一线程下SqlSession可能没有关闭。从而导致服务端资源不能释放,那Spring在整合Mybatis中完成哪些操作呢,下面一起来看下相关源码的处理。

SqlSessionTemplate 模板类

在Spring 整合Mybatis过程,我们要需要在Spirng 容器注册SqlSessionTemplate Bean,SqlSessionTemplate 封装处理Mapper方法的模板类,在MapperScan注解中被ref引用,此类中有定义内部类SqlSessionInterceptor,用于所有Mapper方法拦截,主要代码逻辑如下

 private class SqlSessionInterceptor implements InvocationHandler {
    @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);
        }
      }
    }
  }

SqlSessionUtil 工具类中获取SqlSession实例逻辑如下

public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {

    notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
    notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);

    SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);

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

    if (LOGGER.isDebugEnabled()) {
      LOGGER.debug("Creating a new SqlSession");
    }

    session = sessionFactory.openSession(executorType);

    registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);

    return session;
  }

TransactionSynchronizationManager.getResource(sessionFactory) 使用事务线程中获取到资源对象 SqlSessionHolder,原理就是使用线程的中ThreadLocal变量。所有在同一个线程下,通过SqlSessionUtil.getSqlSession()获取的实例都是同一个。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值