摘要: 原創出處 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. 彩蛋
沒有彩蛋
沒有彩
沒有
沒
下一篇,《分佈式事務(一)之最大努力型》走起。老司機,趕緊上車。
道友,分享一個朋友圈可好?不然交個道姑那~~敏感詞~~你。