《ShardingSphere解读》03 JDBC 规范与 ShardingSphere 是什么关系?

news2026/3/15 18:55:40
在上一篇中我们全面了解了 ShardingSphere 作为 Apache 顶级开源软件的发展历程、设计理念和核心功能。其中特别强调了一点ShardingSphere 是一种典型的客户端分片解决方案而客户端分片的核心实现方式之一就是重写 JDBC 规范。ShardingSphere 对外暴露的分片操作接口与 JDBC 规范中所提供的接口完全一致这究竟是如何实现的本课时将深入剖析 JDBC 规范与 ShardingSphere 的这层关系从底层设计上解开其中的奥秘。一、JDBC 规范简介JDBCJava Database Connectivity是 Java 领域访问数据库的标准规范。它定义了一套统一的接口让应用程序可以通过一致的方式操作不同数据库。数据库厂商则提供这些接口的实现即数据库驱动从而将具体数据库的差异屏蔽在驱动层之下。1.1 JDBC 架构JDBC 的核心架构如下图所示它由 DriverManager、Driver、Connection 等核心组件构成DriverManager负责加载和管理不同数据库的驱动程序并根据连接 URL 返回对应的 Connection 对象。Driver数据库驱动程序由数据库厂商实现负责与数据库建立底层通信。Connection代表与数据库的会话连接是执行 SQL 的上下文。Statement / PreparedStatement用于执行静态 SQL 或预编译 SQL。ResultSet封装 SQL 查询的结果集。1.2 JDBC 核心接口及典型使用流程在 JDBC 规范中DataSource、Connection、Statement、ResultSet是最核心的接口。下面通过一段典型代码展示它们的使用方式// 创建池化的数据源 PooledDataSource dataSource new PooledDataSource(); dataSource.setDriver(com.mysql.jdbc.Driver); dataSource.setUrl(jdbc:mysql://localhost:3306/test); dataSource.setUsername(root); dataSource.setPassword(root); // 获取连接 Connection connection dataSource.getConnection(); // 创建语句并执行查询 PreparedStatement statement connection.prepareStatement(SELECT * FROM user); ResultSet resultSet statement.executeQuery(); // 遍历结果集 while (resultSet.next()) { // 处理每一行数据 } // 关闭资源 resultSet.close(); statement.close(); connection.close();上述流程可以用下图概括1.3 各核心接口详解1.3.1 DataSourceDataSource是 JDBC 2.0 引入的接口它作为连接工厂提供了比DriverManager更强大的功能例如连接池、分布式事务等。其定义如下public interface DataSource extends CommonDataSource, Wrapper { Connection getConnection() throws SQLException; Connection getConnection(String username, String password) throws SQLException; }CommonDataSource是DataSource、ConnectionPoolDataSource和XADataSource的父接口后两者分别用于连接池和分布式事务场景。它们的关系如下注意DataSource还继承了Wrapper接口。Wrapper是 JDBC 4.0 引入的用于让应用程序访问非 JDBC 标准的扩展功能。通过unwrap方法可以将 JDBC 包装对象还原为原生对象通过isWrapperFor可以判断是否可包装为指定类型。这个接口为 ShardingSphere 重写 JDBC 规范提供了基础。1.3.2 ConnectionConnection代表与数据库的会话连接它负责创建Statement或PreparedStatement并管理事务提交、回滚、设置隔离级别等。在分片场景下Connection需要能够路由到多个物理数据库因此 ShardingSphere 实现了ShardingConnection。1.3.3 Statement 与 PreparedStatementStatement用于执行静态 SQL而PreparedStatement继承自Statement支持预编译 SQL可防止 SQL 注入并提升执行效率。ShardingSphere 分别提供了ShardingStatement和ShardingPreparedStatement它们在内部将逻辑 SQL 改写为真实 SQL并路由到对应分片执行。1.3.4 ResultSetResultSet封装查询结果提供遍历和获取数据的方法。分片查询可能涉及多个数据源返回的多个结果集ShardingSphere 的ShardingResultSet负责对这些结果集进行归并对外呈现为单个逻辑结果集。二、基于适配器模式的 JDBC 重写实现方案ShardingSphere 要实现与 JDBC 规范完全兼容的 API必须对DataSource、Connection、Statement、ResultSet等核心接口进行重写使其在内部嵌入分片逻辑但对外依然呈现为标准接口。这一重写机制的设计核心是适配器模式Adapter Pattern。2.1 适配器模式概述适配器模式用于将一个类的接口转换成客户希望的另一个接口使得原本因接口不兼容而无法一起工作的类可以协同工作。在 ShardingSphere 中它扮演的角色是目标接口TargetJDBC 规范中的标准接口如DataSource、Connection。被适配者AdapteeShardingSphere 内部实现分片逻辑的类如ShardingDataSource。适配器Adapter连接目标接口和被适配者的中间层使得最终对象既符合 JDBC 规范又具备分片能力。2.2 ShardingSphere 适配器体系总体结构ShardingSphere 为每个核心接口设计了一套适配器类其总体结构如下图中各层次的含义WrapperJDBC 标准接口所有核心接口都继承它。WrapperAdapterShardingSphere 提供的包装器适配基类实现了recordMethodInvocation和replayMethodsInvocation方法用于记录和重放对底层真实连接的方法调用后面详述。AbstractUnsupportedOperationJdbcObject抽象类将所有 JDBC 中不打算支持的方法直接抛出异常明确职责边界。例如prepareCall存储过程调用在分片场景中通常不支持就在这里抛出SQLFeatureNotSupportedException。AbstractJdbcObjectAdapter抽象类继承自AbstractUnsupportedOperationJdbcObject提供部分方法的默认实现这些方法是 ShardingSphere 需要增强的如prepareStatement。真正的分片逻辑尚未加入留给子类实现。ShardingJdbcObject具体类如ShardingDataSource、ShardingConnection、ShardingStatement它们实现分片逻辑并对外呈现为标准 JDBC 接口。这种分层设计将“不支持的方法”、“需增强的方法”和“具体分片逻辑”清晰地分离既保证了与 JDBC 规范的兼容又使代码易于维护和扩展。2.3 包结构组织在 ShardingSphere 源码的sharding-jdbc-core模块中适配器相关的类位于org.apache.shardingsphere.shardingjdbc.jdbc.adapter包下结构如下org.apache.shardingsphere.shardingjdbc.jdbc.adapter ├── AbstractDataSourceAdapter ├── AbstractConnectionAdapter ├── AbstractStatementAdapter ├── AbstractPreparedStatementAdapter ├── AbstractResultSetAdapter ├── WrapperAdapter └── ... (各子类的实现)这种按职责划分的包结构使得开发者可以快速定位需要扩展的类。三、ShardingSphere 重写 JDBC 规范示例ShardingConnection下面以ShardingConnection为例深入分析其如何通过适配器模式实现对 JDBCConnection接口的重写。3.1 ShardingConnection 的类层结构ShardingConnection的继承体系完全遵循前面介绍的适配器模式AbstractUnsupportedOperationConnection继承WrapperAdapter实现了Connection接口中所有不支持的方法如prepareCall直接抛出异常。这确保ShardingConnection只关注支持的方法。AbstractConnectionAdapter继承AbstractUnsupportedOperationConnection提供了连接缓存、获取物理连接等通用能力但createConnection方法留为抽象由子类实现。ShardingConnection继承AbstractConnectionAdapter实现createConnection方法根据分片规则返回实际的数据库连接并重写prepareStatement等方法嵌入分片逻辑。3.2 连接缓存与获取AbstractConnectionAdapterAbstractConnectionAdapter中维护了一个cachedConnections属性它是一个Map键为数据源名称值为该数据源对应的物理连接集合。这样在同一个逻辑连接生命周期内对同一数据源的多次操作可以复用已创建的连接避免重复创建。核心方法getConnections负责从缓存中获取连接若不足则创建新的连接。其简化流程如下public final ListConnection getConnections(ConnectionMode connectionMode, String dataSourceName, int connectionSize) throws SQLException { // 1. 从缓存中获取已有连接 CollectionConnection connections cachedConnections.get(dataSourceName); // 2. 如果缓存中连接数足够直接返回子列表 if (connections.size() connectionSize) { return new ArrayList(connections).subList(0, connectionSize); } // 3. 否则创建不足数量的新连接 ListConnection newConnections createConnections(dataSourceName, connectionMode, dataSource, connectionSize - connections.size()); // 4. 将新连接加入缓存并返回 synchronized (cachedConnections) { cachedConnections.putAll(dataSourceName, newConnections); } // ... 合并已有连接和新连接返回 }创建连接最终调用抽象方法createConnectionprotected abstract Connection createConnection(String dataSourceName, DataSource dataSource) throws SQLException;ShardingConnection会实现该方法从数据源中获取真正的物理连接。3.3 方法记录与重放WrapperAdapter在AbstractConnectionAdapter的getConnections方法中创建新连接后会调用replayMethodsInvocation(connection)。这个方法是定义在WrapperAdapter中的其作用是将之前对逻辑连接执行的一些配置方法如setAutoCommit、setReadOnly“重放”到新创建的物理连接上确保物理连接的状态与逻辑连接一致。WrapperAdapter中维护了一个jdbcMethodInvocations列表用于记录需要重放的方法调用public final void recordMethodInvocation(Class? targetClass, String methodName, Class?[] argumentTypes, Object[] arguments) { jdbcMethodInvocations.add(new JdbcMethodInvocation(targetClass.getMethod(methodName, argumentTypes), arguments)); } public final void replayMethodsInvocation(Object target) { for (JdbcMethodInvocation each : jdbcMethodInvocations) { each.invoke(target); } }JdbcMethodInvocation是一个简单的包装类内部通过反射执行方法public class JdbcMethodInvocation { private final Method method; private final Object[] arguments; public void invoke(Object target) { method.invoke(target, arguments); } }那么何时记录方法调用在AbstractConnectionAdapter中对setAutoCommit、setReadOnly、setTransactionIsolation这三个方法进行了记录。以setReadOnly为例Override public final void setReadOnly(boolean readOnly) throws SQLException { this.readOnly readOnly; // 记录方法调用 recordMethodInvocation(Connection.class, setReadOnly, new Class[]{boolean.class}, new Object[]{readOnly}); // 对现有所有物理连接立即执行该操作 forceExecuteTemplate.execute(cachedConnections.values(), new ForceExecuteCallbackConnection() { Override public void execute(Connection connection) throws SQLException { connection.setReadOnly(readOnly); } }); }这里既记录了调用也立即对已有连接执行了操作。当后续新连接加入时通过replayMethodsInvocation将这些调用在新连接上重放保证所有物理连接的状态与逻辑连接一致。3.4 不支持的方法处理AbstractUnsupportedOperationConnection在AbstractUnsupportedOperationConnection中所有不打算支持的方法都直接抛出SQLFeatureNotSupportedException例如Override public final CallableStatement prepareCall(String sql) throws SQLException { throw new SQLFeatureNotSupportedException(prepareCall); }这样任何试图调用这些方法的代码都会得到明确的异常提示符合 JDBC 规范中对不支持操作的要求。四、其他核心类的适配实现除了ShardingConnectionShardingSphere 对DataSource、Statement、PreparedStatement、ResultSet也采用了完全相同的适配模式ShardingDataSource继承AbstractDataSourceAdapter实现getConnection返回ShardingConnection。ShardingStatement继承AbstractStatementAdapter重写executeQuery、executeUpdate等方法将逻辑 SQL 路由到真实数据库执行。ShardingPreparedStatement继承AbstractPreparedStatementAdapter处理参数化 SQL并在执行时替换参数值。ShardingResultSet继承AbstractResultSetAdapter归并多个物理结果集对外呈现为单个结果集。它们的继承体系与ShardingConnection类似都遵循WrapperAdapter→AbstractUnsupportedOperationXxx→AbstractXxxAdapter→ShardingXxx的层次结构。五、小结本篇深入剖析了 ShardingSphere 如何通过适配器模式实现对 JDBC 规范的重写使其对外提供完全兼容的 API内部却嵌入了强大的分片功能。我们首先回顾了 JDBC 规范的核心接口及其典型使用流程然后详细介绍了 ShardingSphere 基于适配器模式的整体设计最后以ShardingConnection为例分析了连接缓存、方法记录与重放、不支持方法处理等关键实现细节。这种设计带来的好处显而易见对开发者友好只需掌握标准 JDBC 编程即可使用分片功能。与现有框架无缝集成可轻松与 MyBatis、Hibernate、Spring 等生态结合。高可扩展性适配器模式将不支持的接口统一抛出异常支持的接口通过抽象类预留扩展点新增功能只需添加新的子类。理解这一底层机制是正确使用和扩展 ShardingSphere 的基础。思考题在WrapperAdapter中recordMethodInvocation记录了哪些方法为什么只记录这三个setAutoCommit、setReadOnly、setTransactionIsolation请结合 JDBC 规范和你对 ShardingSphere 的理解谈谈你的看法。欢迎在评论区留言讨论。

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

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

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…