目录
数据处理的发展
1.原生JDBC
2. DBUtils工具类 [jdbctemp..]
3. ORM [MyBatis]
MyBatis概述
① MyBatis 是一款优秀的持久层框架 [ORM],它支持自定义 SQL、存储过程以及高级映射;
② MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作;
③ MyBatis 可以通过简单的 XML文件或注解 将Java对象配置和映射为数据库中的记录;
Java对象:原始类型、接口和 Java POJO [Plain Old Java Objects 普通老式Java对象]
④ MyBatis里面,SQL和代码是分离的,所以会写SQL基本上就会用MyBatis
简单而言:会写SQL语句 你就可以像进行Java编码一样,来完成数据操作
MyBatis核心流程
观察测试类
public void test2() throws Exception{
// 1.获取配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
// 2.加载解析配置文件并获取SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
// 3.根据 SqlSessionFactory对象获取SqlSession对象
SqlSession sqlSession = factory.openSession();
//sqlSession.selectOne("");
// 4.通过SqlSession中提供的 API方法来操作数据库
UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> list = mapper.selectUserList();
for (User user : list) {
System.out.println(user);
}
// 5.关闭会话
sqlSession.close();
}
重要对象和流程
代码简单,我们需要从中提取代码中出现过的重要对象,由此切入核心对象和关键流程分析:
1. SqlSessionFactory初始化
2. 创建SqlSession
3. XxxMapper [代理]
4. SQL操作
SqlSessionFactory [初始化]
获取SqlSessionFactory 对象的主干流程:
// --SqlSessionFactoryBuilder类--// build() 重载一
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
// build() 重载二
public SqlSessionFactory build(InputStream inputStream, String environment, Properties
properties) {
try {
// 用于解析 mybatis-config.xml,同时创建了 Configuration 对象 >>
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment,properties);
// 解析XML,最终返回一个 DefaultSqlSessionFactory >>
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
// build() 重载三
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
MyBatis - Builder
1. XMLConfigBuilder - 解析全局配文件
2. XMLMapperBuilder - 解析Mapper映射文件
3. XMLStatementBuilder - 解析Mapper映射文件中的数据操作节点[CURD]
4. SqlSourceBuilder - 解析SQL语句
5. XMLScriptBuilder - 解析动态SQL
6. MapperBuilderAssistant-工具类[辅助XMLMapperBuilder解析mapper.xml 完善属性信息]
parser.parse()
解析mybatis-config.xml
mapperElement - 获取Configuration
mapperParser.parse() - 解析Mapper映射文件
// --XMLConfigBuilder类--// 默认构造器
public XMLConfigBuilder(InputStream inputStream, String environment,
Properties props) {
// XMLMapperEntityResolver类用于完成配置文件的校验,根据对应的DTD文件来实现// 1.new XPathParser() >>
// 2.this() 转调构造器重载 >>
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()),
environment, props);
}
// --XPathParser类--
// 【完成配置文件的校验、相关属性的初始化操作、创建XPathFactory对象】
public XPathParser(InputStream inputStream, boolean validation,
Properties variables, EntityResolver entityResolver) {
// 完成相关属性的初始化操作
commonConstructor(validation, variables, entityResolver);// 创建Document对象 本质上是通过DOM来解析的,整个配置文件都会加载到内存中
this.document = createDocument(new InputSource(inputStream));
}
// --XMLConfigBuilder类--
// 【初始化Configuration、对应属性设置、设定是否解析标记】
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
super(new Configuration()); // 完成了Configuration的初始化
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props); // 设置对应的Properties属性
this.parsed = false; // 设置 是否解析的标志为 false
this.environment = environment; // 初始化environment
this.parser = parser; // 初始化 解析器}
// --Configuration--// 可观察 new Configuration() >>
public Configuration() {
// 为类型注册别名
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
// ...
}
// --XMLConfigBuilder类--public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;// evalNode方法,读取根节点 XPathParser,dom 和 SAX 都有用到 >>
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
// 进入parseConfiguration方法 >>
private void parseConfiguration(XNode root) {
try {
// 对于全局配置文件各种标签的解析
propertiesElement(root.evalNode("properties"));// 解析 settings 标签
Properties settings = settingsAsProperties(root.evalNode("settings"));// 读取文件
loadCustomVfs(settings);// 日志设置
loadCustomLogImpl(settings);// 类型别名
typeAliasesElement(root.evalNode("typeAliases"));// 插件
pluginElement(root.evalNode("plugins"));// 用于创建对象
objectFactoryElement(root.evalNode("objectFactory"));// 用于对对象进行加工
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));// 反射工具箱
reflectorFactoryElement(root.evalNode("reflectorFactory"));// settings 子标签赋值,默认值就是在这里提供的 >>
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
// 创建了数据源 >>
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 ... Cause: " + e, e);
}
}
// --XMLConfigBuilder类--
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
// child [configuration - mappers - package|mapper]
for (XNode child : parent.getChildren()) {
// 进入mapperParser.parse方法 >>
mapperParser.parse();
}
}
}
// --XMLMapperBuilder类--
public void parse() {
// 总体上做了两件事情:对于语句的注册 和 接口的注册
if (!configuration.isResourceLoaded(resource)) {
// 1、具体增删改查标签的解析。
// 一个标签 创建一个MappedStatement与之对应 >>
configurationElement(parser.evalNode("/mapper"));
configuration.addLoadedResource(resource);// 2、把namespace(接口类型)和工厂类绑定起来,放到一个map
// 一个namespace 一个 MapperProxyFactory >>
bindMapperForNamespace();
}
parsePendingResultMaps();
parsePendingCacheRefs();
parsePendingStatements();
}
// --XMLMapperBuilder类--
private void configurationElement(XNode context) {
try {
String namespace = context.getStringAttribute("namespace");
if (namespace == null || namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
builderAssistant.setCurrentNamespace(namespace);// 添加缓存对象
cacheRefElement(context.evalNode("cache-ref"));// 解析 cache 属性,添加缓存对象
cacheElement(context.evalNode("cache"));// 创建 ParameterMapping 对象
parameterMapElement(context.evalNodes("/mapper/parameterMap"));// 创建 List<ResultMapping>
resultMapElements(context.evalNodes("/mapper/resultMap"));// 解析可以复用的SQL
sqlElement(context.evalNodes("/mapper/sql"));// 解析增删改查标签,得到 MappedStatement >>
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
} catch (Exception e) {
throw new BuilderException("Error...'" + resource + "'. Cause: " + e, e);
}
}
// 在buildStatementFromContext()方法中,创建了用来解析增删改查标签的XMLStatementBuilder,并且把创建 的MappedStatement添加到mappedStatements中
private void buildStatementFromContext(List<XNode> list) {
if (configuration.getDatabaseId() != null) {
buildStatementFromContext(list, configuration.getDatabaseId());
}
// 解析 Statement >>
buildStatementFromContext(list, null);
}
// 进入重载方法
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
for (XNode context : list) {
// 用来解析增删改查标签的 XMLStatementBuilderfinal XMLStatementBuilder statementParser =
new XMLStatementBuilder(configuration, builderAssistant,
context, requiredDatabaseId);
try {
// 解析 Statement,添加 MappedStatement 对象 >>
statementParser.parseStatementNode();
} catch (IncompleteElementException e) {
configuration.addIncompleteStatement(statementParser);
}
}
}
// 进入statementParser.parseStatementNode()方法
// --XMLStatementBuilder类--
public void parseStatementNode() {
String id = context.getStringAttribute("id");
String databaseId = context.getStringAttribute("databaseId");
// ...
// >> 关键的一步: MappedStatement 的创建 >>
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
// 进入addMappedStatement()方法
// --MapperBuilderAssistant--
public MappedStatement addMappedStatement(String id,
//...
String resultSets) {
// 创建 MappedStatement 对象
MappedStatement对象 statement = statementBuilder.build();// 最关键的一步,在 Configuration 添加了 MappedStatement >>
configuration.addMappedStatement(statement);
return statement;
}
// 进入addMappedStatement()方法 观察
// --Configuration类--
public void addMappedStatement(MappedStatement ms) {
mappedStatements.put(ms.getId(), ms);// 观察mappedStatements对象
// protected final Map<String, MappedStatement> mappedStatements = new
StrictMap<MappedStatement>
}
// --XMLMapperBuilder类--
private void bindMapperForNamespace() {
String namespace = builderAssistant.getCurrentNamespace();
if (namespace != null) {
Class<?> boundType = null;
try {
// 根据名称空间加载对应的接口类型
boundType = Resources.classForName(namespace);
} catch (ClassNotFoundException e) {
}
if (boundType != null) {
// 判断 在MapperRegistry中是否注册的有当前类型的 MapperProxyFactory对象
if (!configuration.hasMapper(boundType)) {
configuration.addLoadedResource("namespace:" + namespace);// 添加到 MapperRegistry,本质是一个 map,里面也有 Configuration >>
configuration.addMapper(boundType);
}
}
}
}
// --Configuration类--
public <T> void addMapper(Class<T> type) {
mapperRegistry.addMapper(type);
}
public <T> void addMapper(Class<T> type) {
if (type.isInterface()) { // 检测 type 是否为接口
if (hasMapper(type)) { // 检测是否已经加装过该接口
throw new BindingException("Type " + type + "...");
}
boolean loadCompleted = false;
try {
// !Map<Class<?>, MapperProxyFactory<?>> 存放的是接口类型,和对应的工厂类的关系
knownMappers.put(type, new MapperProxyFactory<>(type));// 注册了接口之后,根据接口,开始解析所有方法上的注解,例如 @Select >>
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);// 进入parse()方法 >>
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
// 进入parse()方法
// --MapperAnnotationBuilder类--
public void parse() {
String resource = type.toString();
if (!configuration.isResourceLoaded(resource)) {
// 先判断 Mapper.xml 有没有解析,没有的话先解析 Mapper.xml(例如定义 package 方式)
loadXmlResource();
configuration.addLoadedResource(resource);
assistant.setCurrentNamespace(type.getName());// 处理 @CacheNamespace
parseCache();// 处理 @CacheNamespaceRef
parseCacheRef();// 获取所有方法
Method[] methods = type.getMethods();
for (Method method : methods) {
try {
if (!method.isBridge()) {
// 该方法主要是解析对应类方法上的update、insert、delete、select等注解
// 添加到 MappedStatement 集合中 >>
parseStatement(method);
}
} catch (IncompleteElementException e) {
configuration.addIncompleteMethod(new MethodResolver(this, method));
}
}
}
// 处理解析异常的SQL节点parsePendingMethods();
}
创建SqlSession会话对象
// --测试类--SqlSession sqlSession = factory.openSession();
// --DefaultSqlSessionFactory--// DefaultSqlSessionFactory提供获得Session的多个方法,这些方法可以根据需要设定Session的SQL执行器的类
//型、事务类型和是否自动提交
public SqlSession openSession() {
// DefaultSqlSessionFactory >>
return openSessionFromDataSource(configuration.getDefaultExecutorType(),
null, false);
}
// --DefaultSqlSessionFactory--
/**
* 以上方法最终都执行本方法,设定SQL执行器的类型、事务隔离等级以及是否自动提交的设置
*
* @param execType 执行器类型
* @param level 事务隔离级别
* @param autoCommit 自动提交
* @return
*/
private SqlSession openSessionFromDataSource(ExecutorType execType,
TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();// 获取事务工厂 >>
final TransactionFactory transactionFactory =
getTransactionFactoryFromEnvironment(environment);
// 创建事务
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
// 根据事务工厂和默认的执行器类型,创建执行器 >>
final Executor executor = configuration.newExecutor(tx, execType);// mybatis根据这些方法提供不同设置的 DefaultSqlSession 实例
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
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 {
// 默认 SimpleExecutor
executor = new SimpleExecutor(this, transaction);
}
// 二级缓存开关,settings 中的 cacheEnabled 默认是 trueif (cacheEnabled) {
executor = new CachingExecutor(executor);
}
// 植入插件的逻辑,至此,四大对象已经全部拦截完毕
executor=(Executor)interceptorChain.pluginAll(executor);
return executor;
}
创建过程中,发现,最后拿到了一个DefaultSqlSession;
DefaultSqlSession中存在:configuration对象、Executor对象;
Executor对象时SQL的真实执行者。
创建XxxMapper[代理]对象
创建Mapper对象的过程,实质上时获取了一个JDK动态代理对象的过程;
这个代理类会继承Proxy类,实现被代理的接口,其持有一个实现了InvocationHandler接口的MapperProxy类型的触发管理类。
// --测试类--
// 4.通过SqlSession中提供的 API方法来操作数据库 >>
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// --SqlSession接口--<T> T getMapper(Class<T> type);
// --DefaultSqlSession类--
public <T> T getMapper(Class<T> type) {
return configuration.getMapper(type, this);
}
// --Configuration类--
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// mapperRegistry中注册的有Mapper的相关信息 在解析映射文件时 调用过addMapper方法// 从mapperRegistry中获取对象 >>
return mapperRegistry.getMapper(type, sqlSession);
}
// --MapperRegistry类--
// 获取Mapper接口对应的代理对象
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// 从knownMappers中 获取Mapper接口对应的 MapperProxyFactory 对象// knownMappers的内容在何时存入?
// XMLConfigBuilder的mapperElement()方法 package分支处final MapperProxyFactory<T> mapperProxyFactory =
(MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known ...");
}
try {
// 进入newInstance()方法 >>
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
// --MapperProxyFactory类--public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<>
(sqlSession, mapperInterface, methodCache);
// newInstance() >>
return newInstance(mapperProxy);
}
// 创建实现了 mapperInterface 接口的代理对象
protected T newInstance(MapperProxy<T> mapperProxy){
// 返回代理对象
// 1.类加载器;2.被代理类实现的接口;3.实现了 InvocationHandler 的触发管理类return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(),
new Class[]{mapperInterface},mapperProxy);
}
执行SQL操作 [复杂一丢丢]
// --测试类--// 调用接口方法
List<User> list = mapper.selectUserList();
// --MapperProxy类--
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// toString hashCode equals getClass等方法,无需走到执行SQL的流程if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}else{
// 提升获取 mapperMethod 的效率,到 MapperMethodInvoker(内部接口) 的 invoke
// 普通方法会走到 PlainMethodInvoker(内部类) 的 invoke >>
return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
}
}catch(Throwable t){
throw ExceptionUtil.unwrapThrowable(t);
}
}
interface MapperMethodInvoker {
// 进入到 MapperProxy 接口实现类 PlainMethodInvoker 的 invoke() 方法 >>
Object invoke(Object proxy, Method method, Object[] args,
SqlSession sqlSession) throws Throwable;
}
private static class PlainMethodInvoker implements MapperMethodInvoker {
private final MapperMethod mapperMethod;
public PlainMethodInvoker(MapperMethod mapperMethod) {
}
public Object invoke(Object proxy, Method method, Object[] args,
SqlSession sqlSession) throws Throwable {
// 调用 execute 方法执行 SQL [SQL执行的真正起点] >>return mapperMethod.execute(sqlSession, args);
}
}
// --MapperMethod类--
// execute() 方法中 会根据不同的数据操作type 做不同的方法调用
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;// 根据 SQL 类型 执行相应的数据库操作 调用SqlSession对应的方法
switch (command.getType()) {
case INSERT: {
// convertArgsToSqlCommandParam() 将 方法参数 转换为 SQL的参数
// 通过 ParamNameResolver 处理args[] 数组 将用户传入的实参和指定参数名称关联起来
Object param = method.convertArgsToSqlCommandParam(args);// sqlSession.insert() 调用SqlSession的insert方法
// rowCountResult 方法会根据 method 字段中记录的方法的返回值类型对结果进行转换result = rowCountResult(sqlSession.insert(command.getName(), param));break;
}
case UPDATE: {
}
case DELETE: {
}
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
// 返回值为空 且 ResultSet通过 ResultHandler处理的方法
executeWithResultHandler(sqlSession, args);
result = null;
}
// ...
else {
// 返回值为 单一对象的方法
Object param = method.convertArgsToSqlCommandParam(args);// 普通 select 语句的执行入口
// 分析 selectOne() 方法 它会涉及到其他方法的调用 流程比较全面result = sqlSession.selectOne(command.getName(), param);
}
}
return result;
}
// --SqlSession接口--<T> T selectOne(String statement, Object parameter);
// --DefaultSqlSession类--
// 来到了对外的接口的默认实现类DefaultSqlSession,selectOne()最终也是调用了selectList()方法
public <T> T selectOne(String statement, Object parameter) {
// 来到了 DefaultSqlSession >>
List<T> list = this.selectList(statement, parameter);
if (list.size() == 1) {
return list.get(0);
} else if (list.size() > 1) {
throw new TooManyResultsException("Expected ... : " + 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) {
try {
// 根据command name(Statement ID)从Configuration中拿到MappedStatement// ms 中有xml中增删改查标签配置的所有属性,包括:
// id、statementType、sqlSource、useCache、入参、出参等
MappedStatement ms = configuration.getMappedStatement(statement);// 如果 cacheEnabled = true(默认),Executor会被 CachingExecutor装饰
// 执行 Executor [CachingExecutor] 的 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();
}
}
// --CachingExecutor类--
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds,
ResultHandler resultHandler) throws SQLException {
// 获取SQL
BoundSql boundSql = ms.getBoundSql(parameterObject);// createCacheKey() 方法创建了CacheKey >>
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);// CacheKey生成之后 query()方法重载 >>>>
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
/**
* 在计算 CacheKey 的过程中,有很多影响因子参与了计算。
* 比如 MappedStatement 的 id 字段、SQL 语句、分页参数、运行时变量、Environment 的 id 字段等。
* 通过让这些影响因子参与计算,可以很好的区分不同查询请求,
* 所以,我们可以简单的把 CacheKey 看做是一个查询请求的 id。有了 CacheKey,就可以使用它读写缓存了。* 什么样的SQL是同一条SQL?
* 看下方代码,
* 也就是说,方法相同、翻页偏移相同、SQL相同、参数值相同、数据源环境相同,才会被认为是同一个查询。
*/
// --BaseExecutor类--
public CacheKey createCacheKey() {
cacheKey.update(ms.getId()); // 方法相同[com.gupaoedu.mapper.BlogMapper.selectBlogById]
cacheKey.update(rowBounds.getOffset()); // 翻页偏移相同
cacheKey.update(rowBounds.getLimit()); // 2147483647 = 2^31-1
cacheKey.update(boundSql.getSql()); // SQL相同
cacheKey.update(value); // 参数值相同
cacheKey.update(configuration.getEnvironment().getId()) // 数据源环境相同
}
// --CachingExecutor类--// 查二级缓存
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds,
ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
Cache cache = ms.getCache();// cache 对象是在哪里创建的? XMLMapperBuilder类
xmlconfigurationElement()
// 由 <cache> 标签决定
if (cache != null) {
// flushCache="true" 清空一级二级缓存 >>
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);// 获取二级缓存
// 缓存通过 TransactionalCacheManager、TransactionalCache 管理@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
// 若二级缓存未命中,则进入BaseExecutor,向一级缓存或者数据库进行查询 >>
// 调用 BaseExecutor 类 的query()方法 >>>>
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
// 写入二级缓存
tcm.putObject(cache, key, list);
}
return list;
}
}
// 走到 SimpleExecutor | ReuseExecutor | BatchExecutor
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
// --BaseExecutor类--// CachingExecutor - delegate.query() >> BaseExecutor - query()// 查一级缓存
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds,
ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
// 异常体系之 ErrorContext
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()) {
// flushCache="true"时,即使是查询,也清空一级缓存
clearLocalCache();
}
List<E> list;
try {
// 防止递归查询重复处理缓存
queryStack++;// 查询一级缓存
// ResultHandler 和 ResultSetHandler的区别
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();
}
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
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 {
// 三种 Executor 的区别,看doUpdate
// 默认SimpleExecutor实现 >>
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;
}
// --SimpleExecutor类--/
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds,
ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
// StatementHandler -> Statement
try {
Configuration configuration = ms.getConfiguration();// 注意,已经来到SQL处理的关键对象 StatementHandler >>
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
// 获取一个 Statement对象 >>>>
stmt = prepareStatement(handler, ms.getStatementLog());// 执行查询 >>>>>>
return handler.query(stmt, resultHandler);
} finally {
// 用完就关闭
closeStatement(stmt);
}
}
/
// --Configuration类--
// 在newStatementHandler()中,new了一个StatementHandler,先得到RoutingStatementHandler
public StatementHandler newStatementHandler(Executor executor,
MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// new RoutingStatementHandler() >>
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
// 植入插件逻辑(返回代理对象) [下次课讲]
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
// RoutingStatementHandler 就是一个功能路由 里面没有任何的实现,是用来创建基本的StatementHandler的。这里会根据MappedStatement里面的statementType决定StatementHandler的类型。
// 默认是PREPARED [STATEMENT、PREPARED、CALLABLE]
// --RoutingStatementHandler类--
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// StatementType 是怎么来的? 增删改查标签中的 statementType="PREPARED",默认值 PREPAREDs
witch(ms.getStatementType()) {
case STATEMENT:
delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED:
// 创建 StatementHandler 的时候做了什么? >>
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 ... : " + ms.getStatementType());
}
}
// --PreparedStatementHandler类--
public PreparedStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
super(executor, mappedStatement, parameter, rowBounds, resultHandler, boundSql);
}
// --BaseStatementHandler类--
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, ObjectparameterObject, 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;
// 创建了四大对象的其它两大对象 >>
// 创建这两大对象的时候分别做了什么?
this.parameterHandler = configuration.newParameterHandler(
mappedStatement, parameterObject, boundSql);
this.resultSetHandler = configuration.newResultSetHandler(executor,
mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
// 四大对象都是可以被插件拦截的四大对象之一,所以在创建之后都要用拦截器进行包装的方法// 抬头一起看看与 newStatementHandler() 同在 Configuration 类中的其他几个方法// --Configuration类--
public ParameterHandler newParameterHandler() {
}
public ResultSetHandler newResultSetHandler() {
}
public StatementHandler newExecutor() {
}
// 流程回到 SimpleExecutor 类的 doQuery() 方法
// prepareStatement() 方法 创建 Statement 对象
// --SimpleExecutor类--
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;// 获取 数据库连接 对象
Connection connection = getConnection(statementLog);// 获取 Statement 对象 [BaseStatementHandler]
stmt = handler.prepare(connection, transaction.getTimeout());// 为 Statement 设置 IN参数
handler.parameterize(stmt);
return stmt;
}
// 流程回到 SimpleExecutor 类的 doQuery() 方法
// query() 方法 执行查询操作 进入PreparedStatementHandler >>
// --PreparedStatementHandler类--
public <E> List<E> query(Statement statement, ResultHandler resultHandler)
throws SQLException {
// 调用 JDBC PreparedStatement API 执行操作
// 使用结果处理器对结果集进行处理
PreparedStatement ps = (PreparedStatement) statement;// 执行 SQL [到了JDBC流程] >>
ps.execute();// 处理结果集
return resultSetHandler.handleResultSets(ps);
}