Java工程师高薪训练营-第一阶段 开源框架源码解析-模块一 持久层框架涉及实现及MyBatis源码分析-任务一:自定义持久层框架
- 任务一:自定义持久层框架
任务一:自定义持久层框架
1.1 JDBC回顾及问题分析
JDBC问题分析:
| 问题 | 解决方案 |
|---|---|
| 1 数据库配置信息存在硬编码 | 使用配置文件 |
| 2 频繁创建释放数据库连接 | 使用连接池 |
| 3 SQL语句、设置参数、获取结果参数存在硬编码问题 | 使用配置文件 |
| 4 手动封装返回结果集,较为繁琐 | 使用反射、内省 |
注意:虽然有两个配置文件,但不建议放到一个文件中,因为一个是经常修改的,一个是几乎不变的,而且逻辑上也不合理,只不过可以通过特殊方式不用手动加载每一个xml文件,具体见1.3.2 sqlMapConfig.xml详解
1.2 自定义持久层框架思路分析
使用端:(项目)引入自定义持久层框架的jar包
提供两部分配置信息:数据库配置信息、SQL配置信息(SQL语句、参数类型、返回值类型)
- sqlMapConfig.xml:存放数据库配置信息
- mapper.xml:存放sql配置信息
自定义框架层本身:(工程)本质就是对JDBC代码进行封装
- 加载配置文件:根据配置文件路径,加载配置文件成字节输入流,存储在内存中
创建Resource类,方法:InputStream getResourceAsStream(String path) - 创建两个JavaBean(容器对象),存放的就是配置文件解析出来的内容
Configuration:核心配置类,存放sqlMapConfig.xml解析出来的内容
MapperStatement:映射配置类,存放mapper.xml解析出来的内容 - 解析配置文件:dom4j
创建类:SqlSessionFactoryBuilder包含方法build(InputStream in)主要做两件事:
3.1 使用dom4j解析配置文件,将解析出来的内容封装到容器对象中
3.2 创建sqlSessionFactory对象,生产SqlSession,即会话对象(增删改查都封装在这里),这里用到了工厂模式,降低程序间的耦合(不直接new一个SqlSession) - 创建SqlSessionFactory接口及实现类DefaultSqlSessionFactory,方法openSession()用以生产sqlSession
- 创建SqlSession接口及实现类DefaultSession,定义对数据库的CRUD操作(selectList、selectOne、update……)
- 创建Executor接口及实现类SimpleExecutor实现类,query(Configuration,MapperStatement,MapperStatement,Object... params)方法,执行的就是JDBC代码
1.3 IPersistence_Test编写
IPersistence_Test可以认为是使用端,首先完成使用端编写,相对比较简单,要做的就是编写配置文件以及引入jar包
两类配置文件:
sqlMapConfig.xml : 写数据库连接相关的配置信息
XXXMapper.xml : (比如UserMapper.xml) 写特定模块(比如用户模块)的语句信息
1.3.1 XXXMapper.xml详解
XXXMapper.xml中主要完成以下功能:
- 配置真正需要在MySql里面执行的sql语句
- 实现特定语句的定位,也就是需要给sql一个特定标识,即statementId
- 指定返回结果的封装类型
- 指定传入参数的类型
但是这么写只能操作user表,假设有了product表,那么都使用selectList就无法确定使用的究竟是哪一个语句,所以要添加命名空间namespace
<mapper namespace="user">
<!--sql的唯一标识:namespace.id来组成,statementId-->
<!--为了能定位到特定的select语句,就要给一个id-->
<!--resultType代表了想要封装的实体,所以就要通过反射从相应路径下获取对应实体及属性-->
<select id="selectList" resultType="com.jlgl.pojo.User">
select * from user
</select>
<!--这条sql语句执行的时候是需要参数的-->
<!--多个参数传递,要有面向对象的思想,把多个对象封装到某个实体-->
<!--
User user=new User();
user.setId();
user.setUsername();
-->
<!--所以参数也需要通过反射获取对应实体及属性-->
<!--为了把对应的属性赋值到对应的占位符上,就要把?改成自定义占位符-->
<select id="selectOne" resultType="com.jlgl.pojo.User" paramterType="com.jlgl.pojo.User">
select * from user where id =#{id} and username = #{username}
</select>
</mapper>
1.3.2 sqlMapConfig.xml详解
为了Resource加载xml文件时只加载一次,就需要把mapper.xml也存放进来,需要mapper.xml的全路径
<configuration>
<!--数据库配置信息-->
<dataSource>
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://120.48.8.213:3306/audio_2020"></property>
<property name="username" value="root"></property>
<property name="password" value="root1028*1"></property>
</dataSource>
<!--为了Resource加载xml文件时只加载一次,就需要把mapper.xml也存放进来,需要mapper.xml的全路径-->
<mapper resource="UserMapper.xml"></mapper>
</configuration>
1.4 Resources类定义
自定义持久层框架本质上就是利用dom4j技术,对使用端写好的xml文件进行分析,然后封装到配置类中,最终配置类被层层传递到Executor的query方法中执行JDBC代码
Resources类里面定义一个方法,目的是将配置文件加载成字节输入流,存储在内存中
1.5 容器对象定义
容器对象:MapperStatement和Configuration,这两个容器对象存放的就是配置文件解析出来的内容
MapperStatement作用是从xxxMapper里面读取内容,所以xxxMapper的各个属性都需要被存储在MapperStatement对应的类属性
Configuration作用是存放的就是sqlMapConfig的内容,其实就是数据库配置信息
1.6 解析核心配置文件sqlMapConfig
如前所述,解析核心配置文件需要两步:
3. 解析配置文件:dom4j
创建类:SqlSessionFactoryBuilder包含方法build(InputStream in)主要做两件事:
3.1 使用dom4j解析配置文件,将解析出来的内容封装到容器对象中
3.2 创建sqlSessionFactory对象,生产SqlSession,即会话对象(增删改查都封装在这里),这里用到了工厂模式,降低程序间的耦合(不直接new一个SqlSession)
首先是使用dom4j解析配置文件,具体是使用XMLConfigBuilder.parseConfig(InputStream in)实现的
将sqlMapConfig.xml生成Configuration
1.7 解析映射配置文件mapper.xml
在XMLConfigBuilder里面,调用XMLMapperBuilder的parse方法,读取XXXMapper.xml生成MapperStatement,并将其放入到Configuration的mapperStatementMap里面
1.8 会话对象sqlSession类定义
在回话对象中,使用Configuration里面储存的转换后的配置文件信息,完成与数据库的连接及数据获取操作
1.9 会话对象sqlSession方法定义
以selectList()为例,需要执行以下三步:
1 初始化Executor对象
2 获取Comfiguration里面存的xxxMapper.xml转换后的MapperStatement
3 执行Executor的query方法
1.10 查询对象query方法定义
一共需要执行六步:
1 注册驱动,获取连接
2 获取sql语句,然后转换sql语句,此时需要配置标记解析器来对占位符的解析处理工作(这里直接用了Mybatis的代码)
3 获取预处理对象:preparedStatement
4 设置参数
5 执行sql
6 封装返回结果集
注意:
在mapper.xml配置时,不直接写成?的原因是,为了能够将根据属性名直接获取传入对象的对应属性
面向对象的思想,将参数封装成对象,再返回,具体见buildParameterMapping,不是将String类型的content直接放入List,而是转换成了ParameterMapping对象放入List
1.11 参数设置实现
使用反射,根据参数名称,获取实体对象的属性值,然后获取对象中的具体参数值
1.12 封装返回结果集实现
使用反射或者内省,根据数据库表和实体的对应关系,完成封装
1.13 Client端运行测试
如何使用IPErsistence框架:
首先将IPersistence类打包,然后在IPersistence_test的pom引入包即可
UML类图(重要,需要好好理解):

1.14 功能扩展——getMapper方法实现
自定义持久层框架存在的问题:
1 代码重复。Dao层加载配置文件、获取SqlSessionFactory、生产sqlSession对象存在代码重复
2 硬编码问题。硬编码了statementId
解决思路:
不要Dao的实现类,使用代理模式实现Dao层接口的代理实现类
具体步骤:
1 在SqlSession创建getMappper,并在DefaultSession重写
3 在Client端直接调用

1.15 功能扩展——动态代理invoke方法实现
注意:不论如何简洁、优化,最终还是要执行底层的方法
xxxMapper.xml文件的规范要遵守,namespace要和接口全限定名一致,方法名也要和接口方法名一致
原因:
invoke方法中是没有办法获取statementId的(前面采用的方式是硬编码写进去的),但是可以通过接口全限定名.方法名即namespace.id,就组装出了statementId
Java工程师高薪训练营-第一阶段 开源框架源码解析-模块一 持久层框架涉及实现及MyBatis源码分析-任务一:自定义持久层框架的更多相关文章
- 【笔记】拉勾Java工程师高薪训练营-第一阶段 开源框架源码解析-模块一 持久层框架涉及实现及MyBatis源码分析-任务一:自定义持久层框架
以下笔记是我看完视频之后总结整理的,部分较为基础的知识点也做了补充,如有问题欢迎沟通. 目录 任务一:自定义持久层框架 1.1 JDBC回顾及问题分析 1.2 自定义持久层框架思路分析 1.3 IPe ...
- Java面试题_第一阶段(static、final、面向对象、多线程、集合、String、同步、接口、GC、JVM)
1.1 简述static和final的用法? static:修饰属性,方法,代码块 (1)静态属性:也可叫类变量 类名.属性名 来访问 (共有的类变量与对象无关,只和类有关) 注意:类中的实例变量 ...
- java课堂测试2第一阶段:方法运用
package test2; import java.util.*; public class Test2 { public static int generateRandom(int fanwei) ...
- java工程师_基础_阶段一_HTML笔记篇
一.了解HTML语言 html:超文本标记语言. 二.HTML整体结构<html> <head> </head> <body> </body> ...
- 死磕 java同步系列之Phaser源码解析
问题 (1)Phaser是什么? (2)Phaser具有哪些特性? (3)Phaser相对于CyclicBarrier和CountDownLatch的优势? 简介 Phaser,翻译为阶段,它适用于这 ...
- 死磕 java同步系列之CyclicBarrier源码解析——有图有真相
问题 (1)CyclicBarrier是什么? (2)CyclicBarrier具有什么特性? (3)CyclicBarrier与CountDownLatch的对比? 简介 CyclicBarrier ...
- 死磕 java同步系列之ReentrantReadWriteLock源码解析
问题 (1)读写锁是什么? (2)读写锁具有哪些特性? (3)ReentrantReadWriteLock是怎么实现读写锁的? (4)如何使用ReentrantReadWriteLock实现高效安全的 ...
- [源码解析] PyTorch 分布式(15) --- 使用分布式 RPC 框架实现参数服务器
[源码解析] PyTorch 分布式(15) --- 使用分布式 RPC 框架实现参数服务器 目录 [源码解析] PyTorch 分布式(15) --- 使用分布式 RPC 框架实现参数服务器 0x0 ...
- [源码解析] PyTorch 分布式(17) --- 结合DDP和分布式 RPC 框架
[源码解析] PyTorch 分布式(17) --- 结合DDP和分布式 RPC 框架 目录 [源码解析] PyTorch 分布式(17) --- 结合DDP和分布式 RPC 框架 0x00 摘要 0 ...
随机推荐
- STM32F103C8T6驱动WS2812b灯条
STM32F103C8T6驱动WS2812b灯条 几天小朋友到别人家玩,看上了人家的金鱼,人家就给了她一条小金鱼,有了小金鱼,怕它没氧气挂掉,买了一个氧气泵,没有东西喂它也不行,又买了一包鱼料,又因为 ...
- shell-的特殊变量-位置变量$0 $n $* $# $@详解
一:shell特殊变量 1. 位置变量 $0 获取当前执行的shell脚本的文件名,包括路径 $n 获取当前执行的shell脚本的第n个参数值,n=1..9,当n为0时表示脚本的文件名,如果n大于9 ...
- MeteoInfo 新网站
MeteoInfo特别是MeteoInfoLab的推广需要写大量详细的帮助文档和示例程序,MeteoInfo原先的网站使用最原始的编写.html文件的方式来更新,效率实在太低,最近学习了一下Sphin ...
- 网络io控制器
网络io控制器 网络io控制器 ZLAN6842,ZLAN6844是8路远程网络IO控制器.含有8路DI.8路DO,8路AI输入.其中DI支持干节点和湿节点,带光耦隔离:DO为继电器输出,具有5A 2 ...
- Jenkins集成appium自动化测试(Windows篇)
一,引入问题 自动化测试脚本绝大部分用于回归测试,这就需要制定执行策略,如每天.代码更新后.项目上线前定时执行,才能达到最好的效果,这时就需要进行Jenkins集成. 不像web UI自动化测试可以使 ...
- 【传递闭包】HDU 2157 How many ways??
UPD:现在才发现本题是个传递闭包 题目内容 春天到了,HDU校园里开满了花,姹紫嫣红,非常美丽. 葱头是个爱花的人,看着校花校草竞相开放,漫步校园,心情也变得舒畅. 为了多看看这迷人的校园,葱头决定 ...
- kinaba 安装踩坑: FATAL Error: [elasticsearch.url]: definition for this key is missing 转
安装 https://www.jianshu.com/p/875457cb8da6 操作系统:Linux kibana 版本: 7.4.0 1. 在/etc/yum.repos.d/ 下新建 ...
- centos8平台:redis6配置启用io多线程(redis6.0.1)
一,linux平台上redis6的安装 请参见这一篇: https://www.cnblogs.com/architectforest/p/12830056.html 说明:刘宏缔的架构森林是一个专注 ...
- centos8平台使用lsof
一,lsof的用途 lsof,List Open Files 列出当前系统打开文件的工具. 在linux环境下,任何事物都以文件的形式存在, 所以lsof通过文件不仅仅可以访问常规数据,还可以访问网络 ...
- centos 开机启动服务 systemctl
systemctl 实现开机自启服务 转载起一个好听的名字 最后发布于2018-06-26 13:49:06 阅读数 13473 收藏 展开 systemctl是RHEL 7 的服务管理工具中主要的 ...