六SqlSession 的创建过程以及 Executor 执行 SQL 过程详解
Posted archerLuo罗
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了六SqlSession 的创建过程以及 Executor 执行 SQL 过程详解相关的知识,希望对你有一定的参考价值。
- 源码地址:https://github.com/RononoaZoro/mybatis-book/tree/master 的 mybatis-book ( mybatis-chapter04 和 mybatis-chapter05)
- 文章内容出自《Mybatis 3 源码深度解析》第五章
- 自己实现代码地址:https://github.com/RononoaZoro/mybatis-book/tree/master 的 archer-mybatis
1、XPath 方式解析 XML 文件
users.xml
<?xml version="1.0" encoding="UTF-8" ?>
<users>
<user id = "1">
<name>张三</name>
<createTime>2018-06-06 00:00:00</createTime>
<passward>admin</passward>
<phone>180000000</phone>
<nickName>阿毛</nickName>
</user>
<user id = "2">
<name>李四</name>
<createTime>2018-06-06 00:00:00</createTime>
<passward>admin</passward>
<phone>180000001</phone>
<nickName>明明</nickName>
</user>
</users>
实体类 UserEntity
package com.blog4java.mybatis.xpath;
import lombok.Data;
import java.util.Date;
@Data
public class UserEntity {
private Long id;
private String name;
private Date createTime;
private String password;
private String phone;
private String nickName;
}
1)、XPath 解析
package com.blog4java.mybatis.xpath;
import com.alibaba.fastjson.JSON;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.converters.DateConverter;
import org.apache.ibatis.builder.BuilderException;
import org.apache.ibatis.io.Resources;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class XPathExample {
@Test
public void testXPathParser() {
try {
// 创建DocumentBuilderFactory实例
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 创建DocumentBuilder实例
DocumentBuilder builder = factory.newDocumentBuilder();
InputStream inputSource = Resources.getResourceAsStream("users.xml");
Document doc = builder.parse(inputSource);
// 获取XPath实例
XPath xpath = XPathFactory.newInstance().newXPath();
// 执行XPath表达式,获取节点信息
NodeList nodeList = (NodeList)xpath.evaluate("/users/*", doc, XPathConstants.NODESET);
List<UserEntity> userList = new ArrayList<>();
for(int i=1; i < nodeList.getLength() + 1; i++) {
String path = "/users/user["+i+"]";
String id = (String)xpath.evaluate(path + "/@id", doc, XPathConstants.STRING);
String name = (String)xpath.evaluate(path + "/name", doc, XPathConstants.STRING);
String createTime = (String)xpath.evaluate(path + "/createTime", doc, XPathConstants.STRING);
String passward = (String)xpath.evaluate(path + "/passward", doc, XPathConstants.STRING);
String phone = (String)xpath.evaluate(path + "/phone", doc, XPathConstants.STRING);
String nickName = (String)xpath.evaluate(path + "/nickName", doc, XPathConstants.STRING);
// 调用buildUserEntity()方法,构建UserEntity对象
UserEntity userEntity = buildUserEntity(id,name, createTime, passward, phone, nickName);
userList.add(userEntity);
}
System.out.println(JSON.toJSONString(userList));
System.out.println(userList.get(0).getCreateTime());
} catch (Exception e) {
throw new BuilderException("Error creating document instance. Cause: " + e, e);
}
}
private UserEntity buildUserEntity(String id,String name,
String createTime, String passward,
String phone, String nickName)
throws IllegalAccessException, InvocationTargetException {
UserEntity userEntity = new UserEntity();
DateConverter dateConverter = new DateConverter(null);
dateConverter.setPattern("yyyy-MM-dd HH:mm:ss");
ConvertUtils.register(dateConverter,Date.class);
BeanUtils.setProperty(userEntity,"id",id);
BeanUtils.setProperty(userEntity,"name",name);
BeanUtils.setProperty(userEntity,"createTime",createTime);
BeanUtils.setProperty(userEntity,"passward",passward);
BeanUtils.setProperty(userEntity,"phone",phone);
BeanUtils.setProperty(userEntity,"nickName",nickName);
return userEntity;
}
}
2)、Mybatis XNode 解析
package com.blog4java.mybatis.xpath;
import com.alibaba.fastjson.JSON;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.converters.DateConverter;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.parsing.XNode;
import org.apache.ibatis.parsing.XPathParser;
import org.junit.Test;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class XPathParserExample {
@Test
public void testXPathParser() throws Exception {
Reader resource = Resources.getResourceAsReader("users.xml");
XPathParser parser = new XPathParser(resource);
// 注册日期转换器
DateConverter dateConverter = new DateConverter(null);
dateConverter.setPattern("yyyy-MM-dd HH:mm:ss");
ConvertUtils.register(dateConverter, Date.class);
List<UserEntity> userList = new ArrayList<>();
// 调用evalNodes()方法获取XNode列表
List<XNode> nodes = parser.evalNodes("/users/*");
// 对XNode对象进行遍历,获取user相关信息
for (XNode node : nodes) {
UserEntity userEntity = new UserEntity();
Long id = node.getLongAttribute("id");
BeanUtils.setProperty(userEntity, "id", id);
List<XNode> childNods = node.getChildren();
for (XNode childNode : childNods) {
BeanUtils.setProperty(userEntity, childNode.getName(),
childNode.getStringBody());
}
userList.add(userEntity);
}
System.out.println(JSON.toJSONString(userList));
}
}
2、SqlSession 实例创建
package com.blog4java.mybatis.sqlsession;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.Reader;
public class SqlSessionExample {
@Test
public void testSqlSession() throws IOException {
// 获取Mybatis配置文件输入流
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
// 通过SqlSessionFactoryBuilder创建SqlSessionFactory实例
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
// 调用SqlSessionFactory的openSession()方法,创建SqlSession实例
SqlSession session = sqlSessionFactory.openSession();
}
}
3、SqlSession 创建过程详解
3.1、初始化 Configuration对象
- 1)、SqlSessionFactoryBuilder#build 方法中初始化了 Configuration 对象(参考:五、Mybatis 核心对象之 Configuration 对象初始化详解)
- 2)、SqlSession 采用工厂模式创建,所以需要创建 SqlSessionFactory 对象,SqlSessionFactory 只有一个默认实现 DefaultSqlSessionFactory
// 通过SqlSessionFactoryBuilder创建SqlSessionFactory实例
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(Reader reader) {
return build(reader, null, null);
}
public SqlSessionFactory build(Reader reader, String environment) {
return build(reader, environment, null);
}
public SqlSessionFactory build(Reader reader, Properties properties) {
return build(reader, null, properties);
}
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
//初始化 Configuration 对象
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.
}
}
}
}
3.2、创建 SqlSession 对象
- 1)、SqlSession 是 Mybatis 提供的面向用户操作数据库的 API
- 2)、SqlSession 默认实现是 DefaultSqlSession
// 调用SqlSessionFactory的openSession()方法,创建SqlSession实例
SqlSession session = sqlSessionFactory.openSession();
public class DefaultSqlSessionFactory implements SqlSessionFactory { private final Configuration configuration; public DefaultSqlSessionFactory(Configuration configuration) { this.configuration = configuration; } @Override public SqlSession openSession() { return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); } private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; try { // 获取Mybatis主配置文件配置的环境信息 final Environment environment = configuration.getEnvironment(); // 创建事务管理器工厂 final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); // 创建事务管理器 tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); // 根据Mybatis主配置文件中指定的Executor类型创建对应的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(); } }}
- 3)、Executor 是真正用来执行 SQL 的执行器
- 4)、默认执行器为 SimpleExecutor
final Executor executor = configuration.newExecutor(tx, execType);
public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; // 根据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); } // 如果cacheEnabled属性为ture,这使用CachingExecutor对上面创建的Executor进行装饰 if (cacheEnabled) { executor = new CachingExecutor(executor); } // 执行拦截器链的拦截逻辑 executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
4、Executor 执行 SQL 过程详解
- 1)、初始化 SqlSession 对象,并拿到 Configuration 对象
- 2)、通过全路径获取 MappedStatement
package com.blog4java.mybatis.example;import com.alibaba.fastjson.JSON;import com.blog4java.common.DbUtils;import com.blog4java.mybatis.example.entity.UserEntity;import org.apache.ibatis.executor.Executor;import org.apache.ibatis.io.Resources;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.session.*;import org.apache.ibatis.transaction.jdbc.JdbcTransaction;import org.junit.Before;import org.junit.Test;import java.io.IOException;import java.io.InputStream;import java.sql.SQLException;import java.util.List;public class ExecutorExample { @Before public void initData() { DbUtils.initData(); } @Test public void testExecutor() throws IOException, SQLException { // 获取配置文件输入流 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); // 通过SqlSessionFactoryBuilder的build()方法创建SqlSessionFactory实例 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 调用openSession()方法创建SqlSession实例 SqlSession sqlSession = sqlSessionFactory.openSession(); Configuration configuration = sqlSession.getConfiguration(); // 从Configuration对象中获取描述SQL配置的MappedStatement对象 MappedStatement listAllUserStmt = configuration.getMappedStatement( "com.blog4java.mybatis.com.blog4java.mybatis.example.mapper.UserMapper.listAllUser"); //创建ReuseExecutor实例 Executor reuseExecutor = configuration.newExecutor( new JdbcTransaction(sqlSession.getConnection()), ExecutorType.REUSE ); // 调用query()方法执行查询操作 List<UserEntity> userList = reuseExecutor.query(listAllUserStmt, null, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER); System.out.println(JSON.toJSON(userList)); }}
- 2)创建 Executor 对象
//创建ReuseExecutor实例Executor reuseExecutor = configuration.newExecutor( new JdbcTransaction(sqlSession.getConnection()), ExecutorType.REUSE);
public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; // 根据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); } // 如果cacheEnabled属性为ture,这使用CachingExecutor对上面创建的Executor进行装饰 if (cacheEnabled) { executor = new CachingExecutor(executor); } // 执行拦截器链的拦截逻辑 executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
- 3)、执行获取结果
// 调用query()方法执行查询操作List<UserEntity> userList = reuseExecutor.query(listAllUserStmt,null,RowBounds.DEFAULT,Executor.NO_RESULT_HANDLER);System.out.println(JSON.toJSON(userList));
BaseExecutor
@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); } @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); } 以上是关于六SqlSession 的创建过程以及 Executor 执行 SQL 过程详解的主要内容,如果未能解决你的问题,请参考以下文章
SqlSessionFactory创建SqlSession的过程
MyBatis 基础知识总结 5SqlSessionFactory和SqlSession
最最常用的 SqlSessionFactory 和 SqlSession,你真的了解吗?
Mybatis学习笔记-增删改的操作 -对SqlSession的优化封装-优化代码