Spring 与 MyBatis

Spring 与 MyBatis

FQA

Spring 数据库连接与 SqlSession 的对应关系

在一个数据库的情况下。在非事务操作中,数据操作时一个连接对应一个SqlSession;在事务操作中,一个连接对应多个SqlSession。

SqlSession 获取流程:

/**
   * Proxy needed to route MyBatis method calls to the proper SqlSession got
   * from Spring's Transaction Manager
   * It also unwraps exceptions thrown by {@code Method#invoke(Object, Object...)} to
   * pass a {@code PersistenceException} to the {@code PersistenceExceptionTranslator}.
   */
  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);
        }
      }
    }
  }

数据库连接(Hikari Connection)获取流程:

getConnection:95, HikariDataSource (com.zaxxer.hikari)
fetchConnection:151, DataSourceUtils (org.springframework.jdbc.datasource)
doGetConnection:115, DataSourceUtils (org.springframework.jdbc.datasource)
getConnection:78, DataSourceUtils (org.springframework.jdbc.datasource)
openConnection:82, SpringManagedTransaction (org.mybatis.spring.transaction)
getConnection:68, SpringManagedTransaction (org.mybatis.spring.transaction)
getConnection:336, BaseExecutor (org.apache.ibatis.executor)
prepareStatement:84, SimpleExecutor (org.apache.ibatis.executor)
doQuery:62, SimpleExecutor (org.apache.ibatis.executor)
queryFromDatabase:324, BaseExecutor (org.apache.ibatis.executor)
query:156, BaseExecutor (org.apache.ibatis.executor)
query:109, CachingExecutor (org.apache.ibatis.executor)
query:83, CachingExecutor (org.apache.ibatis.executor)
selectList:148, DefaultSqlSession (org.apache.ibatis.session.defaults)
selectList:141, DefaultSqlSession (org.apache.ibatis.session.defaults)
selectOne:77, DefaultSqlSession (org.apache.ibatis.session.defaults)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invoke:433, SqlSessionTemplate$SqlSessionInterceptor (org.mybatis.spring)
	-- 关闭数据库连接
	close:245, ProxyConnection (com.zaxxer.hikari.pool)
	close:245, ProxyConnection (com.zaxxer.hikari.pool)
	doCloseConnection:354, DataSourceUtils (org.springframework.jdbc.datasource)
	doReleaseConnection:341, DataSourceUtils (org.springframework.jdbc.datasource)
	releaseConnection:307, DataSourceUtils (org.springframework.jdbc.datasource)
	close:127, SpringManagedTransaction (org.mybatis.spring.transaction)
	close:90, BaseExecutor (org.apache.ibatis.executor)
	close:64, CachingExecutor (org.apache.ibatis.executor)
	close:264, DefaultSqlSession (org.apache.ibatis.session.defaults)
	closeSqlSession:193, SqlSessionUtils (org.mybatis.spring)
	invoke:454, SqlSessionTemplate$SqlSessionInterceptor (org.mybatis.spring)
	selectOne:-1, $Proxy65 (com.sun.proxy)
selectOne:-1, $Proxy65 (com.sun.proxy)
selectOne:166, SqlSessionTemplate (org.mybatis.spring)
execute:82, MapperMethod (org.apache.ibatis.binding)
invoke:59, MapperProxy (org.apache.ibatis.binding)
getById:-1, $Proxy104 (com.sun.proxy)
getById:243, CrmUserDiversionConfServiceImpl (cn.bookln.service.impl)

数据库连接关闭流程:

close:245, ProxyConnection (com.zaxxer.hikari.pool)
doCloseConnection:354, DataSourceUtils (org.springframework.jdbc.datasource)
doReleaseConnection:341, DataSourceUtils (org.springframework.jdbc.datasource)
releaseConnection:307, DataSourceUtils (org.springframework.jdbc.datasource)
close:127, SpringManagedTransaction (org.mybatis.spring.transaction)
close:90, BaseExecutor (org.apache.ibatis.executor)
close:64, CachingExecutor (org.apache.ibatis.executor)
close:264, DefaultSqlSession (org.apache.ibatis.session.defaults)
closeSqlSession:193, SqlSessionUtils (org.mybatis.spring)
invoke:454, SqlSessionTemplate$SqlSessionInterceptor (org.mybatis.spring)
selectOne:-1, $Proxy65 (com.sun.proxy)

2020-02-06 今天在群里看到老哥们讨论一个OOM问题。背景是在一个事务方法中执行循环大数据量查询(100W+),处理过程中导致了OOM。排查原因后得知是由于MyBatis的一级缓存缓存了查询结果,导致GC无法及时释放之前已处理过的数据。在去除事务之后,GC就可以正常回收了。

# Spring  MyBatis 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×