持久层Mybatis3底层源码分析,原理解析
Mybatis-持久层的框架,功能是非常强大的,对于移动互联网的高并发 和 高性能是非常有利的,相对于Hibernate全自动的ORM框架,Mybatis简单,易于学习,sql编写在xml文件中,和代码分离,易于维护,属于半ORM框架,对于面向用户层面的互联网业务性能和并发,可以通过sql优化解决一些问题。
现如今大部分公司都在使用Mybatis,所以我们要理解框架底层的原理。闲话不多说。
Mybatis框架的核心入口 是SqlSessionFactory接口,我们先看一下它的代码
public interface SqlSessionFactory { SqlSession openSession(); SqlSession openSession(boolean autoCommit);
SqlSession openSession(Connection connection);
SqlSession openSession(TransactionIsolationLevel level); SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection); Configuration getConfiguration(); }
SqlSessionFactory
SqlSessionFactory接口很多重载的openSession方法,返回sqlSession类型 对象, 还有Configuration类(这个类非常强大,下面会梳理),我们先看一下SqlSession的代码
public interface SqlSession extends Closeable { <T> T selectOne(String statement); <T> T selectOne(String statement, Object parameter); <E> List<E> selectList(String statement); <E> List<E> selectList(String statement, Object parameter); <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds); <K, V> Map<K, V> selectMap(String statement, String mapKey);
<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey); <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds); <T> Cursor<T> selectCursor(String statement);
<T> Cursor<T> selectCursor(String statement, Object parameter); <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds); void select(String statement, Object parameter, ResultHandler handler); void select(String statement, ResultHandler handler); List<BatchResult> flushStatements(); /**
* Closes the session
*/
@Override
void close(); void clearCache(); Configuration getConfiguration(); <T> T getMapper(Class<T> type); Connection getConnection();
}
sqlSeesion
只是展示了部分代码,但我们可以看到,sqlSeesion里面 大多数方法是 增删改查的执行方法,包括查询返回不同的数据结构,比较注意的是clearCache()和getConnection()方法,一个是清楚缓存,一个是获取连接,获取数据库连接在这不在描述, 为什么要注意清楚缓存那,因为mybatis框架是实现了 缓存的,分为一级缓存,二级缓存,当增删改的时候就会调用此方法,删除缓存(后续会专门写一篇文章来分析Mybatis缓存),先在这给大家熟悉一下。
上面的SqlSessionFactory和SqlSeesion都是接口,我们在看一下实现类DefaultSqlSessionFactory和DefaultSqlSession,下面展示DefaultSqlSessionFactory的比较核心的代码
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);
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();
}
}
DefaultSqlSessionFactory
其实SqlSessionFactory中的多个重载openSeesion方法最终都是执行的这个方法,我们可以看到这个方法中 通过 configuration属性 获取到Executor 执行器对象,DefaultSqlSession构造器把这configuration和executor当成构造参数,初始化创建一个 DefaultSqlSession对象,然后我们在展示一下DefaultSqlSession代码中的大家一看就理解的代码
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
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();
}
}
DefaultSession
看到这个方法大家估计就会看明白了,底层执行的就是 通过Executor 对象执行的 查询, 通过configuration获取到 要执行的sql,获取到我们需要的结果。
从上面代码可以看出 Configuration 类无处不在,那我们就去看一下源码
public class Configuration { protected Environment environment; protected boolean safeRowBoundsEnabled;
protected boolean safeResultHandlerEnabled = true;
protected boolean mapUnderscoreToCamelCase;
protected boolean aggressiveLazyLoading;
protected boolean multipleResultSetsEnabled = true;
protected boolean useGeneratedKeys;
protected boolean useColumnLabel = true;
protected boolean cacheEnabled = true;
protected boolean callSettersOnNulls;
protected boolean useActualParamName = true;
protected boolean returnInstanceForEmptyRow; protected String logPrefix;
protected Class <? extends Log> logImpl;
protected Class <? extends VFS> vfsImpl;
protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
protected JdbcType jdbcTypeForNull = JdbcType.OTHER;
protected Set<String> lazyLoadTriggerMethods = new HashSet<String>(Arrays.asList(new String[] { "equals", "clone", "hashCode", "toString" }));
protected Integer defaultStatementTimeout;
protected Integer defaultFetchSize;
protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;
protected AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior = AutoMappingUnknownColumnBehavior.NONE; protected Properties variables = new Properties();
protected ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
protected ObjectFactory objectFactory = new DefaultObjectFactory();
protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory(); protected boolean lazyLoadingEnabled = false;
protected ProxyFactory proxyFactory = new JavassistProxyFactory(); // #224 Using internal Javassist instead of OGNL protected String databaseId;
/**
* Configuration factory class.
* Used to create Configuration for loading deserialized unread properties.
*
* @see <a href='https://code.google.com/p/mybatis/issues/detail?id=300'>Issue 300 (google code)</a>
*/
protected Class<?> configurationFactory; protected final MapperRegistry mapperRegistry = new MapperRegistry(this);
protected final InterceptorChain interceptorChain = new InterceptorChain();
protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();
protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry(); protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection");
protected final Map<String, Cache> caches = new StrictMap<Cache>("Caches collection");
protected final Map<String, ResultMap> resultMaps = new StrictMap<ResultMap>("Result Maps collection");
protected final Map<String, ParameterMap> parameterMaps = new StrictMap<ParameterMap>("Parameter Maps collection");
protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<KeyGenerator>("Key Generators collection"); protected final Set<String> loadedResources = new HashSet<String>();
protected final Map<String, XNode> sqlFragments = new StrictMap<XNode>("XML fragments parsed from previous mappers"); protected final Collection<XMLStatementBuilder> incompleteStatements = new LinkedList<XMLStatementBuilder>();
protected final Collection<CacheRefResolver> incompleteCacheRefs = new LinkedList<CacheRefResolver>();
protected final Collection<ResultMapResolver> incompleteResultMaps = new LinkedList<ResultMapResolver>();
protected final Collection<MethodResolver> incompleteMethods = new LinkedList<MethodResolver>(); /*
* A map holds cache-ref relationship. The key is the namespace that
* references a cache bound to another namespace and the value is the
* namespace which the actual cache is bound to.
*/
protected final Map<String, String> cacheRefMap = new HashMap<String, String>();}
Configuration
上面的代码都是 Configuration类中的属性值,上面的boolean 类型的属性 都是一些配置的属性,比如useGeneratedKeys是否开启使用返回主键,cacheEnabled是否开启缓存等等,下面的Map类型的 就是存储一些我们项目中需要编写的sql.xml文件,我们可以通过变量名大致推测出来存储的结果,比如typeAliasRegistry 存储的别名,mappedStatements 存储的sql,resultMaps存储的结果等,当然这些map的key对应的就是 sql.xml中的唯一的id,分析到现在,我们大致知道Mybatis框架底层的执行原理了。
但是,这时候就有个疑问了,入口类是SqlSessionFactory,那是怎么加载资源的那,我们通过名称寻找源码,可以找到一个SqlSessionFactoryBuilder(这些开发开源框架的牛人们不管技术NB,对类的命名也是很值的大家效仿的),builder--加载, 说明这个类就是加载 SqlSessionFactory,我们看一下代码
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 {
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.
}
}
} public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
} public SqlSessionFactory build(InputStream inputStream, String environment) {
return build(inputStream, environment, null);
} public SqlSessionFactory build(InputStream inputStream, Properties properties) {
return build(inputStream, null, properties);
} public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
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.
}
}
} public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
} }
SqlSessionFactoryBuilder
查看代码中的build方法,可以看出是 通过流来加载xml文件 ,包括mybatis的配置文件和 sql.xml文件,返回一个DefaultSqlSessionFactory 对象。
本篇文件只是介绍了mybatis的底层执行原理,喜欢深入了解的可以自己去深入了解一下。
以上是个人理解,欢迎大家来讨论,不喜勿喷!谢谢!!
如转载,请注明转载地址,谢谢
持久层Mybatis3底层源码分析,原理解析的更多相关文章
- List-LinkedList、set集合基础增强底层源码分析
List-LinkedList 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 继上一章继续讲解,上章内容: List-ArreyLlist集合基础增强底层源码分析:https:// ...
- List-ArrayList集合基础增强底层源码分析
List集合基础增强底层源码分析 作者:Stanley 罗昊 [转载请注明出处和署名,谢谢!] 集合分为三个系列,分别为:List.set.map List系列 特点:元素有序可重复 有序指的是元素的 ...
- LInkedList总结及部分底层源码分析
LInkedList总结及部分底层源码分析 1. LinkedList的实现与继承关系 继承:AbstractSequentialList 抽象类 实现:List 接口 实现:Deque 接口 实现: ...
- Vector总结及部分底层源码分析
Vector总结及部分底层源码分析 1. Vector继承的抽象类和实现的接口 Vector类实现的接口 List接口:里面定义了List集合的基本接口,Vector进行了实现 RandomAcces ...
- MyBatis 源码分析 - 配置文件解析过程
* 本文速览 由于本篇文章篇幅比较大,所以这里拿出一节对本文进行快速概括.本篇文章对 MyBatis 配置文件中常用配置的解析过程进行了较为详细的介绍和分析,包括但不限于settings,typeAl ...
- v72.01 鸿蒙内核源码分析(Shell解析) | 应用窥伺内核的窗口 | 百篇博客分析OpenHarmony源码
子曰:"苟正其身矣,于从政乎何有?不能正其身,如正人何?" <论语>:子路篇 百篇博客系列篇.本篇为: v72.xx 鸿蒙内核源码分析(Shell解析篇) | 应用窥视 ...
- 鸿蒙内核源码分析(ELF解析篇) | 你要忘了她姐俩你就不是银 | 百篇博客分析OpenHarmony源码 | v53.02
百篇博客系列篇.本篇为: v53.xx 鸿蒙内核源码分析(ELF解析篇) | 你要忘了她姐俩你就不是银 | 51.c.h.o 加载运行相关篇为: v51.xx 鸿蒙内核源码分析(ELF格式篇) | 应 ...
- JAVA ArrayList集合底层源码分析
目录 ArrayList集合 一.ArrayList的注意事项 二. ArrayList 的底层操作机制源码分析(重点,难点.) 1.JDK8.0 2.JDK11.0 ArrayList集合 一.Ar ...
- Cocos2d-X3.0 刨根问底(八)----- 场景(Scene)、层(Layer)相关源码分析
本章节我们重点分析Cocos2d-x3.0与 场景.层相关的源码.这部分源码集中在 libcocos2d –> layers_scenes_transitions_nodes目录下面 我先发个截 ...
随机推荐
- Xcode工程编译错误之iOS开发之The Xcode build system has crashed. Please close and reopen your workspace
解决方法: . 删除DerivedData . 参照上面的链接设置:File -> Workspace Settings -> Build System -> Legacy Buil ...
- 操作系统与cpu
- PowerDesigner软件建立新模型。
打开PowerDesigner软件,选择菜单文件->建立新模型,或者敲击键盘ctrl+N 弹出建立新模型窗口,模型类型选择Object-Oriented Model,图选择Class D ...
- node.js爬取ajax接口数据
爬取页面数据与爬取接口数据,我还是觉得爬取接口数据更加简单一点,主要爬取一些分页的数据. 爬取步骤: 1.明确目标接口地址,举个例子 : https://www.vcg.com/api/common/ ...
- LAYUI select 下拉框得高度
页面下得select 框 在css页面加样式 .layui-form-select dl { max-height: 152px;}
- FEX(Fabric Extender)
一.FEX Cisco Nexus 2000 FEX作为N5K.N6K.N7K.FI的一个远程线卡,单独的2K是没有网管功能的,必须配合父系交换机使用. 主要解决TOR和EOR的问题,TOR,接线简单 ...
- C# 字典Dictionary
Dictionary<TKey, TValue> 泛型类提供了从一组键到一组值的映射.通过键来检索值的速度是非常快的,接近于 O(1),这是因为 Dictionary<TKey, T ...
- 运维面试题之k8s
前言: 到了如今年k8s已经是事实上的容器集群标准了,是时候展现我真正的祖传k8s实力了 吐槽: 我干嘛要知道这些,能用不就行了k8s真香 Kubernetes有哪些特性? Kubernetes是自动 ...
- ELK日志分析解决方案
概要 ELK(Elasticsearch , Logstash, Kibana的简称)是目前比较流行的日志分析解决方案,核心包括了三个部分 Elasticsearch:日志查询分析引擎 Logstas ...
- PHP----------一群猴子排成一圈,按1,2,...,n依次编号。
1.一群猴子排成一圈,按1,2,...,n依次编号.然后从第1只开始数,数到第m只,把它踢出圈,从它后面再开始数,再数到第m只,在把它踢出去...,如此不停的进行下去, 直到最后只剩下一只猴子为止,那 ...