mybatis源码(四)SqlSession执行mapper的过程下篇
代码案例:以SqlSession的selectList为例
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="mapper"> <select id="selectUsers" resultType="com.forest.owl.entity.User"> SELECT id, account, passwd, nickname, phone, email, create_time as createTime, update_time as updateTime FROM user </select> </mapper> public class TestUserMapper { private static SqlSessionFactory sqlSessionFactory; @BeforeClass public static void init(){ try { Reader reader = Resources.getResourceAsReader("mybatis.config.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); reader.close(); } catch (IOException e) { e.printStackTrace(); } } @Test public void TestMybatis(){ SqlSession sqlSession = sqlSessionFactory.openSession(); List<User> userList = sqlSession.selectList("selectUsers"); System.out.println(userList.size()); System.out.println(userList.get(0).getNickname()); System.out.println(userList.get(0).getCreateTime()); } }
首先SqlSession是一个接口,有一个DefaultSqlSession的实现类,实现类实现该接口的代码如下:
@Override public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { try { // 根据Mapper的Id,获取对应的MappedStatement对象 MappedStatement ms = configuration.getMappedStatement(statement); // 以MappedStatement对象作为参数,调用Executor的query()方法 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(); } }
configuration的mapperstatement的对象的值 是在SqlSession创建的时候,通过XmlConfigBuilder解析mybatis-config主配置文件的时候,添加进去的 configration中有一个map集合如下图所示
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection");
该属性是一个Map对象,它的key为mapperSql配置的id。如果sql是通过xml注释的。则id为命名空间加上<select|update|delete|insert标签的id> ,如果sql通过java注解配置。则id为mapper接口的全限定名称加上方法名称
通过上述源码可以看到,实际操作数据库的事Excutor执行器,这里用到了一个外观模式,为了对用户提供友好的访问接口,Excutor执行器是一个接口,有几个实现类
进入实现类BaseExecutor中,查看query的源码
queryFromDatabase 这个地方由于缓存中没有我们要找的数据,所以从数据库中进行数据的读取,这个doQuery方法用到了模板方法设计模式根据上述的类图,可以看到有几个实现类,分别提供了不同的实现
@Override public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { // 获取BoundSql对象,BoundSql是对动态SQL解析生成的SQL语句和参数映射信息的封装 BoundSql boundSql = ms.getBoundSql(parameter); // 创建CacheKey,用于缓存Key CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql); // 调用重载的query()方法 return query(ms, parameter, rowBounds, resultHandler, key, boundSql); } @SuppressWarnings("unchecked") @Override public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId()); if (closed) { throw new ExecutorException("Executor was closed."); } if (queryStack == 0 && ms.isFlushCacheRequired()) { clearLocalCache(); } List<E> list; try { queryStack++; // 从缓存中获取结果 list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; if (list != null) { handleLocallyCachedOutputParameters(ms, key, parameter, boundSql); } else { // 缓存中获取不到,则调用queryFromDatabase()方法从数据库中查询 list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql); } } finally { queryStack--; } if (queryStack == 0) { for (DeferredLoad deferredLoad : deferredLoads) { deferredLoad.load(); } // issue #601 deferredLoads.clear(); if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { // issue #482 clearLocalCache(); } } return list; } private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List<E> list; localCache.putObject(key, EXECUTION_PLACEHOLDER); try { // 调用doQuery()方法查询 list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql); } finally { localCache.removeObject(key); } // 缓存查询结果 localCache.putObject(key, list); if (ms.getStatementType() == StatementType.CALLABLE) { localOutputParameterCache.putObject(key, parameter); } return list; } protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException;
@Override public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; try { Configuration configuration = ms.getConfiguration(); // 获取StatementHandler对象 StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); // 调用prepareStatement()方法,创建Statement对象,并进行设置参数等操作 stmt = prepareStatement(handler, ms.getStatementLog()); // 调用StatementHandler对象的query()方法执行查询操作 return handler.<E>query(stmt, resultHandler); } finally { closeStatement(stmt); } }
实现类2:BatchExecutor
@Override public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; try { flushStatements(); Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql); Connection connection = getConnection(ms.getStatementLog()); stmt = handler.prepare(connection, transaction.getTimeout()); handler.parameterize(stmt); return handler.<E>query(stmt, resultHandler); } finally { closeStatement(stmt); } }
实现类3:ReuseExecutor
@Override public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Configuration configuration = ms.getConfiguration(); StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); Statement stmt = prepareStatement(handler, ms.getStatementLog()); return handler.<E>query(stmt, resultHandler); } Statement 操作数据库就是JDBC提供的操作数据的实现
从三述三种实现类中可以看出StatementHandler是操作Statement的。
@Override public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { String sql = boundSql.getSql(); statement.execute(sql); return resultSetHandler.<E>handleResultSets(statement); }
实现类2:PreparedStatementHandler
@Override public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; // 调用PreparedStatement对象的execute()方法,执行SQL语句 ps.execute(); // 调用ResultSetHandler的handleResultSets()方法处理结果集 return resultSetHandler.<E> handleResultSets(ps); }
实现类3:CallableStatementHandler
@Override public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { CallableStatement cs = (CallableStatement) statement; cs.execute(); List<E> resultList = resultSetHandler.<E>handleResultSets(cs); resultSetHandler.handleOutputParameters(cs); return resultList; }
ResultSetHandler 是一个接口实现,只有一个实现类
public interface ResultSetHandler { <E> List<E> handleResultSets(Statement stmt) throws SQLException; <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException; void handleOutputParameters(CallableStatement cs) throws SQLException; }
DefaultResultSetHandler
// // 处理结果集 // @Override public List<Object> handleResultSets(Statement stmt) throws SQLException { ErrorContext.instance().activity("handling results").object(mappedStatement.getId()); final List<Object> multipleResults = new ArrayList<Object>(); int resultSetCount = 0; // 1、获取ResultSet对象,將ResultSet对象包装为ResultSetWrapper ResultSetWrapper rsw = getFirstResultSet(stmt); // 2、获取ResultMap信息,一般只有一个ResultMap List<ResultMap> resultMaps = mappedStatement.getResultMaps(); int resultMapCount = resultMaps.size(); // 校验ResultMap,如果该ResultMap名称没有配置,则抛出异常 validateResultMapsCount(rsw, resultMapCount); // 如果指定了多个ResultMap,则对每个ResultMap进行处理 while (rsw != null && resultMapCount > resultSetCount) { ResultMap resultMap = resultMaps.get(resultSetCount); // 3、调用handleResultSet方法处理结果集 handleResultSet(rsw, resultMap, multipleResults, null); // 获取下一个结果集对象,需要JDBC驱动支持多结果集 rsw = getNextResultSet(stmt); cleanUpAfterHandlingResultSet(); resultSetCount++; } // 如果JDBC驱动支持多结果集,可以通过<select>标签resultSets属性指定多个ResultMap // 处理<select>标签resultSets属性,该属性一般情况不会指定 String[] resultSets = mappedStatement.getResultSets(); if (resultSets != null) { while (rsw != null && resultSetCount < resultSets.length) { ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]); if (parentMapping != null) { String nestedResultMapId = parentMapping.getNestedResultMapId(); ResultMap resultMap = configuration.getResultMap(nestedResultMapId); //调用handleResultSet方法处理结果集 handleResultSet(rsw, resultMap, null, parentMapping); } rsw = getNextResultSet(stmt); cleanUpAfterHandlingResultSet(); resultSetCount++; } } // 对multipleResults进行处理,如果只有一个结果集,则返回结果集中的元素,否则返回多个结果集 return collapseSingleResultList(multipleResults); } @SuppressWarnings("unchecked") private List<Object> collapseSingleResultList(List<Object> multipleResults) { return multipleResults.size() == 1 ? (List<Object>) multipleResults.get(0) : multipleResults; }
至此,就完成了SqlSession.selectList的 流程,源码涉及的东西比较多,这就是个大致的流程