Mybatis源码笔记

news2024/9/27 12:09:34
String resource = "mybatis-config.xml";
        Reader reader;
        try {
            //将XML配置文件构建为Configuration配置类
            reader = Resources.getResourceAsReader(resource);
            // 通过加载配置文件流构建一个SqlSessionFactory  DefaultSqlSessionFactory
            SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder().build(reader);
            // 数据源 执行器  DefaultSqlSession
            SqlSession session = sqlMapper.openSession();
            try {
                // 执行查询 底层执行jdbc
                User user = (User)session.selectOne("com.tuling.mapper.UserMapper.selectById", 1L);

                UserMapper mapper = session.getMapper(UserMapper.class);
                System.out.println(mapper.getClass());
                User user = mapper.selectById(1L);
                session.commit();
                System.out.println(user.getUserName());
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                session.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder().build(reader);

这句话主要就是解析我们的xml配置文件生成Configuration对象,构建SqlSessionFactory
在这里插入图片描述
我们看下xml怎么变成Configuration的

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--SqlSessionFactoryBuilder中配置的配置文件的优先级最高;config.properties配置文件的优先级次之;properties标签中的配置优先级最低 -->
    <properties resource="org/mybatis/example/config.properties">
      <property name="username" value="dev_user"/>
      <property name="password" value="F2Fa3!33TYyg"/>
    </properties>

    <!--一些重要的全局配置-->
    <settings>
    <setting name="cacheEnabled" value="true"/>
    <!--<setting name="lazyLoadingEnabled" value="true"/>-->
    <!--<setting name="multipleResultSetsEnabled" value="true"/>-->
    <!--<setting name="useColumnLabel" value="true"/>-->
    <!--<setting name="useGeneratedKeys" value="false"/>-->
    <!--<setting name="autoMappingBehavior" value="PARTIAL"/>-->
    <!--<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>-->
    <!--<setting name="defaultExecutorType" value="SIMPLE"/>-->
    <!--<setting name="defaultStatementTimeout" value="25"/>-->
    <!--<setting name="defaultFetchSize" value="100"/>-->
    <!--<setting name="safeRowBoundsEnabled" value="false"/>-->
    <!--<setting name="mapUnderscoreToCamelCase" value="false"/>-->
    <!--<setting name="localCacheScope" value="STATEMENT"/>-->
    <!--<setting name="jdbcTypeForNull" value="OTHER"/>-->
    <!--<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>-->
    <!--<setting name="logImpl" value="STDOUT_LOGGING" />-->
    </settings>

    <typeAliases>

    </typeAliases>

    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!--默认值为 false,当该参数设置为 true 时,如果 pageSize=0 或者 RowBounds.limit = 0 就会查询出全部的结果-->
            <!--如果某些查询数据量非常大,不应该允许查出所有数据-->
            <property name="pageSizeZero" value="true"/>
        </plugin>
    </plugins>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://10.59.97.10:3308/windty"/>
                <property name="username" value="windty_opr"/>
                <property name="password" value="windty!234"/>
            </dataSource>
        </environment>
    </environments>

    <databaseIdProvider type="DB_VENDOR">
        <property name="MySQL" value="mysql" />
        <property name="Oracle" value="oracle" />
    </databaseIdProvider>

    <mappers>
        <!--这边可以使用package和resource两种方式加载mapper-->
        <!--<package name="包名"/>-->
        <!--<mapper resource="./mappers/SysUserMapper.xml"/>-->
        <mapper resource="./mappers/CbondissuerMapper.xml"/>
    </mappers>

</configuration>

在这里插入图片描述
构建了XMLConfigBuilder 对象用来解析xml
这里面没啥好说的,就是解析xml然后负值到Configuration属性上,包括日志、别名、插件、数据源、数据库厂商、typeHandlermapper,这样我们Configuration对象就构建好了。

重点看下mapper怎么解析的

在这里插入图片描述
构建了XMLMapperBuilder用来解析namespace、参数、resultMap、缓存等
ResultMap

org.apache.ibatis.builder.xml.XMLMapperBuilder#resultMapElement(org.apache.ibatis.parsing.XNode, java.util.List<org.apache.ibatis.mapping.ResultMapping>, java.lang.Class<?>)

这里会构建ResultMapping集合
在这里插入图片描述
其实也就是我们一些jdbcType、javaType,对应的列,以及resultMap唯一id
在这里插入图片描述

然后放到

  protected final Map<String, ResultMap> resultMaps = new StrictMap<>("Result Maps collection");

id 就是 唯一id

接下来看怎么解析sql 标签
在这里插入图片描述

org.apache.ibatis.builder.xml.XMLStatementBuilder#parseStatementNode

解析一些缓存、节点名称、节点类型SqlCommandType(后续执行sql 会用到,判断是增删改查)、自增id、解析sql、resultMap 最后封装成MappedStatement当道Configuration的mappedStatements中,key 就是namsespace+MappedStatementId
重点看下sql 怎么解析的
在这里插入图片描述
分为动态sql、和静态sql,返回SqlSource 放入我们的MappedStatement
sqlSource 有getBoundSql 方法
在这里插入图片描述
然后创建 MapperProxyFactory 放入到
Configuration的MapperRegistry的knownMappers.put(type, new MapperProxyFactory<>(type));

SqlSession session = sqlMapper.openSession();

在这里插入图片描述
其实就是构建了我们的DefaultSqlSession,DefaultSqlSession对象中包含Executor和Configuration
我们看下Executor
在这里插入图片描述
默认就是SimpleExecutor
如果开启缓存CachingExecutor,然后调用拦截器

UserMapper mapper = session.getMapper(UserMapper.class);

在这里插入图片描述
在这里插入图片描述
可以看到就是从我们的configuration的mapperRegistry 中拿,看下具体怎么拿的
在这里插入图片描述

在这里插入图片描述
从knownMappers拿到MapperProxyFactory,MapperProxyFactory创建代理,所以最后返回的对象就是MapperProxy

User user = mapper.selectById(1L);

也就是我们代理对象 的

org.apache.ibatis.binding.MapperProxy#invoke

在这里插入图片描述

首先 封装 MapperMethod
在这里插入图片描述
在这里插入图片描述
通过MappedStatement解析出name和type

接下来执行
在这里插入图片描述
其实最后还是调用了sqlSession的方法
sqlSession最后还是调用了executor
在这里插入图片描述

在这里插入图片描述
拿出sql
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
会解析我们的sql,还记得上面的动态sql吗
在这里插入图片描述

如果开启了二级缓存,从二级缓存先取
在这里插入图片描述
在这里插入图片描述
可以看到二级缓存是装饰器模式,可以实现线程安全、fifo内存淘汰、命中率统计
二级缓存没有,从一级缓存取,一级缓存就是一个map
一级缓存是sqlSession级别的,insert、update 操作会清空缓存,commit 也会,所以同一个sqllSerssion 多次操作 会命中一级缓存,一级缓存默认开启,二级缓存默认关闭,且可以持久化,二级缓存提交的时候才回去更新进去,防止回滚脏读,之前也是暂存在map里
org.apache.ibatis.cache.decorators.TransactionalCache#flushPendingEntries
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
new RoutingStatementHandler的时候会初始化父类,这个时候会进行
在这里插入图片描述
在这里插入图片描述
ParameterHandler和ResultSetHandler的拦截
StatementHandler 拦截

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
通过typeHandler 设置我们的参数
在这里插入图片描述
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleResultSet
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleRowValues
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleRowValuesForNestedResultMap
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#applyPropertyMappings
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#getPropertyMappingValue

大概思想就是通过
TypeHandler 对应类型的实现类 从resultSet 中 通过列名 拿到对应的java类型的值,反射放到object上

Plugin

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

上面说过 ParameterHandler、ResultSetHandler、StatementHandler、Executor实例化后会调用我们的InterceptorChain.pluginAll方法,其实就是调用每个拦截器的plugin方法
所以我们plugin方法就是返回代理对象,默认Plugin.wrap(target, this);
我们看看他做了什么
在这里插入图片描述
其实也就是判断当前自定义注解上的type和 目前调用plugin是不是一样,一样就能返回代理对象,那代理对象调用的时候如果方法包含目标方法又回调了我们Interceptor的intercept方法,否则调用本身方法
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/367003.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多点电容触摸屏实验

目录 一、简介 二、硬件原理 ​编辑1、CT_INT 2、I2C2_SCL和I2C2_SDA 3、RESET复位引脚 三、FT54x6/FT52x6电容触摸芯片 四、代码编写 1、编写ft5426.h 2、编写ft5426.c 3、main函数 一、简介 电容屏只需要手指轻触即可&#xff0c;而电阻屏是需要手指给予一定的压力才…

Elasticsearch7.8.0版本进阶——动态更新索引

目录一、如何在保留不变性的前提下实现倒排索引的更新二、按段搜索执行流程三、按段搜索的文档查询四、按段搜索的文档删除五、按段搜索的文档更新一、如何在保留不变性的前提下实现倒排索引的更新 用更多的索引。通过增加新的补充索引来反映最近的修改&#xff0c;而不是直接…

【华为OD机试模拟题】用 C++ 实现 - 整理扑克牌(2023.Q1)

最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…

[Flink]部署模式(看pdf上的放上面)

运行一个wordcountval dataStream: DataStream[String] environment.socketTextStream("hadoop1", 7777) //流式数据不能进行groupBy,流式数据要来一条处理一次.0表示第一个元素,1表示第二个元素 //keyBy(0)根据第一个元素进行分组 val out: DataStream[(String, In…

Spring Boot中使用Sa-Token实现轻量级登录与鉴权

1. Sa-Token 介绍 Sa-Token 是一个轻量级 Java 权限认证框架&#xff0c;主要解决&#xff1a;登录认证、权限认证、单点登录、OAuth2.0、分布式Session会话、微服务网关鉴权 等一系列权限相关问题。 功能结构图 2. 登录认证 对于一些登录之后才能访问的接口&#xff08;例如&…

Graph Embedding基础 图表示学习 什么是Graph Embedding

本文包括 DeepWalk LINE SDNE Node2vec Struc2vec等几个重要的Graph Embedding 方法 先说下不同embedding的区别是什么&#xff1a; DeepWalk&#xff1a;采用随机游走&#xff0c;形成序列&#xff0c;采用skip-gram方式生成节点embedding。node2vec&#xff1a;不同的随机游…

[游戏开发][Unity]Assetbundle打包篇(4)开始打包

上一篇文章讲了如何收集打包资源&#xff0c;得到了一个List<AssetInfo>下面正式进入打包流程&#xff0c;调用PostAssetBuild方法即可开始正式打包流程public void PostAssetBuild() {Debug.Log("------------------------------OnPostAssetBuild-----------------…

ASE140N04-ASEMI低压MOS管ASE140N04

编辑-Z ASE140N04在TO-220F封装里的静态漏极源导通电阻&#xff08;RDS(ON)&#xff09;为4mΩ&#xff0c;是一款N沟道低压MOS管。ASE140N04的最大脉冲正向电流ISM为400A&#xff0c;零栅极电压漏极电流(IDSS)为1uA&#xff0c;其工作时耐温度范围为-55~175摄氏度。ASE140N04…

深入浅出——this的理解与使用

文章目录 this的语法理解一、this的绑定方式二、两个细节 1.严格模式引入库2.如何更改this指向总结this的语法理解 this在英文中是一个指示代词&#xff0c;表示 这&#xff1b;这个 顾名思义&#xff0c;在编程于语言里&#xff0c;this就是一个指代作用。 我在人民广场吃…

《分布式技术原理与算法解析》学习笔记Day20

CAP理论 什么是CAP理论&#xff1f; CAP理论用来指导分布式系统设计&#xff0c;以保证系统的可用性、数据一致性等。 C&#xff0c;Consistency&#xff0c;一致性&#xff0c;指所有节点在同一时刻的数据是相同的&#xff0c;即更新操作执行结束并响应用户完成后&#xff…

GO 中的 defer 有哪些注意事项?上

xdm &#xff0c; 不知道你们是否有使用过 defer &#xff0c;这种语法在是 go 特有的&#xff0c;用起来真是爽的不要不要的 很多时候&#xff0c;我们在使用一些新东西&#xff0c;出现一些莫名其妙的现象或者是结果的时候&#xff0c;我们总会认为&#xff0c;这个东西不友…

打游戏什么蓝牙耳机好用?打游戏比较好的蓝牙耳机

游戏耳机提供身临其境的细致声音&#xff0c;同时也是与朋友在线聊天的绝佳通信设备&#xff0c;尤其对于游戏玩家来说&#xff0c;聆听和被聆听的最佳方式之一就是游戏耳机&#xff0c;那2023年到底有哪些值得购买的游戏耳机呢&#xff1f;现在就让我们一起来看看吧。 第一款…

【uniapp】uniapp项目vue2/vue3引入使用vant组件库

前言 vant是一个优秀的移动端组件库&#xff0c;他支持VUE2、VUE3、微信小程序三个框架&#xff0c;这期就来尝试在uniapp中&#xff0c;vue2和vue3分别引入vant组件库 注意&#xff1a;本教程只适用H5&#xff0c;无法运行到微信小程序 Vue3引入vant 新建一个uniapp项目&am…

如何利用 Python 进行客户分群分析(附源码)

每个电子商务数据分析师必须掌握的一项数据聚类技能 如果你是一名在电子商务公司工作的数据分析师&#xff0c;从客户数据中挖掘潜在价值&#xff0c;来提高客户留存率很可能就是你的工作任务之一。 然而&#xff0c;客户数据是巨大的&#xff0c;每个客户的行为都不一样。20…

python中安装gurobi和pycharm没有语法提示问题解决

安装gurobi第一步 &#xff1a;下载gurobi ( http://www.gurobi.com ) &#xff0c;需要注册账号第二步、申请License注册如果可以通过校园网&#xff0c; 则直接生成。不能的话&#xff0c;通过网站&#xff0c;发邮件申请 http://www.gurobi.cn/NewsView1.Asp?id4第三、邮件…

【虹科】基于Lidar的体积监控实现高效的库存管理

迄今为止&#xff0c;很多物料厂家测量库存的结果数据仍然不准确&#xff0c;会存在很大的误差&#xff0c;导致供应链效率低下——这个问题可以通过Lidar技术轻松解决。近年来&#xff0c;全球供应链的脆弱性已经多次得到证明。无论是油轮被困在苏伊士运河&#xff0c;阻塞海峡…

JSP 在线学习管理系统myeclipse定制开发sqlserver数据库网页模式java编程jdbc

一、源码特点 JSP 在线学习管理系统是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为SQLServer2008&#x…

从事Python自动化测试,30岁熬到月薪20K+,分享我的多年面试经…

年少不懂面试经&#xff0c;读懂已是测试人。 大家好&#xff0c;我是小码哥&#xff0c;一名历经沧桑&#xff0c;看透互联网行业百态的测试从业者&#xff0c;经过数年的勤学苦练&#xff0c;精钻深研究&#xff0c;终于从初出茅庐的职场新手成长为现在的测试老鸟&#xff0…

nodejs/eggjs如何使用第三方pure esm lib

问题Instead change the require of index.js in xxx/app/ws/index.ts to a dynamic import() which is available in all CommonJS modules.上述错误发生在我使用import引入一个第三方包的时候提示的&#xff0c;至于原因&#xff0c;主要是node当前仅支持cjs&#xff0c;而目…

TCP的三握四挥

本文是向大家介绍tcp的三次握手四次挥手的全过程&#xff0c;能够让我们更熟悉面向连接的传输层控制协议的原理&#xff0c;保证了数据传输的稳定性和可靠性。如果我们把网络体系按照OSI模型划分&#xff0c;那么不论是从上往下还是从下往上数&#xff0c;处于最中间的都是传输…