Mybatis源码分析(四)
上回我们分析了Mybatis解析mapper映射文件的代码,我们继续上次的分析,开始mybatis执行sql语句的流程,话不多说咱们上代码!!!!!!
上回总结
上回我们分析了mybatis解析mapper映射文件的过程
- 解析***Mapper.xml文件的
mapper
标签; - 解析
select|insert|update|delete
标签; - 解析动态sql语句将sql语句解析后封装为一个
SqlSource
; - 通过
builderAssistant
(构建者助手),构建MappedStatement
对象; - 将
MappedStatement
对象放入configuration
对象中的mappedStatements
map中;
最终我们的到SqlSessionFactory
对象,封装后具体结构如下:
开始执行流程
创建SqlSession对象
-
回到我们的main方法中,得到
SqlSessionFactory
对象后,调用sqlSessionFactory.openSession()
方法创建SqlSession对象;//通过工厂生产一个sqlsession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //调用sqlSessionFactory的openSession方法 @Override public SqlSession openSession() { return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); } private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { // 获取数据源环境信息 final Environment environment = configuration.getEnvironment(); // 获取事务工厂 final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); // 获取JdbcTransaction或者ManagedTransaction tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); // 创建Executor执行器 final Executor executor = configuration.newExecutor(tx, execType); // 创建DefaultSqlSession return new DefaultSqlSession(configuration, executor, autoCommit); } catch (Exception e) { closeTransaction(tx); // may have fetched a connection so lets call close() throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
获取事务工厂创建
TransactionFactory
(我们使用的是jdbc,所以创建的是JdbcTransactionFactory,使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交),通过工厂创建Transaction(我们使用的是jdbc,所以创建的是JdbcTransaction);创建Executor执行器,用来操作数据库;//Executor执行器 public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; if (ExecutorType.BATCH == executorType) { // 批处理执行器 executor = new BatchExecutor(this, transaction); } else if (ExecutorType.REUSE == executorType) { // 可重用执行器 executor = new ReuseExecutor(this, transaction); } else { // 简单执行器 executor = new SimpleExecutor(this, transaction); } // 如果开启缓存(默认是开启的),则使用缓存执行器 if (cacheEnabled) { executor = new CachingExecutor(executor); } // 插件执行 executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
我们这里创建了一个简单执行器,mybatis默认是开启了一级缓存的,又创建缓存执行器,后面用来执行我们解析好的sql语句,最后创建了一个DefaultSqlSession对象;
-
通过SqlSession获取接口的代理对象
//通过SqlSession获取一个PersionMapper接口的代理对象 PersonMapper mapper = sqlSession.getMapper(PersonMapper.class); //调用Sqlsession的getMapper调用configuration中的getMapper方法 public <T> T getMapper(Class<T> type) { // 从Configuration对象中,根据Mapper接口,获取Mapper代理对象 return configuration.<T>getMapper(type, this); } //从configuration中取到之前封装好的mapperRegistry //里面有之前放进去的代理对象工厂 public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return mapperRegistry.getMapper(type, sqlSession); } //调用mapperRegistry的getMapper方法取到Mapper代理对象工厂 //key为接口的class对象,value为接口的代理对象工厂 public <T> T getMapper(Class<T> type, SqlSession sqlSession) { // 根据Mapper接口的类型,从Map集合中获取Mapper代理对象工厂 final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type); if (mapperProxyFactory == null) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } try { // 通过MapperProxyFactory生产MapperProxy,通过MapperProxy产生Mapper代理对象 return mapperProxyFactory.newInstance(sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } }
从
mapperRegistry
中取到mapper的代理对象工厂,并生产MapperProxy
,通过MapperProxy
产生Mapper代理对象;
创建Mapper代理对象
// 通过MapperProxyFactory生产MapperProxy,通过MapperProxy产生Mapper代理对象
return mapperProxyFactory.newInstance(sqlSession);
//调用生产出来的mapperProxyFactory的newInstance方法,生产mapperProxy
public T newInstance(SqlSession sqlSession) {
// 创建基于JDK实现的Mapper代理对象
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
//通过mapperProxy创建Mapper接口代理对象
protected T newInstance(MapperProxy<T> mapperProxy) {
// 使用JDK动态代理方式,生成代理对象
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
这里通过MapperProxyFactory
生产了一个MapperProxy
对象,通过MapperProxy
给予JDK的动态代理创建了一个mapper代理对象;
-
执行代理对象的seleceById方法
//创建入参对象并赋值 Person person1 = new Person(); person1.setId("1"); //执行selectById方法传入入参 "1" Person person = mapper.selectById(person1); // public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { // 是Interface接口还是Object类 // 如果方法是Object类自带的方法,比如没有被重写的 equals toString, hashcode 等,还是执行原来的方法 // getDeclaringClass()返回表示声明由此 Method 对象表示的方法的类或接口的 Class 对象。 if (Object.class.equals(method.getDeclaringClass())) { return method.invoke(this, args); } else if (isDefaultMethod(method)) { return invokeDefaultMethod(proxy, method, args); } } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } // 如果不是object的自带方法,先去 Map<Method, MapperMethod> methodCache中找是否已经存在这个method了 // 没有就将method封装成MapperMethod存进mehtodCache中然后返回MapperMethod final MapperMethod mapperMethod = cachedMapperMethod(method); // 然后执行MapprMehtod的execute方法(执行sqlsession的方法) return mapperMethod.execute(sqlSession, args); }
执行代理对象的seleceById方法,会进入MapperProxy.invoke()方法,判断当前是Interface接口还是Object类,判断有没有缓存这个方法,最后执行MapperProxy.execute()方法;
-
执行MapperProxy.execute()方法
//执行MapperProxy.execute()执行SQL脚本,得到结果对象,然后转换成对应method返回类型的对象 public Object execute(SqlSession sqlSession, Object[] args) { Object result; //判断Sql指令类型 switch (command.getType()) { //插入指令 case INSERT: { //构建sql脚本参数名-参数对象映射集合; Object param = method.convertArgsToSqlCommandParam(args); //执行插入Sql脚本,然后将更新记录数转换成method所需要的返回类型对象 result = rowCountResult(sqlSession.insert(command.getName(), param)); break; } //修改指令 case UPDATE: { //构建sql脚本参数名-参数对象映射集合; Object param = method.convertArgsToSqlCommandParam(args); //执行修改Sql脚本,然后将更新记录数转换成method所需要的返回类型对象 result = rowCountResult(sqlSession.update(command.getName(), param)); break; } //删除指令 case DELETE: { //构建sql脚本参数名-参数对象映射集合; Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.delete(command.getName(), param)); break; } //查询指令 case SELECT: //如果method返回类型为void 而且 method有ResultHandler类型参数 if (method.returnsVoid() && method.hasResultHandler()) { //用ResultHandler执行查询sql executeWithResultHandler(sqlSession, args); //处理结果赋值为ull result = null; //如果method返回类型为Collection的子类或者返回类型是数组 } else if (method.returnsMany()) { /** * 执行查询SQL,默认返回结果对象集合,但如果method返回类型为数组,该方法就会自动将结果对象集合 * 转换成数组;如果method返回类型为自定义的Collection实现类,该方法也会将结果对象集合的元素添加到 * 自定义的Collection实现类对象中 */ result = executeForMany(sqlSession, args); //如果method的返回类型是Map } else if (method.returnsMap()) { //执行查询SQL,返回结果对象映射赋值给result result = executeForMap(sqlSession, args); //如果method返回类型是Cursor游标 } else if (method.returnsCursor()) { //执行查询SQL,返回结果对象游标赋值给result result = executeForCursor(sqlSession, args); } else { //构建sql脚本参数名-参数对象映射集合 Object param = method.convertArgsToSqlCommandParam(args); //执行查询SQL,返回结果对象赋值给result result = sqlSession.selectOne(command.getName(), param); //如果method返回类型为Optional 且 结果对象为null 或者 method返回类型不等于结果对象类型 if (method.returnsOptional() && (result == null || !method.getReturnType().equals(result.getClass()))) { //如果对象即可能是 null 也可能是非 null,使用 ofNullable() 方法可以防止空指针异常 result = Optional.ofNullable(result); } } break; //刷新指令 case FLUSH: //执行全部等待批处理语句,并将结果封装到BatchResult集合中,然后赋值reuslt result = sqlSession.flushStatements(); break; default: throw new BindingException("Unknown execution method for: " + command.getName()); } //如果结果对象为null 且 method的返回类型为原始类型 且 method的返回类型不是void if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) { throw new BindingException("Mapper method '" + command.getName() + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ")."); } return result; }
-
执行SqlSession.selectOne()方法
//执行查询SQL,返回结果对象赋值给result result = sqlSession.selectOne(command.getName(), param); //执行SqlSession的selectOne方法 public <T> T selectOne(String statement, Object parameter) { // Popular vote was to return null on 0 results and throw exception on too many. List<T> list = this.selectList(statement, parameter); if (list.size() == 1) { return list.get(0); } else if (list.size() > 1) { throw new TooManyResultsException( "Expected one result (or null) to be returned by selectOne(), but found: " + list.size()); } else { return null; } } //执行SqlSession的selectList public <E> List<E> selectList(String statement, Object parameter) { return this.selectList(statement, parameter, RowBounds.DEFAULT); } //执行selectList方法 public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { try { // 根据传入的statementId,获取MappedStatement对象 MappedStatement ms = configuration.getMappedStatement(statement); // 调用执行器的查询方法 // RowBounds是用来逻辑分页(按照条件将数据从数据库查询到内存中,在内存中进行分页) // wrapCollection(parameter)是用来装饰集合或者数组参数 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(); } }
根据
statementId
在configuration中取到对应的MappedStatement对象,调用执行器执行查询方法;
调用执行器的查询方法(获取boundSql)
//调用之前创建的CachingExecutor的query方法
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
// 获取绑定的SQL语句,比如“SELECT * FROM user WHERE id = ? ”
BoundSql boundSql = ms.getBoundSql(parameterObject);
// 生成缓存Key
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
//调用MappedStatement.getBoundSql()获取绑定的SQL语句
public BoundSql getBoundSql(Object parameterObject) {
// 调用SqlSource获取BoundSql
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings == null || parameterMappings.isEmpty()) {
boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
}
// check for nested result maps in parameter mappings (issue #30)
for (ParameterMapping pm : boundSql.getParameterMappings()) {
String rmId = pm.getResultMapId();
if (rmId != null) {
ResultMap rm = configuration.getResultMap(rmId);
if (rm != null) {
hasNestedResultMaps |= rm.hasNestedResultMaps();
}
}
}
return boundSql;
}
//调用SqlSource获取BoundSql
public BoundSql getBoundSql(Object parameterObject) {
//创建动态sql上下文
DynamicContext context = new DynamicContext(configuration, parameterObject);
// 此处会调用MixedSqlNode中包含的所有SqlNode的apply方法
// 此处会处理${},也会处理动态标签
// 最终将所有的SqlNode信息进行解析之后,追加到DynamicContext对象的StringBuilder对象中
rootSqlNode.apply(context);
// 创建SQL信息解析器
SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
// 获取入参类型
Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
// 执行解析:将带有#{}的SQL语句进行解析,然后封装到StaticSqlSource中
SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
// 将解析后的SQL语句还有入参绑定到一起(封装到一个对象中,此时还没有将参数替换到SQL占位符?)
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
}
return boundSql;
}
创建动态SQL上下文,执行SqlSource中封装的rootSqlNode的apply方法,处理${}、处理动态标签,将处理过后的sql追加到动态SQL上下文中的StringBuilder对象中;
这里详细讲解一下每个SqlNode:
SQLNode:每个Xml Node都会解析成对应的SQLNode对象
//SqlNode接口
public interface SqlNode {
//将各个Sql片段合并到DynamicContext中,拼接为完整的SQL;
boolean apply(DynamicContext context);
}
//MixedSqlNode
public class MixedSqlNode implements SqlNode {
//记录sql节点中的所有SQL片段
private final List<SqlNode> contents;
public MixedSqlNode(List<SqlNode> contents) {
this.contents = contents;
}
@Override
public boolean apply(DynamicContext context) {
for (SqlNode sqlNode : contents) {
sqlNode.apply(context);
}
return true;
}
}
通过解析Sql节点得到的MixedSqlNode结构如下:
-
StaticSqlSource:最简单的SqlNode,功能仅仅是将自身记录的text拼接到context上下文中;
//StaticTextSqlNode public class StaticTextSqlNode implements SqlNode { private final String text; public StaticTextSqlNode(String text) { this.text = text; } @Override public boolean apply(DynamicContext context) { context.appendSql(text); return true; } }
-
TextSqlNode:表示包含‘${}’占位符的动态Sql节点;
//使用GenericTokenParser解析‘${}’,并直接转换成传入的实际参数 public boolean apply(DynamicContext context) { GenericTokenParser parser = createParser(new BindingTokenParser(context, injectionFilter)); context.appendSql(parser.parse(text)); return true; } //实际参数值获取逻辑方法 @Override public String handleToken(String content) { // 获取入参对象 Object parameter = context.getBindings().get("_parameter"); // 如果入参对象为null或者入参对象是简单类型,不需要关注${}中的名称,直接设置${}的参数名称必须为value // 如果content不为value,则取不出数据,会报错 if (parameter == null) { // context.getBindings().put("value", null); return ""; } else if (SimpleTypeRegistry.isSimpleType(parameter.getClass())) { // context.getBindings().put("value", parameter); return String.valueOf(parameter); } // 使用Ognl API,通过content中的表达式去获取入参对象中的指定属性值 // context.getBindings()就是一个ContextMap对象,也是HashMap的子对象 Object value = OgnlCache.getValue(content, parameter); String srtValue = value == null ? "" : String.valueOf(value); // issue #274 return "" instead of "null" checkInjection(srtValue); return srtValue; }
-
IFSqlNode:if标签平常使用的是最多的,在处理对应的逻辑节点时,主要工作就是通过Ognl表达式和传入的参数进行判断,看传入的参数是否满足if test里的表达式,满足将SQL片段合并到context上下文中。若不满足test则过滤掉这一部分的SQL片段,不添加到context中;
@Override public boolean apply(DynamicContext context) { //通过Ognl表达式和传入的参数进行判断,看传入的参数是否满足if test里的表达式 if (evaluator.evaluateBoolean(test, context.getBindings())) { contents.apply(context); return true; } return false; }
-
WhereSqlNode和SetSqlNode:都是继承自TrimSqlNode
- WhereSqlNode:会传入
prefix=WHERE
和prefixesToOverride=["AND ","OR ","AND\n", "OR\n", "AND\r", "OR\r", "AND\t", "OR\t"]
; - SetSqlNode:会传入
prefix=WHERE
和prefixesToOverride=[“,”]
; - 会传入
prefix=WHERE
和prefixesToOverride=[“,”]
;
- WhereSqlNode:会传入
-
TrimSqlNode:<trim /> 标签的SqlNode实现类;
-
ForEachSqlNode:<foreach /> 标签的SqlNode实现类;
-
VarDeclSqlNode: <bind /> 标签的SqlNode实现类;
最后动态sql上下文中拼接好的sql为:
-
解析’#{}’
//创建SqlSourceBuilder解析#{} public SqlSource parse(String originalSql, Class<?> parameterType, Map<String, Object> additionalParameters) { ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters); // 创建分词解析器 GenericTokenParser parser = new GenericTokenParser("#{", "}", handler); // 解析#{} String sql = parser.parse(originalSql); // 将解析之后的SQL信息,封装到StaticSqlSource对象中 // SQL字符串是带有?号的字符串,?相关的参数信息,封装到ParameterMapping集合中 return new StaticSqlSource(configuration, sql, handler.getParameterMappings()); }
-
调用缓存执行器的query方法;
@Override public <E> List<E> 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<E> list = (List<E>) tcm.getObject(cache, key); // 如果二级缓存中没有查询到数据,则查询数据库 if (list == null) { // 委托给BaseExecutor执行 list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); tcm.putObject(cache, key, list); // issue #578 and #116 } return list; } } // 委托给BaseExecutor执行 return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
这里查看是否存在二级缓存,如果存在则查询二级缓存,不存在则查询数据库(前提是开启了mybatis的二级缓存)
-
委托给BaseExecutor执行查询方法
@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 { // 如果一级缓存没有数据,则从数据库查询数据 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; }
查看一级缓存是否有数据,没有的话则从数据库查询;
-
调用BaseExecutor.queryFromDatabase()方法
//调用BaseExecutor.queryFromDatabase()方法 private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { List<E> list; //将缓存key存入一级缓存中 localCache.putObject(key, EXECUTION_PLACEHOLDER); try { // 执行查询 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; }
将处理好的sql,以及查询结果存入一级缓存中,执行查询方法;
-
执行SimpleExecutor的查询方法doQuery
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; try { // 获取Configuration对象 Configuration configuration = ms.getConfiguration(); // 创建RoutingStatementHandler,用来处理Statement // RoutingStatementHandler类中初始化delegate类(SimpleStatementHandler、PreparedStatementHandler) StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); // 子流程1:设置参数 stmt = prepareStatement(handler, ms.getStatementLog()); // 子流程2:执行SQL语句(已经设置过参数),并且映射结果集 return handler.query(stmt, resultHandler); } finally { closeStatement(stmt); } }
创建Statement处理器
创建RoutingStatementHandler用来处理对应的Statement,构造方法如下;
//根据不同的类型创建不同的Statement处理器,进行处理
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
switch (ms.getStatementType()) {
//简单的Statement处理器
case STATEMENT:
delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
//PreparedStatement处理器
case PREPARED:
delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
//callable处理器
case CALLABLE:
delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
default:
throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
}
}
根据不同的类型创建不同的Statement处理器,处理statement;
- 设置参数,执行Statement处理器的prepareStatement方法
//后获取jdbc链接,创建Statement并设置Statement参数
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
// 获取连接
Connection connection = getConnection(statementLog);
// 创建Statement(PreparedStatement、Statement、CallableStatement)
stmt = handler.prepare(connection, transaction.getTimeout());
// SQL参数设置
handler.parameterize(stmt);
return stmt;
}
//创建prepareStatement
public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
// 实例化Statement,比如PreparedStatement
statement = instantiateStatement(connection);
// 设置查询超时时间
setStatementTimeout(statement, transactionTimeout);
setFetchSize(statement);
return statement;
} catch (SQLException e) {
closeStatement(statement);
throw e;
} catch (Exception e) {
closeStatement(statement);
throw new ExecutorException("Error preparing statement. Cause: " + e, e);
}
}
//创建prepareStatement
protected Statement instantiateStatement(Connection connection) throws SQLException {
// 获取带有占位符的SQL语句
String sql = boundSql.getSql();
// 处理带有主键返回的SQL
if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
String[] keyColumnNames = mappedStatement.getKeyColumns();
if (keyColumnNames == null) {
return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
} else {
return connection.prepareStatement(sql, keyColumnNames);
}
} else if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {
return connection.prepareStatement(sql);
} else {
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
}
}
//调用prepareStatement的parameterize方法,使用parameterHandler参数处理器设置参数
public void parameterize(Statement statement) throws SQLException {
// 通过ParameterHandler处理参数
parameterHandler.setParameters((PreparedStatement) statement);
}
//对prepareStatement设置参数
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
// 获取要设置的参数映射信息
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
// 只处理入参
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
// 获取属性名称
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
// 获取每个参数的类型处理器,去设置入参和获取返回值
TypeHandler typeHandler = parameterMapping.getTypeHandler();
// 获取每个参数的JdbcType
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
// 给PreparedStatement设置参数
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException e) {
throw new TypeException(
"Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
} catch (SQLException e) {
throw new TypeException(
"Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}
在参数处理器中创建每个参数的typeHandler(类型处理器的)setParameter方法,设置参数;
-
执行StatementHandler的query方法执行sql语句
//执行PreparedStatement,也就是执行SQL语句 public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { PreparedStatement ps = (PreparedStatement) statement; // 执行PreparedStatement,也就是执行SQL语句 ps.execute(); // 处理结果集 return resultSetHandler.handleResultSets(ps); }
-
处理结果集
public List<Object> handleResultSets(Statement stmt) throws SQLException { ErrorContext.instance().activity("handling results").object(mappedStatement.getId()); // <select>标签的resultMap属性,可以指定多个值,多个值之间用逗号(,)分割 final List<Object> multipleResults = new ArrayList<>(); int resultSetCount = 0; // 这里是获取第一个结果集,将传统JDBC的ResultSet包装成一个包含结果列元信息的ResultSetWrapper对象 ResultSetWrapper rsw = getFirstResultSet(stmt); // 这里是获取所有要映射的ResultMap(按照逗号分割出来的) List<ResultMap> resultMaps = mappedStatement.getResultMaps(); // 要映射的ResultMap的数量 int resultMapCount = resultMaps.size(); validateResultMapsCount(rsw, resultMapCount); // 循环处理每个ResultMap,从第一个开始处理 while (rsw != null && resultMapCount > resultSetCount) { // 得到结果映射信息 ResultMap resultMap = resultMaps.get(resultSetCount); // 处理结果集 // 从rsw结果集参数中获取查询结果,再根据resultMap映射信息,将查询结果映射到multipleResults中 handleResultSet(rsw, resultMap, multipleResults, null); rsw = getNextResultSet(stmt); cleanUpAfterHandlingResultSet(); resultSetCount++; } // 对应<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(rsw, resultMap, null, parentMapping); } rsw = getNextResultSet(stmt); cleanUpAfterHandlingResultSet(); resultSetCount++; } } // 如果只有一个结果集合,则直接从多结果集中取出第一个 return collapseSingleResultList(multipleResults); } //调用上边的handleResultSet(rsw, resultMap, multipleResults, null); //处理结果映射 private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException { try { // 处理嵌套结果映射 if (parentMapping != null) { handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping); } else { // 第一次一般来说resultHandler为空,则创建DefaultResultHandler来处理结果 if (resultHandler == null) { DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory); // 处理行数据,其实就是完成结果映射 handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null); multipleResults.add(defaultResultHandler.getResultList()); } else { handleRowValues(rsw, resultMap, resultHandler, rowBounds, null); } } } finally { // issue #228 (close resultsets) closeResultSet(rsw.getResultSet()); } } //判断映射嵌套关系 public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { // 是否有内置嵌套的结果映射 if (resultMap.hasNestedResultMaps()) { ensureNoRowBounds(); checkResultHandler(); // 嵌套结果映射 handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); } else { // 简单结果映射 handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping); } } //处理简单的映射关系 private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { DefaultResultContext<Object> resultContext = new DefaultResultContext<>(); // 获取结果集信息 ResultSet resultSet = rsw.getResultSet(); // 使用rowBounds的分页信息,进行逻辑分页(也就是在内存中分页) skipRows(resultSet, rowBounds); while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) { // 通过<resultMap>标签的子标签<discriminator>对结果映射进行鉴别 ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null); // 将查询结果封装到POJO中 Object rowValue = getRowValue(rsw, discriminatedResultMap, null); // 处理对象嵌套的映射关系 storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet); } }
处理完成后,将查询到的结果返回;
到这里我们完整的走了一遍Mybatis通过接口Mapper映射文件查询数据库,经过了解析xml、封装SQl、获取SQl、执行SQl、解析结果集。希望通过学习源码让自己对框架的了解更深一些.