mybatis笔记3 一些原理的理解
1,mybatis流程跟踪,原理理解
基本思路: 从SqlSessionFactory的初始化出发,观察资源的准备和环境的准备,以及实现持久层的一些过程;
进入SqlSessionFactoryBean类,发现先执行的是
然后是:
在初始化类之后,做的准备工作如下:
public void afterPropertiesSet() throws Exception {
notNull(dataSource, "Property 'dataSource' is required");//1,检查spring准备的datasource是否ok
notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");//2,检查空构造方法的sqlSessionFactoryBuilder是否准备好this.sqlSessionFactory = buildSqlSessionFactory();//3,利用配置的属性,构造sqlSessionFactory
}构造细节如下:方法有点长,注意注释这个是流程,之后我画一个图来加深理解;
protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
Configuration configuration;
XMLConfigBuilder xmlConfigBuilder = null;
if (this.configLocation != null) {//1,检查是否有配置configLocation,即mybatis的整体配置文件,非mapper文件,如果有加载进去,没有,构造一个空的
xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
configuration = xmlConfigBuilder.getConfiguration();
} else {
if (logger.isDebugEnabled()) {
logger.debug("Property 'configLocation' not specified, using default MyBatis Configuration");
}
configuration = new Configuration();
configuration.setVariables(this.configurationProperties);
}if (this.objectFactory != null) {//2,检查对象工厂,如果有设置进去,没有留空
configuration.setObjectFactory(this.objectFactory);
}if (this.objectWrapperFactory != null) {//3,检查对象装饰工厂,如果有设置进去,没有留空
configuration.setObjectWrapperFactory(this.objectWrapperFactory);
}if (hasLength(this.typeAliasesPackage)) {//4,检查包的简称,如果有注册进去
String[] typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
for (String packageToScan : typeAliasPackageArray) {
configuration.getTypeAliasRegistry().registerAliases(packageToScan,
typeAliasesSuperType == null ? Object.class : typeAliasesSuperType);
if (logger.isDebugEnabled()) {
logger.debug("Scanned package: '" + packageToScan + "' for aliases");
}
}
}if (!isEmpty(this.typeAliases)) {//5,检查类的简称,如果有注册进去
for (Class<?> typeAlias : this.typeAliases) {
configuration.getTypeAliasRegistry().registerAlias(typeAlias);
if (logger.isDebugEnabled()) {
logger.debug("Registered type alias: '" + typeAlias + "'");
}
}
}if (!isEmpty(this.plugins)) {//6,检查插件,如果有注册进去
for (Interceptor plugin : this.plugins) {
configuration.addInterceptor(plugin);
if (logger.isDebugEnabled()) {
logger.debug("Registered plugin: '" + plugin + "'");
}
}
}if (hasLength(this.typeHandlersPackage)) {//7,检查类型转换类包,如果有注册进去
String[] typeHandlersPackageArray = tokenizeToStringArray(this.typeHandlersPackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
for (String packageToScan : typeHandlersPackageArray) {
configuration.getTypeHandlerRegistry().register(packageToScan);
if (logger.isDebugEnabled()) {
logger.debug("Scanned package: '" + packageToScan + "' for type handlers");
}
}
}if (!isEmpty(this.typeHandlers)) {//8,检查类型转换类,如果有注册进去
for (TypeHandler<?> typeHandler : this.typeHandlers) {
configuration.getTypeHandlerRegistry().register(typeHandler);
if (logger.isDebugEnabled()) {
logger.debug("Registered type handler: '" + typeHandler + "'");
}
}
}if (xmlConfigBuilder != null) {//9,检查是否有xml的构造器,如果有,直接使用构造器构造
try {
xmlConfigBuilder.parse();if (logger.isDebugEnabled()) {
logger.debug("Parsed configuration file: '" + this.configLocation + "'");
}
} catch (Exception ex) {
throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
} finally {
ErrorContext.instance().reset();
}
}if (this.transactionFactory == null) {//10,检查事物工厂,如果没有,构造一个spring管理的事物工厂
this.transactionFactory = new SpringManagedTransactionFactory();
}//11,构造环境变量
Environment environment = new Environment(this.environment, this.transactionFactory, this.dataSource);
configuration.setEnvironment(environment);if (this.databaseIdProvider != null) {
try {//12,检查是否配置了db id,如果有,设置到配置的类中
configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
} catch (SQLException e) {
throw new NestedIOException("Failed getting a databaseId", e);
}
}if (!isEmpty(this.mapperLocations)) {//13,把配置的mapper弄进来总配置文件里
for (Resource mapperLocation : this.mapperLocations) {
if (mapperLocation == null) {
continue;
}try {
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
configuration, mapperLocation.toString(), configuration.getSqlFragments());
xmlMapperBuilder.parse();
} catch (Exception e) {
throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
} finally {
ErrorContext.instance().reset();
}if (logger.isDebugEnabled()) {
logger.debug("Parsed mapper file: '" + mapperLocation + "'");
}
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("Property 'mapperLocations' was not specified or no matching resources found");
}
}return this.sqlSessionFactoryBuilder.build(configuration);//14,最后通过得到的配置类来构造一个sqlsessionFactory工厂
}设置好属性之后,执行
得到factory构造的bean,即sqlSessionFactory,
最后容器启动成功的事件监控
public void onApplicationEvent(ApplicationEvent event) {
if (failFast && event instanceof ContextRefreshedEvent) {
// fail-fast -> check all statements are completed
this.sqlSessionFactory.getConfiguration().getMappedStatementNames();
}
}以上是资源的准备,下面来一次增删改查的跟踪,观察内部的工作原理;
查询单条记录的过程:
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);//1,通过转换,得到存储的mapperedStatement
List<E> result = executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);//2,转换成jdbc代码执行
return result;
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}内部就像是一台精密的仪器,去除了大量的模版jdbc代码;
mybatis笔记3 一些原理的理解的更多相关文章
- Mybatis笔记01-基本原理,配置文件,映射文件,以及调用过程
Mybatis基本原理 应用程序找Mybatis要数据 mybatis从数据库中找来数据 2.1 通过mybatis-config.xml 定位哪个数据库 2.2 通过Category.xml执行对应 ...
- Python源代码剖析笔记3-Python运行原理初探
Python源代码剖析笔记3-Python执行原理初探 本文简书地址:http://www.jianshu.com/p/03af86845c95 之前写了几篇源代码剖析笔记,然而慢慢觉得没有从一个宏观 ...
- 动态代理之投鞭断流!看一下MyBatis的底层实现原理
转:https://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&mid=2247486856&idx=1&sn=d430be5d14d1 ...
- MyBatis笔记二:配置
MyBatis笔记二:配置 1.全局配置 1.properites 这个配置主要是引入我们的 properites 配置文件的: <properties resource="db.pr ...
- Atitit 泛型原理与理解attilax总结
Atitit 泛型原理与理解attilax总结 1. 泛型历史11.1.1. 由来11.2. 为什么需要泛型,类型安全21.3. 7.泛型的好处22. 泛型的机制编辑22.1.1. 机制32.1.2. ...
- 从tcp原理角度理解Broken pipe和Connection reset by peer的区别
从tcp原理角度理解Broken pipe和Connection reset by peer的区别 http://lovestblog.cn/blog/2014/05/20/tcp-broken-pi ...
- C++标准库第二版笔记 3 和异常的理解 1
C++标准库第二版笔记 3 和异常的理解 1 差错和异常(error and exception)的处理 标准异常类(exception class) 定义于 分为: 1.语言本身支持的异常 2.标准 ...
- Mybatis笔记二:接口式编程
目录 旧方法的弊端 接口式编程 接口式编程的好处 接口式编程的增删改查 旧方法的弊端 在Mybatis笔记一中,我们使用命名空间+id的方式实现了Mybatis的执行,不过这里的命名空间是我们随便写的 ...
- 对CAP原理的理解
对CAP原理的理解 CAP原理按照定义,指的是C(Consistency)一致性,A(Availability)可用性,P(Partition tolerance)分区容错性在一个完整的计算机系统中三 ...
随机推荐
- nodejs利用ajax实现网页无刷新上传图片
nodejs利用ajax实现网页无刷新上传图片 标签(空格分隔): nodejs 通常情况下上传图片是要通过提交form表单来实现的,但是这又不可避免的产生了网页转. 利用ajax技术和FormDat ...
- ThinkPHP 模板substr的截取字符串函数
ThinkPHP 模板substr的截取字符串函数在Common/function.php加上以下代码 /** ** 截取中文字符串 **/ function msubstr($str, $start ...
- ecshop验证码
<?php //仿制ecshop验证码(四位大写字母和数字.背景) //处理码值(四位大写字母和数字组成) //所有的可能的字符集合 $chars = 'ABCDEFGHIJKLMNOPQRST ...
- 一个软件开发者的BPM之路
我是小林,一名普通的软件工程师,从事BPM(业务流程管理)软件开发工作.我没有几十年的技术底蕴,无法像大牛们一样高谈阔论,品评BPM开发之道:也不是资深的流程管理专家,能与大家分析流程管理的时弊.我只 ...
- https 安全验证问题
最近为了满足苹果的 https 要求, 经过努力终于写出了方法 验证 SSL 证书是否满足 ATS 要求 nscurl --ats-diagnostics --verbose https://你的域名 ...
- 关于Genymotion下载比较慢的解决办法
Genymotion号称Android模拟器中运行最快的,但是服务器在国外,Android镜像下载起来那个速度就不想说了. Add new device后下载速度太慢了,容易失败 先登录,然后add, ...
- Alwayson的IP冲突
Alwayson的IP冲突 https://social.technet.microsoft.com/Forums/office/en-US/4d50cb1c-eef7-4dcc-b937-3c8eb ...
- CSS3变形记(上):千变万化的Div
传统上,css就是用来对网页进行布局和渲染网页样式的.然而,css3的出现彻底打破了这一格局.了解过css3的人都知道,css3不但可以对网页进行布局和渲染样式,还可以绘制一些图形.对元素进行2D和3 ...
- 增强版字典DictionaryEx
代码 public class DictionaryEx<TKey, TValue> : IDictionary<TKey, TValue> { /// <summary ...
- 如何在腾讯开放平台的云服务器上安装php和memcache 一
由于被通知腾讯的CEE要关闭了,必须自己切换到服务器,自己装php.烦到一个B. 首先找到官方wiki: http://wiki.qcloud.com/wiki/SUSE%E7%8E%AF%E5%A2 ...


