可以看到Mapper是一个MapperProxy的代理类
执行mapper的方法最终会进入MapperProxy的invoke方法
进入MapperMethods#execute。以select为例
result = sqlSession.selectOne(command.getName(), param);这个sqlSession是一个SqlSessionTemplate
SqlSessionTemplate#selectOne publicT selectOne(String statement, Object parameter) { return this.sqlSessionProxy.selectOne(statement, parameter); }
sqlSessionProxy也是被代理了,这个方法会进入
SqlSessionInterceptor#invoke方法
首先会获取到一个sqlSession,这个sqlSession是DefaultSqlSession。接着就会真正调用
DefaultSqlSession的selectOne方法。这里先跳过
之所以spring会用代理包了一层,就是因为后面几句话。spring用自己的事务管理器来管理事务。
if (!SqlSessionUtils.isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) { sqlSession.commit(true); }
如果没有事务,那么就会直接提交事务。并且最后会直接销毁sql,
SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
进入这个方法:
public static void closeSqlSession(SqlSession session, SqlSessionFactory sessionFactory) { Assert.notNull(session, "No SqlSession specified"); Assert.notNull(sessionFactory, "No SqlSessionFactory specified"); SqlSessionHolder holder = (SqlSessionHolder)TransactionSynchronizationManager.getResource(sessionFactory); if (holder != null && holder.getSqlSession() == session) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Releasing transactional SqlSession [" + session + "]"); } holder.released(); } else { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Closing non transactional SqlSession [" + session + "]"); } session.close(); } }
如果没有开启事务,会走到else分支,session是被关闭了
所以当我们没有开启事务的时候,在一个service中执行个数据库操作,是属于三个不同的sqlSession。
如果我们开启事务,
SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
方法会进入if分支。这里并没有关闭session
我们找到
SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
点击进去
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) { Assert.notNull(sessionFactory, "No SqlSessionFactory specified"); Assert.notNull(executorType, "No ExecutorType specified"); SqlSessionHolder holder = (SqlSessionHolder)TransactionSynchronizationManager.getResource(sessionFactory); SqlSession session = sessionHolder(executorType, holder); if (session != null) { return session; } else { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Creating a new SqlSession"); } session = sessionFactory.openSession(executorType); registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session); return session; } }
发现sqlSession会先从缓存中获取。
----------------
解释了半天,其实就是说明一个现象,如果开启了事务,那么只要是一个service中的所有数据库操作都属于一个sqlsession,反之则不是。。这个很容易验证,开启debug日志模式,看一看打出的sql就知道了,如果都用一个sqlSession,同样的sql是可以利用一级缓存的。
----------------------------
话说回来,接着看找到DefaultSqlSession的#selectList方法
@Override publicList selectList(String statement, Object parameter, RowBounds rowBounds) { try { MappedStatement ms = configuration.getMappedStatement(statement); return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER); } catch (Exception e) { throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
首先会根据id获取到Mappedstatment,其实就可以理解成sql。然后用executor去执行。mybatis中的Executor有一个装饰器模式在里面,这这里会进入CacheExecutor
BoundSql boundSql = ms.getBoundSql(parameterObject); CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql); return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
很明显,CacheExecutor对SimpleExecutor的功能进行了增强
进入query方法
@Override publicList query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { Cache cache = ms.getCache(); if (cache != null) { flushCacheIfRequired(ms); if (ms.isUseCache() && resultHandler == null) { ensureNoOutParams(ms, boundSql); @SuppressWarnings("unchecked") List list = (List ) tcm.getObject(cache, key); if (list == null) { list = delegate. query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); tcm.putObject(cache, key, list); // issue #578 and #116 } return list; } } return delegate. query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
----->
BaseExecutor#query ----->
BaseExecutor#queryFromDatabase------------>
SimpleExecutor#doQuery-------------->
Configuration#newStatementHandler
可以看到这里会处理所有的插件
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
public Object pluginAll(Object target) { for (Interceptor interceptor : interceptors) { target = interceptor.plugin(target); } return target; }
SimpleExecutor#prepareStatement
Connection connection = getConnection(statementLog); stmt = handler.prepare(connection, transaction.getTimeout()); handler.parameterize(stmt);
首先会拿到连接,。然后通过statmentHandler获取到一个Satament,所以我们就可以吧statmentHandler理解成获取到stament的一个工具。有点handlerMapping的味道,,
---------------->
PreparedStatementHandler#query
publicList query(Statement statement, ResultHandler resultHandler) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; ps.execute(); return resultSetHandler. handleResultSets(ps); }
这个ps也是个代理,execute方法会进入
PreparedStatementLogger#invoke方法。应该就是和日志相关吧,这里不是很清楚
最终会进入
ClientPreparedStatement#execute 方法去执行数据库操作,
回到PreparedStatementHandler#query方法:
resultSetHandler.handleResultSets(ps);
当数据放回数据之后,就会用ResultHandler去处理返回的数据了,这里具体就不详细说明了。。