一、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;都优于…