Mybatis源码分析
一、引言
之前的文章已经介绍mybatis的架构跟源码的构建构成,这篇文章会根据之前的测试类来调试解析源码。
二、创建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
reader是读取的我们的mybatis-config配置文件,主要看一下build方法
public SqlSessionFactory build(Reader reader) {
return build(reader, null, null);
}
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
//建造者模式,构建XMLConfigBuilder,用来解析mybatis全局配置文件的对象
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
//解析配置文件
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
创建xml解析器
public XMLConfigBuilder(Reader reader, String environment, Properties props) {
//创建XPathParser,用来解析xml
this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
}
解析配置文件
public SqlSessionFactory build(Configuration config) {
//将解析后得到的配置对象放入DefaultSqlSessionFactory
return new DefaultSqlSessionFactory(config);
}
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
//标志位
parsed = true;
//mybatis配置文件的根节点configuration
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
解析标签
private void parseConfiguration(XNode root) {
try {
// issue #117 read properties first
//解析properties标签
propertiesElement(root.evalNode("properties"));
//解析settings的标签
Properties settings = settingsAsProperties(root.evalNode("settings"));
//vfs 虚拟文件系统
loadCustomVfs(settings);
//log日志,如果配置了LogImpl,会设置到LogFactory中去
loadCustomLogImpl(settings);
//别名
typeAliasesElement(root.evalNode("typeAliases"));
// plugin
//插件
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
//环境的配置,例如:是否开启二级缓存等等
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
//环境
//在Mybatis中支持我们根据不同的环境进行配置不同的数据库,这些配置会放到environments节点下
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
//类型处理器
typeHandlerElement(root.evalNode("typeHandlers"));
//解析mapper节点配置
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
以上过程就是初始化构建环境,比较简单,我们挑一个mapper标签解析看一下
//4种配置方式
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
if ("package".equals(child.getName())) {
String mapperPackage = child.getStringAttribute("name");
configuration.addMappers(mapperPackage);
} else {
// 获取resource属性
String resource = child.getStringAttribute("resource");
// 获取url属性
String url = child.getStringAttribute("url");
// 获取class属性
String mapperClass = child.getStringAttribute("class");
if (resource != null && url == null && mapperClass == null) {
ErrorContext.instance().resource(resource);
try(InputStream inputStream = Resources.getResourceAsStream(resource)) {
// 创建XMLMapperBuilder对象
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
// 解析映射文件
mapperParser.parse();
}
} else if (resource == null && url != null && mapperClass == null) {
ErrorContext.instance().resource(url);
try(InputStream inputStream = Resources.getUrlAsStream(url)){
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
mapperParser.parse();
}
} else if (resource == null && url == null && mapperClass != null) {
Class<?> mapperInterface = Resources.classForName(mapperClass);
configuration.addMapper(mapperInterface);
} else {
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
}
}
}
}
}
mapper标签大的类型可以分成两种:配置package和配置资源文件,资源文件又可分为3种resource、url、class,都是为了找到具体的mapper.xml文件,然后解析mapperParser.parse()。
public void parse() {
// 判断是否已经加载过该映射文件
if (!configuration.isResourceLoaded(resource)) {
// 处理mapper节点
configurationElement(parser.evalNode("/mapper"));
// 将映射文件记录到Configuration.loadedResources字段中 是一个Set
configuration.addLoadedResource(resource);
// 注册Mapper
bindMapperForNamespace();
}
// 处理解析失败的ResultMap
parsePendingResultMaps();
// 处理解析失败的cache-ref
parsePendingCacheRefs();
// 处理解析失败的SQL
parsePendingStatements();
}
处理mapper文件
private void configurationElement(XNode context) {
try {
// 获取namespace属性
String namespace = context.getStringAttribute("namespace");
// namespace不存在抛出异常
if (namespace == null || namespace.isEmpty()) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
// 设置builderAssistant字段的currentNamespace属性
builderAssistant.setCurrentNamespace(namespace);
// 解析cache-ref节点
cacheRefElement(context.evalNode("cache-ref"));
// 解析cache节点
cacheElement(context.evalNode("cache"));
//入参
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
//返回值
resultMapElements(context.evalNodes("/mapper/resultMap"));
//sql片段
sqlElement(context.evalNodes("/mapper/sql"));
//sql语句
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
} catch (Exception e) {
throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
}
}
cache-ref
private void cacheRefElement(XNode context) { if (context != null) { // Configuration.cacheRefMap属性中添加数据 当前命名空间和节点的namespace属性进行关联 configuration.addCacheRef(builderAssistant.getCurrentNamespace(), context.getStringAttribute("namespace")); // 创建CacheRefResolver对象 CacheRefResolver cacheRefResolver = new CacheRefResolver(builderAssistant, context.getStringAttribute("namespace")); try { // 解析cacheRef cacheRefResolver.resolveCacheRef(); } catch (IncompleteElementException e) { // 如果解析发生异常添加到incompleteCacheRef字段中 configuration.addIncompleteCacheRef(cacheRefResolver); } } }
cache
private void cacheElement(XNode context) {
if (context != null) {
// 获取type属性 默认为PERPETUAL
String type = context.getStringAttribute("type", "PERPETUAL");
// 通过别名获取对应的类型
Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);
// 获取eviction属性 默认为LRU
String eviction = context.getStringAttribute("eviction", "LRU");
// 获取eviction别名对应的类型
Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction);
// 获取flushInterval属性
Long flushInterval = context.getLongAttribute("flushInterval");
// 获取size属性
Integer size = context.getIntAttribute("size");
// 获取redaOnly属性 默认为false
boolean readWrite = !context.getBooleanAttribute("readOnly", false);
// 获取blocking属性 默认为false
boolean blocking = context.getBooleanAttribute("blocking", false);
// 获取子节点数据
Properties props = context.getChildrenAsProperties();
// 创建Cache对象并添加到Configuration.caches中
builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);
}
}
public Cache useNewCache(Class<? extends Cache> typeClass,
Class<? extends Cache> evictionClass,
Long flushInterval,
Integer size,
boolean readWrite,
boolean blocking,
Properties props) {
// 创建Cache对象
Cache cache = new CacheBuilder(currentNamespace)
.implementation(valueOrDefault(typeClass, PerpetualCache.class))
.addDecorator(valueOrDefault(evictionClass, LruCache.class))
.clearInterval(flushInterval)
.size(size)
.readWrite(readWrite)
.blocking(blocking)
.properties(props)
.build();
// 将cache添加到configuration中
configuration.addCache(cache);
// 记录当前命名空间使用的cache
currentCache = cache;
return cache;
}
cache和cache-ref节点的解析最后都会修改MapperBuilderAssistant.currentCache属性的值,因此,当这两个标签都存在时会存在覆盖的问题。
解析sql语句
private void buildStatementFromContext(List<XNode> list) {
if (configuration.getDatabaseId() != null) {
buildStatementFromContext(list, configuration.getDatabaseId());
}
buildStatementFromContext(list, null);
}
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
//循环解析sql语句
for (XNode context : list) {
final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
try {
statementParser.parseStatementNode();
} catch (IncompleteElementException e) {
configuration.addIncompleteStatement(statementParser);
}
}
}
public void parseStatementNode() {
// 获取id属性
String id = context.getStringAttribute("id");
// 获取databaseId属性
String databaseId = context.getStringAttribute("databaseId");
// 获取到的databaseId和创建时设置的databaseId不一致 不处理
if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
return;
}
// 获取节点名称
String nodeName = context.getNode().getNodeName();
// 获取sql类型
SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
//判断是否为select节点
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
// 是否刷新缓存
boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
// 是否使用缓存
boolean useCache = context.getBooleanAttribute("useCache", isSelect);
boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);
// 处理include节点
XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
includeParser.applyIncludes(context.getNode());
// 获取parameterType属性
String parameterType = context.getStringAttribute("parameterType");
// 获取parameterType类型
Class<?> parameterTypeClass = resolveClass(parameterType);
// 获取lang属性
String lang = context.getStringAttribute("lang");
// 获取LanguageDriver对象
LanguageDriver langDriver = getLanguageDriver(lang);
// selectKey节点
processSelectKeyNodes(id, parameterTypeClass, langDriver);
//解析sql
KeyGenerator keyGenerator;
String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
if (configuration.hasKeyGenerator(keyStatementId)) {
keyGenerator = configuration.getKeyGenerator(keyStatementId);
} else {
keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
}
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
//按照我们写的语句标签,解析成一个个节点,sqlNode
StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
Integer fetchSize = context.getIntAttribute("fetchSize");
Integer timeout = context.getIntAttribute("timeout");
String parameterMap = context.getStringAttribute("parameterMap");
String resultType = context.getStringAttribute("resultType");
Class<?> resultTypeClass = resolveClass(resultType);
String resultMap = context.getStringAttribute("resultMap");
String resultSetType = context.getStringAttribute("resultSetType");
ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
if (resultSetTypeEnum == null) {
resultSetTypeEnum = configuration.getDefaultResultSetType();
}
String keyProperty = context.getStringAttribute("keyProperty");
String keyColumn = context.getStringAttribute("keyColumn");
String resultSets = context.getStringAttribute("resultSets");
//创建MappedStatement对象
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
三、获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession()
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
// 获取environment
final Environment environment = configuration.getEnvironment();
// 获取事务工厂
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
// 创建事务对象
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
// 创建执行器对象
final Executor executor = configuration.newExecutor(tx, execType);
// 返回一个DefaultSqlSession对象
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
// may have fetched a connection so lets call close()
closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
比较重要的是执行器的创建,也是后面用来执行sql的四大对象之一,executorType 是在初始化时配置进去的。
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) {
//包装成CachingExecutor
executor = new CachingExecutor(executor);
}
// 拦截器执行
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。
ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。简言之,就是重复使用Statement对象。
BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。
自定义插件的代理初始化,前提我们自定义了插件,并配置到了配置文件中
<plugins>
<plugin interceptor="com.ren.mybatis.plugin.PrintSqlPlugin">
</plugin>
</plugins>
我们这里自定义了一个打印sql语句的插件
@Intercepts({@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),
@Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),
@Signature(type = StatementHandler.class, method = "batch", args = {Statement.class})})
public class PrintSqlPlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object target = invocation.getTarget();
long startTime = System.currentTimeMillis();
StatementHandler statementHandler = (StatementHandler) target;
try {
return invocation.proceed();
} finally {
long endTime = System.currentTimeMillis();
long sqlCost = endTime - startTime;
BoundSql boundSql = statementHandler.getBoundSql();
String sql = boundSql.getSql();
Object parameterObject = boundSql.getParameterObject();
List<ParameterMapping> parameterMappingList = boundSql.getParameterMappings();
// 格式化Sql语句,去除换行符,替换参数
sql = formatSql(sql, parameterObject, parameterMappingList);
System.out.println("SQL:[" + sql + "] use: [" + sqlCost + "ms]");
}
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
```
}
执行插件的plugin方法,会生成动态代理对象
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
//执行插件的plugin方法
target = interceptor.plugin(target);
}
return target;
}
//PrintSqlPlugin
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
public static Object wrap(Object target, Interceptor interceptor) {
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
Class<?> type = target.getClass();
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
//根据自定义插件的注解生成相应的代理类
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}
四、SQL执行
PetUser petUser = (PetUser)sqlSession.selectOne("com.ren.mybatis.mapper.PetUserMapper.selectById","1")
public <T> T selectOne(String statement, Object parameter) {
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;
}
}
public <E> List<E> selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
return selectList(statement, parameter, rowBounds, Executor.NO_RESULT_HANDLER);
}
private <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
try {
//获取MappedStatement对象,里面包含了初始化时解析好的sql信息
MappedStatement ms = configuration.getMappedStatement(statement);
//wrapCollection(parameter)包装了入参,通过执行器执行sql
return executor.query(ms, wrapCollection(parameter), rowBounds, handler);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
执行器执行CachingExecutor
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//获取执行的sql,就是根据之前初始化时,构建的多层sqlNode,递归解析,最终生成我们需要执行的sql语句,还未替换参数,只是替换成了?
BoundSql boundSql = ms.getBoundSql(parameterObject);
//创建缓存的key=statementId+offset+limit+sql+paramValueList+environmentId
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
//执行查询
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
执行查询
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
Cache cache = ms.getCache();
//是否配置了缓存<cache></cache>
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) {
//二级缓存没有获取到,去数据库查询
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
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());
//sqlSession已经关闭则报错
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;
}
一级缓存使用的地方,然后开始进行从数据库查询
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 {
//走子类的查询
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;
}
又回到子类的查询
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);
//预处理,主要就是开始替换参数
stmt = prepareStatement(handler, ms.getStatementLog());
//执行查询之前,如果我们自定义了插件,会先走我们自定义的插件的intercept
return handler.query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
创建StatementHandler对象,预处理,执行查询之前如果配置了插件,会执行插件的intercept方法,再执行数据库查询操作
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
//创建StatementHandler,如有plugin还会创建代理
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
switch (ms.getStatementType()) {
case STATEMENT:
delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED:
delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case CALLABLE:
delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
default:
throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
}
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
this.configuration = mappedStatement.getConfiguration();
this.executor = executor;
this.mappedStatement = mappedStatement;
this.rowBounds = rowBounds;
this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.objectFactory = configuration.getObjectFactory();
if (boundSql == null) { // issue #435, get the key before calculating the statement
generateKeys(parameterObject);
boundSql = mappedStatement.getBoundSql(parameterObject);
}
this.boundSql = boundSql;
//先创建ParameterHandler,有添加plugin,会创建代理
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
//再创建ResultSetHandler,有添加plugin,会创建代理
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
执行查询完成之后,处理结果集
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
//处理结果集
return resultSetHandler.handleResultSets(ps);
}
处理完结果集,再放回一级缓存,二级缓存。
五、关闭sqlSession
sqlSession.close()
public void close() {
try {
//关闭SqlSession
executor.close(isCommitOrRollbackRequired(false));
//关闭游标
closeCursors();
dirty = false;
} finally {
ErrorContext.instance().reset();
}
}
关闭SqlSession
public void close(boolean forceRollback) {
try {
try {
//判断是否需要事务回滚操作
rollback(forceRollback);
} finally {
if (transaction != null) {
//关闭事务
transaction.close();
}
}
} catch (SQLException e) {
// Ignore. There's nothing that can be done at this point.
log.warn("Unexpected exception on closing transaction. Cause: " + e);
} finally {
transaction = null;
deferredLoads = null;
//清空缓存
localCache = null;
localOutputParameterCache = null;
//重置sqlSession标志
closed = true;
}
}