第 2 章 基础支持层(下)

2.6 DataSource

MyBatis 提供了两个 javax.sql.DataSource 接口实现,分别是 PooledDataSource 和 UnpooledDataSource。MyBatis 使用不同的 DataSourceFactory 接口实现创建不同类型的 DataSource。

2.6.1 工厂方法模式

在工厂方法模式中,定义一个用于创建对象的工厂接口,并根据工厂接口的具体实现类决定具体实例化哪一个产品类。

在这里插入图片描述

工厂方法由四个角色构成:

  1. 工厂接口(Factory):核心接口,调用者会直接与工厂接口交互用于获取具体的产品实现类
  2. 具体工厂类(ConcreteFactory):实现类,用于实例化产品对象
  3. 产品接口(Product):用于定义产品类的功能,具体工厂类产生的所有产品对象都必须实现该接口
  4. 具体产品类(ConcreteProduct):实现产品接口的实现类

当需要添加新的第三方数据源组件时,只需要添加对应的工厂实现类,新数据源就能被 MyBatis 使用。

2.6.2 DataSourceFactory

在数据源模块中,DataSourceFactory 接口扮演工厂接口的角色。UnpooledDataSourceFactory 和 PooledDataSourceFactory 则扮演着具体工厂类的角色。

在这里插入图片描述

2.6.3 UnpooledDataSource

javax.sql.DataSource 接口在数据源模块中扮演了产品接口的角色,MyBatis 提供了两个 DataSource 接口的实现类,分别是 UnpooledDataSource 和 PooledDataSource,它们扮演了具体的产品类的角色。

在这里插入图片描述

2.6.4 PooledDataSource

数据库连接的创建过程是非常耗时的,数据库能够建立的连接数也非常有限。使用数据库连接池就显得尤为必要。

PooledDataSource 实现了简易数据库连接池的功能,如图

在这里插入图片描述

public class PoolState {protected PooledDataSource dataSource;protected final List<PooledConnection> idleConnections = new ArrayList<>();protected final List<PooledConnection> activeConnections = new ArrayList<>();}

2.7 Transaction

MyBatis 使用 Transaction 接口对数据库事务进行抽象,它有 JdbcTransaction 和 ManagedTransaction 两个实现。

在这里插入图片描述

JdbcTransaction 依赖于 JDBC Connection 控制事务的提交和回滚。

ManagedTransaction 事务和提交和回滚都是空实现,依靠窗口管理的。

2.8 binding 模块

binding 模块提供 Mapper 接口,定义 SQL 语句对应的方法,这些方法在 MyBatis 初始化过程中会与映射配置文件中定义的 SQL 语句相关联。如果存在无法关系的 SQL 语句,就会抛出异常。

2.8.1 MapperRegistry & MapperProxyFactory

MapperRegistry 是 Mapper 接口及其对应的代理对象工厂的注册中心。

public class MapperRegistry {// Configuration 对象,MyBatis 全局唯一的配置对象,包含了所有配置信息private final Configuration config;// 记录 Mapper 接口与对应 MapperProxyFactory 之间的关系private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();
}

MyBatis 初始化过程中人读取映射配置文件以及 Mapper 接口中的注解信息,填充到 knownMappers 集合中。

在需要执行 SQL 语句时,会通过 knownMappers 获取 MapperProxyFactory,并使用 JDK 动态代理生成代理对象执行 SQL 语句。

2.8.2 MapperProxy

MapperProxy 实现了 InvocationHandler 接口,核心功能如下

public class MapperProxy<T> implements InvocationHandler, Serializable {// 记录了关联的 SqlSession 对象private final SqlSession sqlSession;// Mapper 接口对应的 Class 对象private final Class<T> mapperInterface;// 用于缓存 MapperMethod 对象,key:Mapper 接口中方法对应的 Method 对象,value: 对应的 MapperMethod 对象。private final Map<Method, MapperMethodInvoker> methodCache;
}
2.8.3 MapperMethod

MapperMethod 中封装了 Mapper 接口中对应方法的信息,以及对应 SQL 语句的信息。MapperMethod 可以理解为连接 Mapper 接口以及映射配置文件中定义的 SQL 语句的桥梁。

public class MapperMethod {// 记录了 SQL 语句的名称和类型private final SqlCommand command;// Mapper 接口中对应方法的相关信息private final MethodSignature method;
}

MapperMethod 中最核心的方法是 execute(),它会根据 SQL 语句的类型调用 SqlSession 对应的方法完成数据库操作。

public Object execute(SqlSession sqlSession, Object[] args) {Object result;switch (command.getType()) {case INSERT: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.insert(command.getName(), param));break;}case UPDATE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.update(command.getName(), param));break;}case DELETE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.delete(command.getName(), param));break;}case SELECT:if (method.returnsVoid() && method.hasResultHandler()) {executeWithResultHandler(sqlSession, args);result = null;} else if (method.returnsMany()) {result = executeForMany(sqlSession, args);} else if (method.returnsMap()) {result = executeForMap(sqlSession, args);} else if (method.returnsCursor()) {result = executeForCursor(sqlSession, args);} else {Object param = method.convertArgsToSqlCommandParam(args);result = sqlSession.selectOne(command.getName(), param);if (method.returnsOptional()&& (result == null || !method.getReturnType().equals(result.getClass()))) {result = Optional.ofNullable(result);}}break;case FLUSH:result = sqlSession.flushStatements();break;default:throw new BindingException("Unknown execution method for: " + command.getName());}return result;}

2.9 缓存模块

MyBatis 中的缓存是两层结构,分为一级缓存和二级缓存,但在本质是都是 Cache 接口的实现。

2.9.1 装饰器模式

装饰器可以动态地为对象添加功能,它是基于组合的方式实现该功能的。

在这里插入图片描述

  • Component(组件):定义了全部组件实现类以及所有装饰器实现的行为
  • ConcreteComponent(具体组件实现类):实现了 Component 接口。通常情况下就是被装饰器装饰的原始对象。
  • Decorator(装饰器):所有装饰器的父类,它是一个实现了 Component 接口的抽象类,
  • ConcreteDecorator:具体的装饰器实现类,该实现类要向被装饰对象添加某些功能。

使用装饰器模式有两个明显优点:

  1. 相较于承继,装饰器模式更灵活,也更容易扩展
  2. 当有新功能需要添加时,只需要添加新的装饰器实现类,无须修改已有类的代码,符合开闭原则
2.9.2 Cache 接口及其实现
public interface Cache {// 缓存对象的 idString getId();// 向缓存中添加数据,key:cacheKey,value:查询结果void putObject(Object key, Object value);// 根据指定的 key,在缓存中查询结果Object getObject(Object key);// 删除 key 对应的缓存项Object removeObject(Object key);// 清空缓存void clear();// 缓存项的个数,不会被 MyBatis 核心代码使用int getSize();// 获取读写锁,不会被 MyBatis 核心代码使用default ReadWriteLock getReadWriteLock() {return null;}
}

实现类 PerpetualCache 提供了 Cache 接口的基本实现。底层使用 HashMap 记录缓存项,并实现 Cache 接口中定义的相应方法。

public class PerpetualCache implements Cache {private final String id;private final Map<Object, Object> cache = new HashMap<>();public PerpetualCache(String id) {this.id = id;}@Overridepublic String getId() {return id;}@Overridepublic int getSize() {return cache.size();}@Overridepublic void putObject(Object key, Object value) {cache.put(key, value);}@Overridepublic Object getObject(Object key) {return cache.get(key);}@Overridepublic Object removeObject(Object key) {return cache.remove(key);}@Overridepublic void clear() {cache.clear();}
}

Cache 的其他实现类,会在 PerpetualCache 的基础上提供一些额外功能,通过多个组合后满足一个特定的需求。

BlockingCache:阻塞版本的缓存装饰器,它会保证只有一个线程到数据库中查找指定 key 对应的数据。

public class BlockingCache implements Cache {// 阻塞超时时长private long timeout;// 被装饰的底层 Cache 对象private final Cache delegate;// 每个 key 都有对应的 ReentrantLock 对象private final ConcurrentHashMap<Object, CountDownLatch> locks;
}

FifoCache & LruCache

public class FifoCache implements Cache {// 被装饰的底层 Cache 对象private final Cache delegate;// 用于记录 key 进入缓存的先后顺序private final Deque<Object> keyList;// 记录了缓存项的上限,超过该值,则需要清理最老的缓存项private int size;public FifoCache(Cache delegate) {this.delegate = delegate;this.keyList = new LinkedList<>();this.size = 1024;}
}
public class LruCache implements Cache {// 被装饰的底层 Cache 对象private final Cache delegate;// LinkedHashMap,记录 key 最近的使用情况private Map<Object, Object> keyMap;// 记录最少被使用的缓存项的 keyprivate Object eldestKey;public LruCache(Cache delegate) {this.delegate = delegate;setSize(1024);}
}

SoftCache & WeakCache

关于强、软、弱、虚引用,会在其他笔记中整理

public class SoftCache implements Cache {// 在 SoftCache 中,保存最近使用的一部分缓存项不被 GC 回收private final Deque<Object> hardLinksToAvoidGarbageCollection;// 引用队列,用于记录已经被 GC 回收的缓存项所对应的 SoftEntry 对象private final ReferenceQueue<Object> queueOfGarbageCollectedEntries;// 被装饰的底层 Cache 对象private final Cache delegate;// 强连接的个数private int numberOfHardLinks;public SoftCache(Cache delegate) {this.delegate = delegate;this.numberOfHardLinks = 256;this.hardLinksToAvoidGarbageCollection = new LinkedList<>();this.queueOfGarbageCollectedEntries = new ReferenceQueue<>();}
}

ScheduledCache & LoggingCache & SynchronizedCache & SerializedCache

  • ScheduledCache 是周期性清理缓存的装饰器,默认一小时清理一次
  • LoggingCache 在 Cache 的基础上提供了日志功能,通过 requestshits 计算缓存的命中率
  • SynchronizedCache 通过在每个方法上添加 synchronized 关键字,为 Cache 添加了同步功能。
  • SerializedCache 提供了将 value 对象序列化的功能。添加缓存时,会将 value 序列化为 byte[] 存入缓存;获取缓存时,会将 byte[] 反序列化成 Java 对象。

Tips:perpetual(adj. 永恒的),delegate(n. 代表)

2.9.3 CacheKey

在 Cache 中唯一确定一个缓存项需要使用缓存项的 key,这个 key 不能仅仅通过一个 String 表示,所以需要定义 CacheKey 类型

public class CacheKey implements Cloneable, Serializable {private static final int DEFAULT_MULTIPLIER = 37;private static final int DEFAULT_HASHCODE = 17;// 参与计算 hashcode,默认 37private final int multiplier;// CacheKey 对象的 hashcode,初始 17private int hashcode;// 校验和private long checksum;// updateList 集合的个数private int count;// 由该集合中的所有对象共同决定两个 CacheKey 是否相同private List<Object> updateList;public CacheKey() {this.hashcode = DEFAULT_HASHCODE;this.multiplier = DEFAULT_MULTIPLIER;this.count = 0;this.updateList = new ArrayList<>();}
}

实际上,CacheKey 对象的 updateList 由四部分组成,分别是:

  1. MappedStatement 的 id
  2. 指定查询结果集的范围,也就是 RowBounds.offset 和 RowBounds.limit
  3. 查询所使用的 SQL 语句,也就是 boundSql.getSql() 方法返回的 SQL 语句,其中可能包含“?”占位符
  4. 用户传递给上述 SQL 语句的实际参数值

2.10 本章小结

  1. XML 解析的基础知识以及解析器模块的具体实现
  2. MyBatis 对 Java 反射的封装,Type 接口的基础知识以及复杂属性表达式在类层面和对象层面的处理
  3. MyBatis 如何实现数据在 Java 类型与 JDBC 类型之间的转换以及别名功能
  4. 日志模块的相关实现
  5. MyBatis 中 JDK 动态代理的应用
  6. DataSource 模块的实现和原理
  7. Transaction 模块如何实现事务
  8. binding 模块如何将 Mapper 与映射配置信息相关联
  9. Cache 模块的实现

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

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

相关文章

ssm题库管理系统的设计与实现

系统包含&#xff1a;源码论文 所用技术&#xff1a;SpringBootVueSSMMybatisMysql 免费提供给大家参考或者学习&#xff0c;获取源码请私聊我 需要定制请私聊 目 录 摘 要 I Abstract II 1 绪论 1 1.1课题研究背景和来源 1 1.2课题研究现状 1 1.3课题开发的目的和意…

大贤3D家谱-关于节点

节点释疑&#xff1a; 父-代表父亲&#xff0c;位置在节点上方 母-代表母亲&#xff0c;位置在节点上方 夫-代表丈夫&#xff0c;位置在节点左前方 妻-代表妻子&#xff0c;位置在节点左前方 兄-代表兄弟&#xff0c;位置在节点右侧 姊-代表姐妹&#xff0c;位置在节点右…

Android复杂问题分析工具bugreportz详解

文章目录 bugreportz详细介绍功能与作用使用方法生成详细报告检查进度bugreportz 的优势分析报告 如何分析1. 解压 ZIP 文件2. 分析主要文件2.1 bugreport.txt2.2 logcat.txt2.3 kernel.log / last_kmsg2.4 events.log2.5 traces.txt2.6 dumpstate_board.txt 3. 工具支持4. 重点…

创意多元化是提升Facebook广告销量的关键

在投放Facebook广告的时候&#xff0c;我们面向的受众是非常广泛的&#xff0c;用户的需求也是非常多样的&#xff0c;打个比方&#xff0c;同样是买一件衣服&#xff0c;有的人注重款式&#xff0c;喜欢新颖的设计&#xff1b;有的人注重质量&#xff0c;更关心面料材质&#…

重学SpringBoot3-集成Redis(七)之分布式限流

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-集成Redis&#xff08;七&#xff09;之分布式限流 1. 什么是分布式限流&#xff1f;2. 常见的限流算法3. Redis 分布式限流实现3.1. 添加依赖3.2. 配置…

Qt-窗口对话框QMessageBox的使用(51)

目录 前言 描述 使用 自定义按钮 简单方式创建 前言 Qt 提供了多种可复⽤的对话框类型&#xff0c;即 Qt 标准对话框。Qt 标准对话框全部继承于 QDialog类。常⽤标准对话框如下&#xff1a; 描述 消息对话框 QMessageBox 消息对话框是应⽤程序中最常⽤的界⾯元素。消息…

微信点赞的测试用例,应该在哪些方面进行设计!

功能模块测试的测试用例设计方法包括&#xff1a; 等价类划分法&#xff1a;把所有可能的输入数据&#xff0c;即程序的输入域划分成若干部分&#xff0c;然后从每一个部分中选取少数具有代表性的数据作为测试用例。比如字符串长度检查,字符类型检查,标点符号检查,特殊字符检查…

活动预告丨第二十八期 “CCF 开源高校行”暨“木兰技术开放日”活动走进北京大学...

点击蓝字 关注我们 CCF Opensource Development Committee 开源高校行 北京大学站 在数字化转型的浪潮中&#xff0c;开源软件人才的培养是信息技术创新发展的重要根基&#xff0c;高校学子作为我国开源生态的源头活水备受重视。10月9日下午15:00-17:10 “CCF 开源高校行”暨“…

318页PPT5G智慧校园顶层设计方案

2019年&#xff0c;中共中央、国务院印发的《中国教育现代化2035》提出从构建更为完善信息化基础环境、配置学校数字教学资源、建立学校信息化系统运行维护长效机制、统筹建设一体化智能化教学和管理与服务平台等方面建设智能化校园。因此&#xff0c;未来随着信息通信技术的不…

Java项目实战II基于Java+Spring Boot+MySQL的中药实验管理系统(源码+数据库+文档)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 中药作为中…

龙迅LT8911EXB 高性价比方案MIPICSI/DSI转EDP 1.4 大批量出货产品

龙迅LT891EXB描述&#xff1a; Lontium LT8911EXB是MIPIDSI/CSI到eDP转换器&#xff0c;单端口MIPI接收器有1个时钟通道和4个数据通道&#xff0c;每个数据通道最大运行2.0Gbps&#xff0c;最大输入带宽为8.0Gbps。转换器解码输入MIPI RGB16/18/24/30/36bpp、YUV422 16/20/24b…

huohuo

c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话&#xff1a; 知不足而奋进&#xff0c;望远山而前行&am…

C++网络编程之套接字基础

概述 在网络编程中&#xff0c;套接字&#xff08;Socket&#xff09;是一种用于进程间通信的接口。套接字是操作系统提供的一种抽象层&#xff0c;它允许不同计算机之间的进程通过网络进行通信。套接字实际上并不神秘&#xff0c;简单来说&#xff0c;套接字是连接网络中不同主…

网络安全 IP地址防泄漏指南

IP地址作为每个上网人的“门牌标识号”&#xff0c;如果产生泄露&#xff0c;可能会导致个人行踪曝光、数据被窃取甚至遭受网络攻击&#xff0c;要防止IP地址不被窃取&#xff0c;我们可以尝试以下方法&#xff1a; 利用专用网络加强隐私保护 通过加密在公共网络上创建一条安全…

利用LangSmith Chat数据集轻松微调模型

在这篇文章中&#xff0c;我们将探讨如何使用LangSmith Chat数据集来微调AI模型&#xff0c;并将其应用于LangChain应用中。这个过程简单易行&#xff0c;只需三个步骤&#xff1a;创建聊天数据集、加载示例并微调模型。 引言 随着对聊天AI需求的增加&#xff0c;能够通过特定…

怎样在不改变使用习惯的前提下,实现替代FTP的操作?

但国家信创要求出台后&#xff0c;“28N”行业领域已陆续实现信创国产化的替代&#xff0c;从操作系统到CPU、数据库等&#xff0c;下一步&#xff0c;可能就会落实到引用层面&#xff0c;这时候&#xff0c;作为文件传输关键载体的FTP就不得不考虑信创国产化替代的问题。 那么…

如何采集1688商品的多语言数据

访问1688官网的数据&#xff0c;是中文的商品数据&#xff0c;如果直接采集1688的中文商品数据&#xff0c;还需要自己翻译数据&#xff0c;翻译标题&#xff0c;描述&#xff0c;格式化数据等比较麻烦 教大家一种新的方式&#xff0c;1688在2023年底已经开通了跨境专供&#…

谷歌最近在其量子处理器中发现了一个“低噪声相变”现象

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

2024年第四届机器人、自动化和人工智能国际会议(RAAI 2024)即将召开!

学术会议查询-学术会议交流服务平台-爱科会易 (uconf.com)https://www.uconf.com/ 第四届机器人、自动化和人工智能国际会议&#xff08;RAAI 2024&#xff09;将于 2024 年 12 月 19-21 日在新加坡举行。会议旨在为研究人员、从业人员和行业专家提供一个平台&#xff0c;分享他…

鸿蒙--下拉刷新+上拉加载

概述 Refresh组件支持下拉刷新&#xff0c;包裹list组件&#xff0c;下拉事件中更新列表 这里我们需要提前了解一下 Builder装饰器 的基本用法 ArkUI提供了一种轻量的UI元素复用机制Builder&#xff0c;该自定义组件内部UI结构固定&#xff0c;仅与使用方进行数据传递&#…