《拉勾Java高薪课程》阶段一输出 之 持久层框架设计实现及MyBatis源码分析-学习笔记 --菜鸟小回

2023-11-06

阶段一模块一学习笔记


文章目录


前言:由于一段时间的外包生活,觉得自己技术开始落后,很多基础知识和底层已经遗忘殆尽。对所有的框架都所谓“知其然而不知所以然”,焦虑袭上心头的时候发现了拉勾高薪课程。目前学习完mybatis源码实现和spring手写ioc和aop,感受颇多。此文结合讲师的设计模式解析。自己总结并结合身边实例,输出自己学习内容。

相关拉勾课程输出笔记:模块一:房屋租赁流程理解设计模式(单例模式,代理模式,工厂模式)
专栏地址:拉勾专栏(持续更新…)


一、自定义持久层框架

1. JDBC问题总结:

原始jdbc开发存在的问题如下:

  1. 数据库连接创建、释放频繁造成系统资源浪费,从而影响系统性能。
  2. Sql语句在代码中硬编码,造成代码不易维护,实际应用中sql变化的可能较大,sql变动需要改变
    java代码。
  3. 使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能
    多也可能少,修改sql还要修改代码,系统不易维护。
  4. 对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据 库
    记录封装成pojo对象解析比较方便
    enter description here

2. 问题解决思路

  1. 使用数据库连接池初始化连接资源
  2. 将sql语句抽取到xml配置文件中
  3. 使用反射、内省等底层技术,自动将实体与表进行属性与字段的自动映射

3. 自定义框架设计

使用端:
提供核心配置文件:

  • sqlMapConfig.xml : 存放数据源信息,引入mapper.xml
  • Mapper.xml : sql语句的配置文件信息
    框架端:
  1. 读取配置文件
    读取完成以后以流的形式存在,我们不能将读取到的配置信息以流的形式存放在内存中,不好操作,可
    以创建javaBean来存储
    (1)Configuration : 存放数据库基本信息、Map<唯一标识,Mapper> 唯一标识:namespace + “.” +
    id
    (2)MappedStatement:sql语句、statement类型、输入参数java类型、输出参数java类型
  2. 解析配置文件
    创建sqlSessionFactoryBuilder类:
    if (connection != null) { try {connection.close(); } catch (SQLException e) { e.printStackTrace(); }} }
    方法:sqlSessionFactory build():
    第一:使用dom4j解析配置文件,将解析出来的内容封装到Configuration和MappedStatement中
    第二:创建SqlSessionFactory的实现类DefaultSqlSession
  3. 创建SqlSessionFactory:
    方法:openSession() : 获取sqlSession接口的实现类实例对象
  4. 创建sqlSession接口及实现类:主要封装crud方法
    方法:selectList(String statementId,Object param):查询所有
    selectOne(String statementId,Object param):查询单个
    具体实现:封装JDBC完成对数据库表的查询操作
    涉及到的设计模式:
    Builder构建者设计模式、工厂模式、代理模式

4. 实际项目目录分析

  • 使用端:enter description here
  • 框架端:22222222
  • 源码:git clone -b master1 https://gitee.com/idse666666/lagou.git

5. 优化

5-1: 将测试类方法

enter description here
封装为分别的dao方法
enter description here

5-2: 仍存在问题:
  • dao的实现类中存在重复的代码,整个操作的过程模板重复(加载配置文件、创建sqlsessionFactory,调用sqlsession方法)
  • dao的实现类中存在硬编码,调用sqlsession的方法时,参数statement的id硬编码
5-3: 解决方式
  • 使用代理模式生成dao层接口的代理实现类
  • SqlSessionImpl中添加如下方法
    enter description here
  • 使xml中的路径对应上到层路径,xml方法名对应dao层方法名,此时就可以删除UserDao的接口实现类了
    enter description here
    enter description here
  • 源码:git clone -b master2 https://gitee.com/idse666666/lagou.git

6.课后小结以及个人思考

  • 课后练习:enter description here
  • 个人思考:mybatis的自定义实现是:xml配置方式记录数据库连接信息以及想要执行的sql->以文件流形式传入到框架端->框架端解析后利用其构建sqlsessionFactory工厂->使用工厂生产sqlsession->sqlsession实现具体的sql方法->有参数的sql需要使用对应工具类->优化过程使用代理模式,用dao层的包名.方法名巧妙映射xml中的namespace.id 从而解决了硬编码,代码重复问题

二、mybatis

1.相关概念

  1. ORM:ORM完成面向对象的编程语言到关系数据库的映射;ORM框架实现的效果:把对持久化对象的保存、修改、删除 等操作,转换为对数据库的操作
  2. 简介:MyBatis是一款优秀的基于ORM的半自动轻量级持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis可以使用简单的XML或注解来配置和映射原生类型、接口和Java对象为数据库中的记录。
  3. Mybatis的优势:Mybatis是一个半自动化的持久层框架,对开发人员开说,核心sql还是需要自己进行优化,sql和java编码进行分离,功能边界清晰,一个专注业务,一个专注数据。

2.具体实现

  1. 编写SqlMapperConfig.xml,其中配置mapper.xml信息
    enter description here
  2. UserMapper.xml信息
    enter description here
  3. 生产出sqlsession后调用其selectList接口即可,添加insert,修改update,删除delete。除了查询都需要提交事务。传递参数信息。
    enter description here

3、优化:

  1. 优化一:使用dao层实现,实则仍需要加载配置文件创建工厂以及生产sqlsession:
    enter description here
  • 源码:git clone -b master3 https://gitee.com/idse666666/lagou.git
  • 省略掉dao层实现,直接将mapper.xml的namespace对应到dao的资源包
    enter description here
  • 使用配置文件
    enter description here

2. mybatis常用标签:

  • 一对一映射:association
  • 一对多映射:collection
  • 判断:if
  • 循环:foreach
//例:
<if test="p.depaCode != null and p.depaCode != ''">
   and u.depa_code in
   <foreach collection="p.umsDepas" separator="," close=")" open="(" item="item" index="index">
   	#{item}
   </foreach>
</if>
  • 源码 git clone -b master4 https://gitee.com/idse666666/lagou.git

3.mybatis缓存

3-1. 缓存概念:
  • 缓存就是内存中的数据,常常来自对数据库查询结果的保存,使用缓存,我们可以避免频繁的与数据库进行交互,进而提高响应速度
  • 一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的
  • 二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的
  • enter description here
3-2. 验证一级缓存:
  • 一级缓存验证
    enter description here
    enter description here
  • 总结:
    2-1. 第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从 数据
    库查询用户信息。得到用户信息,将用户信息存储到一级缓存中。
    2-2. 如果中间sqlSession去执行commit操作(执行插入、更新、删除),则会清空SqlSession中的 一级
    缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
    2-3. 第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直 接从
    缓存中获取用户信息
    enter description here
    enter description here
3-3. 一级缓存源码分析
  • 找到源码的存储结构为HashMap
    enter description here
  • 在执行query方法时,判断缓存的存在状态,存在直接取出,不存在查询数据库
    enter description here
    查询数据库得到结果后放入一级缓存中
    enter description here
3-4. 二级缓存
  • 二级缓存的原理和一级缓存原理一样,第一次查询,会将数据放入缓存中,然后第二次查询则会直接去缓存中取。但是一级缓存是基于sqlSession的,而二级缓存是基于mapper文件的namespace的,也就是说多个sqlSession可以共享一个mapper中的二级缓存区域,并且如果两个mapper的namespace 相同,即使是两个mapper,那么这两个mapper中执行sql查询到的数据也将存在相同的二级缓存区域 中
    enter description here

  • 二级缓存需要手动开启

//sqlMapConfig.xml中
<!--开启二级缓存  -->
<settings>
   <setting name="cacheEnabled" value="true"/>
</settings>
//mapper.xml中
<!--开启二级缓存--> 
<cache>
</cache>
//或者注解方式在mapper接口上方
@CacheNamespace
//同时要注意实体类需要序列化
User implements Serializable

验证

  • 多个session在同一个mapper的namespace中,不同session会缓存数据
    enter description here
  • 同一个mapper的namespace中有一个提交了增删改事务,二级缓存清空
    enter description here

二级缓存附加配置:mybatis中还可以配置userCache和flushCache等配置项

  • useCache=true(默认)改为false时禁用该statement二级缓存
  • flushCache=true(默认)改为false时禁用该statement提交事务后时刷新二级缓存(可能出现脏读)

4. 二级缓存自定义

  • 因为mybatis自带的二级缓存无法在分布式环境下正常使用,选用redis作为分布式缓存
  • 使用@CacheNamespace(implementation = RedisCache.class)注解,使用redis缓存
  • 查阅源码可知 redis配置文件名称固定:redis.properties;redisCache为HashMap
    enter description here
  • 验证结果
    enter description here

5. mybatis插件

  • mybatis在四大组件(Executor、StatementHandler、ParameterHandler、ResultSetHandler)处提供了简单易用的插 件扩展机制

  • 实际上就是一个拦截器,可以自定义
    enter description here

  • 源码 git clone -b master5 https://gitee.com/idse666666/lagou.git

三、Mybatis架构原理

1. 架构设计

enter description here

2. 主要构件及其相互关系

enter description here
3.

3. 二级缓存源码优先级别

二级缓存>一级缓存>数据库

4. 二级缓存的存取机制

  • 只有提交了SqlSession.commit(),后二级缓存才被真正写入

  • 存储二级缓存对象的时候是放到了TransactionalCache.entriesToAddOnCommit这个map中,但是每次查询的时候是直接从TransactionalCache.delegate中去查询的,所以这个二级缓存查询数据库后,设置缓存值是没有立刻生效的,主要是因为直接存到 delegate 会导致脏数据问题
    enter description here

  • MyBatis二级缓存只适用于不常进行增、删、改的数据,比如国家行政区省市区街道数据。一但数据变更,MyBatis会清空缓存。因此二级缓存不适用于经常进行更新的数据。

  • 源码 git clone -b master6 https://gitee.com/idse666666/lagou.git

5. 延迟加载

5-1 延迟加载概念:
  • 就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载。
  • 优点:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表 速度要快。
  • 缺点:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时 间,所以可能造成用户等待时间变长,造成用户体验下降
5-2 实现
//1.返回resultMap
<select id="findById" resultMap="userMap"  >
	select * from user where id = #{id}
</select>
//2.设置fetchType="lazy,并指定子查询的全路径和参数值
<resultMap id="userMap" type="com.lagou.pojo.User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<collection property="orderList" ofType="com.lagou.pojo.Order"
			select="com.lagou.mapper.IOrderMapper.findOrderByUid" column="id" fetchType="lazy">
	<id property="id" column="oid"/>
	<result property="orderTime" column="ordertime"/>
	<result property="total" column="total"/>
</collection>
</resultMap>
//3.子查询,需要id作为参数值
<select id="findOrderByUid" resultType="com.lagou.pojo.Order">
select * from orders where uid = #{uid}

enter description here

5-3 通过以上配置延迟加载,实现如果只查询一级用户信息,二级查询则不会执行

enter description here

5-4 全局延迟加载
<settings>
	<!--开启全局延迟加载功能-->
	<setting name="lazyLoadingEnabled" value="true"/> 
</settings>
  • 源码 git clone -b master7 https://gitee.com/idse666666/lagou.git

四、设计模式:

1. mybatis中用到的设计模式

enter description here

2. 构建者模式

2-1.构建者模式概念

Builder模式的定义是"将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。”,它属于创建类模式,一般来说,如果一个对象的构建比较复杂,超出了构造函数所能包含的范围,就可以使用工厂模式和Builder模式,相对于工厂模式会产出一个完整的产品,Builder应用于更加复杂的对象的构建,甚至只会构建产品的一个部分,直白来说,就是使用多个简单的对象一步一步构建成一个复杂的对象

2-2. 例:分别构建出电脑的各个组件

enter description here
enter description here

2-3. mybatis中体现

SqlSessionFactoryBuilder会调用XMLConfigBuilder读取所有的
MybatisMapConfig.xml 和所有的 Mapper.xml 文件,构建 Mybatis 运行的核心对象 Configuration
对象,然后将该Configuration对象作为参数构建一个SqlSessionFactory对象。
enter description here

3.工厂模式

3-1.简单工厂模式概念

在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类

3-2.例子

enter description here

3-3.mybatis中体现

SqlSessionFactory,该Factory的openSession ()方法重载了很多个,分别支持autoCommit、Executor、Transaction等参数的输入,来构建核心的SqlSession对象。该方法先从configuration读取对应的环境配置,然后初始化TransactionFactory 获得一个 Transaction 对象,然后通过 Transaction 获取一个 Executor 对象,最后通过configuration、Executor、是否autoCommit三个参数构建了 SqlSession

4.代理模式

4-1.代理模式概念

代理模式(Proxy Pattern):给某一个对象提供一个代理,并由代理对象控制对原对象的引用。代理模式 的英文叫做Proxy,它是一种对象结构型模式,代理模式分为静态代理和动态代理,

4-2.例子

enter description here

4-3.mybatis中体现

代理模式可以认为是Mybatis的核心使用的模式,正是由于这个模式,我们只需要编写Mapper.java接口,不需要实现,由Mybati s后台帮我们完成具体SQL的执行。当我们使用Configuration的getMapper方法时,会调用mapperRegistry.getMapper方法,而该方法又会调用mapperProxyFactory.newInstance(sqlSession)来生成一个具体的代理

  • 源码 git clone -b master8 https://gitee.com/idse666666/lagou.git

阶段一模块一源码(总):git clone -b master https://gitee.com/idse666666/lagou.git

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

《拉勾Java高薪课程》阶段一输出 之 持久层框架设计实现及MyBatis源码分析-学习笔记 --菜鸟小回 的相关文章

  • django 国际化

    一 开启国际化 1 setting中默认语言改为 LANGUAGE CODE es es 2 添加中间件 django middleware locale LocaleMiddleware MIDDLEWARE CLASSES django
  • 「数字货币监管」听证会重磅来袭,无形之笼悄然降临?

    美国的国会老爷们要认真讨论数字货币的监管问题了 一个全方位的数字货币监管框架正在成型 作者 唐晗 编辑 秦晋 出品 碳链价值 ID cc value 美国国会对数字货币上瘾了 7月30日 美国参议院银行 住房和城市事务委员会将于华盛顿时间上
  • 配置wsl外网访问(实操步骤)

    介绍 wsl存在一个ip1 window存在一个ip2 ip1无法ping通与ip2处于同一网段下的ip 此种情况下 涉及到网络通信相关的开发就比较困难 本文介绍配置wsl外网的访问 操作步骤 获取wsl的ip 管理员身份在powershe
  • Jenkins安装部署与自动化部署网站实战

    1 CICD与Jenkins概述 互联网软件的开发和发布 已经形成了一套标准流程 假如把开发工作流程分为以下几个阶段 编码 构建 集成 测试 交付 部署 在上图中看到 持续集成 Continuous Integration 持续交付 Con
  • 数据结构-1

    1 2 线性结构树状结构网状结构 表 数 图 数据 数值型 非数值型 1 2 3数据类型和抽象数据类型 1 3抽象数据类型 概念小结 线性表 如果在独立函数实现的 c 文件中需要包含 stdlib h 头文件 而主函数也需要包含 stdli

随机推荐

  • 服务器部署Java项目详述

    前言 记录一下自己从0到1部署Java前后端项目到服务器上的过程 过程梗概 首先要先买一个服务器 一般用CentOS7 然后大概步骤是再配置一下所买的服务器环境 再安装下对应我们的Java项目所需要的一些应用程序即可 其中 Nginx是用来
  • 如何部署LVS + keepalived 负载均衡高可用集群

    目录 一 LVS架构 概念 L4和L7负载均衡的区别 keepalive故障自动切换 抢占与非抢占 二 keepalived管理LVS负载均衡器 LVS集中节点的健康检查 三 部署LVS keeplived 高可用集群 第一步 关闭防火墙和
  • Scala中 常用容器类的函数/方法

    1 foreach 迭代遍历集合中的每个元素 对每个元素进行处理 但是没有返回值 常用于打印结果数据 val ls List 1 3 5 7 9 ls foreach println 打印每个元素 ls foreach println 打印
  • kzalloc 函数详解

    用kzalloc申请内存的时候 效果等同于先是用 kmalloc 申请空间 然后用 memset 来初始化 所有申请的元素都被初始化为 0 kzalloc allocate memory The memory is set to zero
  • wpf

    Windows Presentation Foundation WPF 是微软新一代图形系统 运行在 NET Framework 3 0架构下 为用户界面 2D 3D 图形 文档和媒体提供了统一的描述和操作方法 基于DirectX 9 10
  • DP和HDMI区别

    转自 https www toutiao com i6877677362054595080 在目前市面上显示器接口中 VGA和DVI已经逐渐退出了历史舞台 Type C还算是小众 而DP DisplayPort 与HDMI则成为了主流产品的
  • 普通人在chatGPT的3个赚钱机会

    短短的2个多月内 到处都在讨论ChatGPT 不管你有没有参与其中 以GPT为代表的AI工具已经进化到一个很恐怖的程度了 比如说最近爆火的AutoGPT 能按照一个指令自动干活了 好想试一下 让AutoGPT自动帮我分析福利彩票 ChatG
  • 实现el-form一行中多个el-form-item

    el form item默认一个占一行 利用el row和el col实现一行中多个 注意 el col span 12 中的12是一个占据的列数 默认一列总共24列 通过调整这个数字 可以调整不同列的宽度 如果只使用el col 不在外面
  • c++23中的新功能之一介绍

    一 c 23的目标和延革 c 的标准发展速度在经过c 11的近乎可以称革新的变化之后 开始步入了快车道 有的人在网上说 c 11后的c 语言和c 11以前的c 语言不是一个语言 这有点夸张了 但不可否认 其内容确实变化非常大 很多人可能都没
  • 异步处理机制 多线程

    在处理程序执行流程时 一定要切记 android的处理机制是异步处理 多线程的它并不会因为一个线程处于阻塞状态时其他的线程就不往下执行了 看看代码是不是一个线程的 如果是一个线程的 线面就阻塞了 转载于 https www cnblogs
  • SpringBoot项目将数据源变成Json文件(Jackson2RepositoryPopulatorFactoryBean实现)

    一 项目情景 有时在我们项目当中需要存储一些固定值时 会使用一些配置文件来存储 例如最常见的 json文件 它可以用来存储相应的属性以及属性值 当你需要的时候进行提取 甚至还可以基于这个 json文件写一些条件查询的语句来获得自己需要的值
  • 正则表达式转义字符

    正则表达式的转义字符 除 外 其他字符与自身匹配 点的转义 gt u002E 美元符号的转义 gt u0024 乘方符号的转义 gt u005E 左大括号的转义 gt u007B 左方括号的转义 gt u005B 左圆括号的转义 gt u0
  • 浙大python网_Python爬虫学习(8):浙大软院网络登陆保持

    在浏览器的验证窗口中输入登陆名和密码后 成功后会弹出一个小的新窗口 如果不小心关闭了这个窗口 则就会无法联网 如果说我在一个不带有桌面的Linux系统中 我是不能够通过浏览器接入网络的 虽然提供了不同系统的不同版本的客户端 没有用过 但是还
  • koa文件上传(详解koa-body)

    koa body const koa require koa const koaBody require koa body const path require path const app new koa let app new Koa
  • linux切换目录shell脚本,【Linux命令行与shell脚本编程】教程三——切换目录

    浏览文件系统 1 Linux文件路径 linux文件路径和windows文件路径不同 一个windows文件的路径可能是这样的 C Users John Documents test txt 而Linux的路径是这样的 home John
  • IOS通知中心(观察者模式)[NSNotificationCenter defaultCenter]

    通知机制和KVO都是通过 观察者模式实现的 KVO 即 Key Value Observing 它提供一种机制 当指定的对象的属性被修改后 则对象就会接受到通知 简单的说就是每次指定的被观察的对象的属性被修改后 KVO就会自动通知相应的观察
  • 深入理解计算机系统(第二版) 家庭作业 第十一章

    11 6 A 因为read requesthdrs中已经打印出了请求报头 所以只要打印请求行即可 在doit函数中第一个sscanf语句之后添加下面的语句即可 printf s s s n method uri version B 用火狐浏
  • webM文件解析--基于Matroska和EBML

    1 什么是webM 要说webM 先说Matroska Matroska是一个可扩展的 开源的多媒体容器 说简单点 容器的作用 就是把视频和音频封装到一个文件 使用这种容器的常见文件 一个是MKV 一个就是webM 两者的区别 无非是支持的
  • 大话西游灯谜答案

  • 《拉勾Java高薪课程》阶段一输出 之 持久层框架设计实现及MyBatis源码分析-学习笔记 --菜鸟小回

    阶段一模块一学习笔记 文章目录 阶段一模块一学习笔记 toc 一 自定义持久层框架 1 JDBC问题总结 2 问题解决思路 3 自定义框架设计 4 实际项目目录分析 5 优化 5 1 将测试类方法 5 2 仍存在问题 5 3 解决方式 6