摘要: 原创出处 http://www.iocoder.cn/Sharding-JDBC/jdbc-implement-and-read-write-splitting/ 「芋道源码」欢迎转载,保留摘要,谢谢!
本文主要基于 Sharding-JDBC 1.5.0 正式版
关注微信公众号:【芋道源码】有福利:
RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
新的源码解析文章实时收到通知。每周更新一篇左右。
认真的源码交流微信群。
1. 概述
本文主要分享 JDBC 与 读写分离 的实现。为什么会把这两个东西放在一起讲呢?客户端直连数据库的读写分离主要通过获取读库和写库的不同连接来实现,和 JDBC Connection 刚好放在一块。
OK,我们先来看一段 Sharding-JDBC 官方对自己的定义和定位
Sharding-JDBC定位为轻量级java框架,使用客户端直连数据库,以jar包形式提供服务,未使用中间层,无需额外部署,无其他依赖,DBA也无需改变原有的运维方式,可理解为增强版的JDBC驱动,旧代码迁移成本几乎为零。
可以看出,Sharding-JDBC 通过实现 JDBC规范,对上层提供透明化数据库分库分表的访问。 黑科技?实际我们使用的数据库连接池也是通过这种方式实现对上层无感知的提供连接池。甚至还可以通过这种方式实现对 Lucene、MongoDB 等等的访问。
扯远了,下面来看看 Sharding-JDBC jdbc
包的结构:
unsupported
:声明不支持的数据操作方法adapter
:适配类,实现和分库分表无关的方法core
:核心类,实现和分库分表相关的方法
根据 core
包,可以看出分到四种我们超级熟悉的对象
-
Datasource
-
Connection
-
Statement
-
ResultSet
实现层级如下:JDBC 接口 <=(继承)== unsupported
抽象类 <=(继承)== unsupported
抽象类 <=(继承)== core
类。
本文内容顺序
unspported
包adapter
包插入流程,分析的类:
ShardingDataSource
ShardingConnection
ShardingPreparedStatement(ShardingStatement 类似,不重复分析)
GeneratedKeysResultSet、GeneratedKeysResultSetMetaData
ShardingPreparedStatement
ShardingResultSet
MasterSlaveDataSource
Sharding-JDBC 正在收集使用公司名单:传送门。
你的登记,会让更多人参与和使用 Sharding-JDBC。传送门
Sharding-JDBC 也会因此,能够覆盖更多的业务场景。传送门
登记吧,骚年!传送门
2. unspported 包
unspported
包内的抽象类,声明不支持操作的数据对象,所有方法都是 thrownewSQLFeatureNotSupportedException()
方式。
public abstract class AbstractUnsupportedGeneratedKeysResultSet extends AbstractUnsupportedOperationResultSet { @Override public boolean getBoolean(final int columnIndex) throws SQLException { throw new SQLFeatureNotSupportedException("getBoolean"); } // .... 省略其它类似方法}public abstract class AbstractUnsupportedOperationConnection extends WrapperAdapter implements Connection { @Override public final CallableStatement prepareCall(final String sql) throws SQLException { throw new SQLFeatureNotSupportedException("prepareCall"); } // .... 省略其它类似方法}
3. adapter 包
adapter
包内的抽象类,实现和分库分表无关的方法。
考虑到第4、5两小节更容易理解,本小节贴的代码会相对多
3.1 WrapperAdapter
3.2 AbstractDataSourceAdapter
AbstractDataSourceAdapter,数据源适配类。
直接点击链接查看源码。
3.3 AbstractConnectionAdapter
AbstractConnectionAdapter,数据库连接适配类。
3.5 AbstractPreparedStatementAdapter
AbstractPreparedStatementAdapter,预编译语句对象的适配类。
3.6 AbstractResultSetAdapter
AbstractResultSetAdapter,代理结果集适配器。
4. 插入流程
插入使用分布式主键例子代码如下:
// 代码仅仅是例子,生产环境下请注意异常处理和资源关闭String sql = "INSERT INTO t_order(uid, nickname, pid) VALUES (1, '2', ?)";DataSource dataSource = new ShardingDataSource(shardingRule);Connection conn = dataSource.getConnection();PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); // 返回主键需要 Statement.RETURN_GENERATED_KEYSps.setLong(1, 100);ps.executeUpdate();ResultSet rs = ps.getGeneratedKeys();if (rs.next()) { System.out.println("id:" + rs.getLong(1));}
调用 #executeUpdate()
方法,内部过程如下:
5. 查询流程
单纯从 core
包里的 JDBC 实现,查询流程 #executeQuery()
和 #execute()
基本一致,差别在于执行和多结果集归并。
-
SQL执行 感兴趣的同学可以看:《Sharding-JDBC 源码分析 ―― SQL 执行》
-
结果归并 感兴趣的同学可以看:《Sharding-JDBC 源码分析 ―― 结果归并》
-
结果归并
#merge()
完后,创建分片结果集( ShardingResultSet )
6. 读写分离
建议前置阅读:《官方文档 ―― 读写分离》
当你有读写分离的需求时,将 ShardingRule 配置对应的数据源 从 ShardingDataSource 替换成 MasterSlaveDataSource。我们来看看 MasterSlaveDataSource 的功能和实现。
支持一主多从的读写分离配置,可配合分库分表使用
同一线程且同一数据库连接内,如有写入操作,以后的读操作均从主库读取,用于保证数据一致性。
-
ShardingConnection 获取到的数据源是 MasterSlaveDataSource 时,调用
MasterSlaveDataSource#getConnection()
方法获取真实的数据源 -
通过
#isMasterRoute()
判断是否读取主库,以下三种情况会访问主库:非查询语句 (DQL)
该数据源在当前线程访问过主库:通过线程变量
DML_FLAG
实现强制主库:程序里调用
HintManager.getInstance().setMasterRouteOnly()
实现
-
666. 彩蛋
没有彩蛋
没有彩
没有
没
下一篇,《分布式事务(一)之最大努力型》走起。老司机,赶紧上车。
道友,分享一个朋友圈可好?不然交个道姑那~~敏感词~~你。