SpringJDBC源碼初探-DataSource類

一、DataSource接口核心作用

DataSource是JDBC規范的核心接口,位于javax.sql包中,用于替代傳統的DriverManager獲取數據庫連接。Spring框架通過org.springframework.jdbc.datasource包對該接口進行了增強,提供連接池管理、事務綁定等高級特性。

二、DataSource源碼分析

核心接口javax.sql.DataSource

public interface DataSource  extends CommonDataSource, Wrapper {// 獲取數據庫連接Connection getConnection() throws SQLException;// 使用憑證獲取連接Connection getConnection(String username, String password)throws SQLException;
}

可以看到,DataSource接口提供了獲取連接的的方法,并且DataSource繼承了兩個父接口CommonDataSource和Wrapper,CommonDataSource定義如下:

public interface CommonDataSource {// 獲取日志記錄器PrintWriter getLogWriter() throws SQLException;// 設置日志記錄器void setLogWriter(PrintWriter out) throws SQLException;// 設置登錄超時時間(秒)void setLoginTimeout(int seconds) throws SQLException;// 獲取登錄超時時間int getLoginTimeout() throws SQLException;// 獲取父Loggerdefault Logger getParentLogger() throws SQLFeatureNotSupportedException {throw new SQLFeatureNotSupportedException();}
}

這里CommonDataSource 提供了獲取和設置日志的方法,連接超時管理以及獲取父Logger的方法。

public interface Wrapper {// 檢查是否實現指定接口boolean isWrapperFor(Class<?> iface) throws SQLException;// 獲取接口實現<T> T unwrap(Class<T> iface) throws SQLException;
}

Wrapper主要用于獲取特定擴展功能

AbstractDataSource抽象類,主要提供DataSource接口中的某些方法(如getLoginTimeout()、setLoginTimeout(int)等)的默認實現
主要的繼承關系如下

AbstractDataSource
├── AbstractDriverBasedDataSource
│   ├── DriverManagerDataSource
│   └── SimpleDriverDataSource
├── AbstractRoutingDataSource└──IsolationLevelDataSourceRouter
  1. DriverManagerDataSource核心方法
public class DriverManagerDataSource extends AbstractDriverBasedDataSource {@Overrideprotected Connection getConnectionFromDriver(String username, String password) throws SQLException {Properties mergedProps = new Properties();// 合并連接屬性Properties connProps = getConnectionProperties();if (connProps != null) {mergedProps.putAll(connProps);}if (username != null) {mergedProps.setProperty("user", username);}if (password != null) {mergedProps.setProperty("password", password);}// 關鍵點:每次通過DriverManager新建連接return DriverManager.getConnection(getUrl(), mergedProps);}
}

說明:通過用戶名密碼從驅動獲取連接,每次調用 getConnection() 都創建一條新連接,無連接池功能,適合測試環境。

2. SingleConnectionDataSource方法

public class SingleConnectionDataSource extends AbstractDriverBasedDataSource {private volatile Connection connection;@Overrideprotected Connection getConnectionFromDriver(String username, String password) throws SQLException {synchronized (this) {if (this.connection == null) {// 初始化唯一連接this.connection = doGetConnection(username, password);}return this.connection;}}protected Connection doGetConnection(String username, String password) throws SQLException {// 實際創建連接邏輯Properties mergedProps = new Properties();// ...屬性合并邏輯與DriverManagerDataSource類似return DriverManager.getConnection(getUrl(), mergedProps);}
}

說明:單例模式來維護唯一連接,直接使用JDBC Driver實例,線程安全通過synchronized和volatile保證。

3.AbstractRoutingDataSource
AbstractRoutingDataSource實現動態數據源路由抽象類,主要屬性如下

public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {// 目標數據源映射表private Map<Object, Object> targetDataSources;// 默認數據源private Object defaultTargetDataSource;// 解析后的數據源映射表private Map<Object, DataSource> resolvedDataSources;// 解析后的默認數據源private DataSource resolvedDefaultDataSource;// 數據源查找接口private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();// 是否寬松回退到默認數據源private boolean lenientFallback = true;
}

初始化方法(afterPropertiesSet)

@Overridepublic void afterPropertiesSet() {if (this.targetDataSources == null) {throw new IllegalArgumentException("Property 'targetDataSources' is required");}this.resolvedDataSources = CollectionUtils.newHashMap(this.targetDataSources.size());this.targetDataSources.forEach((key, value) -> {Object lookupKey = resolveSpecifiedLookupKey(key);DataSource dataSource = resolveSpecifiedDataSource(value);this.resolvedDataSources.put(lookupKey, dataSource);});if (this.defaultTargetDataSource != null) {this.resolvedDefaultDataSource = resolveSpecifiedDataSource(this.defaultTargetDataSource);}}

說明:將配置的targetDataSources轉換為可用的resolvedDataSources
獲取連接的邏輯:

@Override
public Connection getConnection() throws SQLException {return determineTargetDataSource().getConnection();
}
protected DataSource determineTargetDataSource() {Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");// 獲取當前查找鍵Object lookupKey = determineCurrentLookupKey();// 根據鍵查找數據源DataSource dataSource = this.resolvedDataSources.get(lookupKey);// 回退到默認數據源if (dataSource == null && (this.lenientFallback || lookupKey == null)) {dataSource = this.resolvedDefaultDataSource;}if (dataSource == null) {throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");}return dataSource;
}

AbstractRoutingDataSource定義了determineCurrentLookupKey()抽象方法,子類僅需實現此方法提供鍵值獲取邏輯。

核心邏輯:

  1. 初始化階段:
  • . 實現InitializingBean接口,在afterPropertiesSet()中解析targetDataSources,生成resolvedDataSources
  • defaultTargetDataSource解析為resolvedDefaultDataSource
  1. 運行時路由:
  • 通過determineCurrentLookupKey()抽象方法獲取當前數據源標識
  • 根據標識從resolvedDataSources中查找對應的數據源
  • 未找到時根據lenientFallback決定是否使用默認數據源

4.IsolationLevelDataSourceRouter(基于事務隔離級別的路由)

public class IsolationLevelDataSourceRouter extends AbstractRoutingDataSource {private static final Constants constants = new Constants(TransactionDefinition.class);@Overrideprotected Object resolveSpecifiedLookupKey(Object lookupKey) {// 解析隔離級別配置if (lookupKey instanceof Integer) return lookupKey;if (lookupKey instanceof String) {String constantName = (String) lookupKey;if (!constantName.startsWith(DefaultTransactionDefinition.PREFIX_ISOLATION)) {throw new IllegalArgumentException("Only isolation constants allowed");}return constants.asNumber(constantName);}throw new IllegalArgumentException("Invalid lookup key");}@Overrideprotected Object determineCurrentLookupKey() {// 從當前事務同步管理器中獲取隔離級別return TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();}
}

特點:

  • 根據事務隔離級別選擇數據源
  • 支持通過整數或字符串常量配置隔離級別

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/91185.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/91185.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/91185.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C語言(08)——關于指針(逐漸清晰版)

為了更好地理解本篇文章的知識內容&#xff0c;讀者可以將以下文章作為補充知識進行閱讀 &#xff1a; C語言————原碼 補碼 反碼 &#xff08;超絕詳細解釋&#xff09;-CSDN博客 C語言————二、八、十、十六進制的相互轉換-CSDN博客 C語言————斐波那契數列的理解…

LeetCode 1616.分割兩個字符串得到回文串

給你兩個字符串 a 和 b &#xff0c;它們長度相同。請你選擇一個下標&#xff0c;將兩個字符串都在 相同的下標 分割開。由 a 可以得到兩個字符串&#xff1a; aprefix 和 asuffix &#xff0c;滿足 a aprefix asuffix &#xff0c;同理&#xff0c;由 b 可以得到兩個字符串 …

算法【1】

網址&#xff1a;主站 工具補充 1. sort 函數的使用規則 作用&#xff1a;對容器元素進行排序&#xff0c;默認升序。語法&#xff1a;sort(起始迭代器, 結束迭代器, 比較規則) 前兩個參數是排序范圍&#xff1a;[begin, end)&#xff08;包含begin&#xff0c;不包含end&am…

信創國產Linux操作系統匯總:從桌面到服務器,百花齊放

在數字化浪潮席卷全球的今天&#xff0c;操作系統作為信息產業的基石&#xff0c;其戰略地位日益凸顯。曾經由國外巨頭壟斷的格局正悄然改變——中國本土Linux操作系統歷經多年沉淀&#xff0c;已形成了百花齊放的局面。無論是日常辦公、專業開發&#xff0c;還是關鍵行業應用&…

claudia for claude code

一.安裝所有必需的依賴項 1.安裝 Git for Windows 步驟: 訪問 Git 的官方網站 git-scm.com。 下載適用于 Windows 的最新版本安裝程序。 運行安裝程序。在安裝向導的各個步驟中&#xff0c;建議保留所有默認設置&#xff0c;這些設置對于本指南的后續操作已經足夠。 驗證…

企業內外網文件安全傳輸解決方案

企業內外網文件安全傳輸解決方案 基于零信任架構的智能中轉系統設計 一、業務背景與挑戰分析 1.1 企業網絡安全現狀 在數字化轉型浪潮下&#xff0c;企業面臨著前所未有的安全挑戰。傳統的"城墻式"網絡防護已無法滿足現代企業靈活協作的需求。根據《2024年中國企業…

《HCIA-Datacom 認證》希賽三色筆記:詳解 VLAN 間通信的 3 種實現方式

標記說明:&#xffed;掌握內容 &#xffed;次重點 &#xffed;理解內容 在局域網部署中&#xff0c;VLAN 技術通過隔離廣播域提升了網絡安全性和穩定性&#xff0c;但不同 VLAN 間的通信需求又成了新的難題。比如財務部門的電腦&#xff08;VLAN 10&#xff09;需要訪問服務…

Windows 10 系統下的編程字體安裝與配置(VSCode)教程

Windows 10 系統下的編程字體安裝與配置教程 常見的優秀編程字體 開發者社區中有許多備受推崇的編程字體&#xff0c;它們都致力于提升代碼的可讀性和舒適度。以下是一些常見的選擇&#xff1a; Fira Code: 以其豐富的編程連字&#xff08;ligatures&#xff09;而聞名&…

ITIL 4 高速IT:解耦架構——構建快速迭代的技術基座

一、為什么要解耦&#xff1a;從“架構”談到“速度”1.高速IT的真正瓶頸&#xff1a;不是能力&#xff0c;而是架構在我們深入學習ITIL 4 高速IT的時候&#xff0c;大家可能都會有個疑問&#xff1a;為什么有些組織在數字化轉型過程中推得動&#xff0c;有些卻始終難以突破&am…

網絡協議——MPLS(多協議標簽轉發)

一&#xff0c;基本概述1. mpls基本概念MPLS位于二三層之間&#xff0c;可以向所有網絡層提供服務。通過在數據鏈路層和網絡層之間增加額外的MPLS頭部&#xff0c;基于MPLS頭部實現數據快速轉發。2. 控制平面和轉發平面控制平面&#xff1a;負責產生和維護路由信息以及標簽信息…

影刀RPA_初級課程_玩轉影刀自動化_EXCEL操作自動化

聲明&#xff1a;相關內容來自影刀學院&#xff0c;本文章為自用筆記&#xff0c;切勿商用&#xff01;&#xff08;若有侵權&#xff0c;請聯絡刪除&#xff09; 1. 數據的表達 1.1 列表 1.1 獲取一段字符&#xff08;字符串列表的截取 —— 前開后閉&#xff09; 1.2 獲取長…

當貝純凈版_海信ip811n海思mv320處理器安卓4.42及9.0主板優盤免拆刷機固件及教程

海信IP811N安卓4.4.2及安卓9.0主板免拆升級教程 下載固件之前&#xff0c;請拆機確認下主板處理器是否為 海思hi3798mv320處理器&#xff0c;拆機將主板上 位于中心位置的CPU芯片上的黑色貼紙取下 然后查看芯片第二行是否有V32字樣&#xff0c;如下圖 然后進入機頂盒設置&a…

三、平衡橋電路

一、電路結構 由于平衡橋后要連接雙T型橋逆變電路并聯&#xff0c;這里采用平衡橋電路來穩定母線和中線的電壓平衡&#xff0c;使正母線電壓BUS和負母線電壓BUS-相對于中線的電壓大小相等&#xff0c;極性相反&#xff0c;如50VBUS&#xff0c;-50BUS-。 平衡橋電路由兩個電容…

Java-85 深入淺出 MySQL InnoDB 存儲結構:Buffer Pool、寫緩沖與日志機制全解

點一下關注吧&#xff01;&#xff01;&#xff01;非常感謝&#xff01;&#xff01;持續更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持續更新中&#xff01;&#xff08;長期更新&#xff09; AI煉丹日志-30-新發布【1T 萬億】參數量大模型&#xff01;Kim…

Linux救援模式之應用篇

掛載并訪問文件系統1. 首先識別分區 fdisk -l # 查看所有磁盤和分區 lsblk # 以樹狀結構查看塊設備 blkid # 查看分區的UUID和文件系統類型2. 創建掛載點并掛載分區 mkdir /mnt/rescue # 創建掛載點# 掛載根分區(根據你實際的根分區設備) mount /dev/…

【學習路線】游戲開發大師之路:從編程基礎到獨立游戲制作

前言 游戲開發是一個充滿創意和技術挑戰的領域&#xff0c;它融合了編程、美術、音效、設計等多個學科。隨著游戲產業的蓬勃發展&#xff0c;游戲開發已成為最具吸引力的技術職業之一。本文將為您提供一條從零基礎到游戲開發大師的完整學習路線&#xff0c;涵蓋編程基礎、游戲引…

宇樹 G1 部署(九)——遙操作控制腳本 teleop_hand_and_arm.py 分析與測試部署

首先&#xff0c;我使用的是 v1.0 版本&#xff0c;宇樹最近發力了更新的很快&#xff1a;xr_teleoperate-1.0 teleop_hand_and_arm.py 支持通過 XR 設備&#xff08;比如手勢或手柄&#xff09;來控制實際機器人動作&#xff0c;也支持在虛擬仿真中運行。可以根據需要&#x…

第十一天:不定方程求解

每日一道C題&#xff1a;不定方程求解 問題&#xff1a;給定正整數a&#xff0c;b&#xff0c;c。求不定方程 axbyc 關于未知數x和y的所有非負整數解組數。 要求&#xff1a;輸入一行&#xff0c;包含三個正整數a&#xff0c;b&#xff0c;c&#xff0c;兩個整數之間用單個空格…

ElasticStack技術棧概述及Elasticsearch8.2.2集群部署并更換JDK版本為openjdk-17

ElasticStack 一、引言 在當今數據驅動的時代&#xff0c;如何高效地收集、處理和分析日志及其他類型的數據&#xff0c;已成為企業構建可觀測性和運維能力的重要課題。Elastic Stack&#xff08;早期稱為 ELK Stack&#xff09;是一套由 Elastic 公司推出的開源技術棧&#xf…

Doris中文檢索效果調優

一、問題描述 原來的日志系統使用的是ES作為底層存儲&#xff0c;后來因為數據量大了之后&#xff0c;出現了寫入存在阻塞和查詢效率變低的問題。后來決定切換到Doris數據庫。 Doris的優勢根據公開資料來看&#xff0c;它在寫入性能、查詢效率和存儲成本上&#xff0c;都優于…