当前位置: 首页 > news >正文

SpringBoot 手动实现动态切换数据源 DynamicSource (上)

大家好,我是此林。

在实际开发中,经常可能遇到在一个SpringBoot Web应用中需要访问多个数据源的情况。

下面来介绍一下多数据源的使用场景、底层原理和手动实现。

一、 多数据源经典使用场景

场景一:业务复杂,数据量过大

1. 业务初期,开发的SpringBoot应用只需要访问一个数据库。

2. 随着业务的复杂度和数据量的不断增长,一台Mysql服务器容量可能存不下了,或者说业务复杂需要对接多个数据源。

3. 此时,一个SpringBoot 需要访问多个数据源。

上文所述也就是应用没有拆分,数据库进行了拆分。

有人可能会说,为什么不把应用也拆分成微服务,每个服务可以使用自己的独立的数据库。

答:要看实际业务,SpringBoot拆分成微服务也需要成本。

场景二:读写分离

虽然一个SpringBoot应用使用一个数据源,但为了保证Mysql的性能和高可用性,采用了Mysql主从集群的方式部署,主数据库只进行写操作,从数据库负责读操作。

此时,需要进行数据源的动态切换。

常用中间件:ShardingSphere、MyCat。

Mysql主从集群、读写分离,解决了以下问题:

1. 提高并发量,因为写锁会阻塞读操作。

2. 保证高可用性,数据备份。

二、动态切换数据源的底层原理 

我们先来想下,要用Spring 去操作mysql,配置流程。

比如我们执行了 userMapper.insert(user) ,见下图。

简而言之,ORM框架底层通过Spring-jdbc拿到我们配置的DataSource,再调用getConnection() 方法拿到数据库connection连接。

那么,Mybatis 通过 connection 就可以对数据库进行 CRUD 操作了。

观察发现,要实现动态数据源切换,我们能配置的只有DataSource这个扩展点。

所以,更改如下。

这里我们自定义了DynamicDataSource类,实现了DataSource接口,重写了getConnection() 方法。

读操作(用R标识) ,写操作(用W标识)。

根据不同的业务标识(R 或 W),来返回不同的注入的datsource bean(最左侧)。

因为前面也说了,只要执行了userMapper.insert() 方法,那么它底层就会先去 getConnection 得到数据库连接,才能对mysql 进行 CRUD操作。

三、手动实现

pom.xml

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.3.2</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.24</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope></dependency></dependencies>

application.yml

spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedatasource1:url: jdbc:mysql://localhost:3306/datasource1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghaiusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driverdatasource2:url: jdbc:mysql://localhost:3307/datasource2?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghaiusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver

DataSourceConfig.java

@Configuration
public class DataSourceConfig {@Bean(name = "dataSource1")@ConfigurationProperties(prefix = "spring.datasource.datasource1")public DataSource dataSource1(){return DruidDataSourceBuilder.create().build();}@Bean(name = "dataSource2")@ConfigurationProperties(prefix = "spring.datasource.datasource2")public DataSource dataSource2(){return DruidDataSourceBuilder.create().build();}
}

DynamicDataSource.java

@Component
@Primary // 将该Bean设置为主要注入Bean
public class DynamicDataSource implements DataSource, InitializingBean {// 当前使用的数据源标识public static ThreadLocal<String> name = new ThreadLocal<>();// 写@Autowired@Qualifier("dataSource1")DataSource dataSource1;// 读@Autowired@Qualifier("dataSource2")DataSource dataSource2;@Overridepublic Connection getConnection() throws SQLException {if (name.get().equals("R")) {return dataSource1.getConnection();} else {return dataSource2.getConnection();}}@Overridepublic Connection getConnection(String username, String password) throws SQLException {return null;}@Overridepublic <T> T unwrap(Class<T> iface) throws SQLException {return null;}@Overridepublic boolean isWrapperFor(Class<?> iface) throws SQLException {return false;}@Overridepublic PrintWriter getLogWriter() throws SQLException {return null;}@Overridepublic void setLogWriter(PrintWriter out) throws SQLException {}@Overridepublic void setLoginTimeout(int seconds) throws SQLException {}@Overridepublic int getLoginTimeout() throws SQLException {return 0;}@Overridepublic Logger getParentLogger() throws SQLFeatureNotSupportedException {return null;}@Overridepublic void afterPropertiesSet() throws Exception {name.set("W");}
}

由于我们注入了三个DataSource:datasource1、datasource2、DynamicDatasource

1. Spring 首先根据DataSource类型去IOC 容器中找,找到了三个DataSource。

2. 找到了后再根据beanName = "datasource" 去找

3. 我们这里没有bean的名字叫datasource的,所以Spring不知道使用哪个DataSource。

解决:在DynamicDatasource类上加@Primary,将其作为主要的Bean优先注入使用。

(即:当出现相同的DataSource类型,优先使用DynamicDatasource)

测试:

通过浏览器访问,查看mysql数据库检验是否进行了对应的数据源切换即可。

当然,这只是粗糙的实现了以下动态数据源的切换,为了讲明白原理,简化了很多步骤。

后续会出SpringBoot 手动实现动态切换数据源 DynamicSource (中)、SpringBoot 手动实现动态切换数据源 DynamicSource (下),讲述进阶版、多数据源事务管理、及主流框架使用,持续更新!

关注我吧,我是此林,带你看不一样的世界!

更新后续:

2024.12.12

SpringBoot 手动实现动态切换数据源 DynamicSource (中)-CSDN博客

相关文章:

SpringBoot 手动实现动态切换数据源 DynamicSource (上)

大家好&#xff0c;我是此林。 在实际开发中&#xff0c;经常可能遇到在一个SpringBoot Web应用中需要访问多个数据源的情况。 下面来介绍一下多数据源的使用场景、底层原理和手动实现。 一、 多数据源经典使用场景 场景一&#xff1a;业务复杂&#xff0c;数据量过大 1. 业务…...

ERROR Error: command failed: yarnError: command failed: yarn

1、异常信息 2、解决 解决方法一&#xff1a; WinR进入命令行&#xff0c;重新安装npm(如果报镜像源问题建议镜像源也重新配置) 输入命令&#xff0c;重新安装npm/yarn #npm npm install#npm 配置镜像源 npm config set registry https://registry.npmmirror.com#npm 查看镜…...

【java】finalize方法

目录 1. 说明2. 调用过程3. 注意事项 1. 说明 1.finalize方法是Java中Object类的一个方法。2.finalize方法用于在对象被垃圾回收之前执行一些清理工作。3.当JVM&#xff08;Java虚拟机&#xff09;确定一个对象不再被引用、即将被回收时&#xff0c;会调用该对象的finalize方法…...

C++ 内存管理和模板与STL

此篇目是之后各种C库的基础 目录 内存管理 内存分布 内存管理方式 new和delete operator new 与 operator delete函数 实现原理 定位new表达式(placement-new) 模板基础 泛型编程 模板 函数模板 类模板 STL 组成部分 内存管理 内存分布 int globalVar 1; //全局变量 静…...

同一个局域网下的两台电脑实现定时或者实时拷贝数据

【亲测能用】 需求&#xff1a;从数据库服务器上将数据库备份文件*.bak&#xff0c;每天定时拷贝到局域网下另一台电脑上&#xff0c;实现异机备份。 本文中192.168.1.110是本机&#xff0c;192.168.1.130是异机&#xff08;备份机&#xff09;。需求是每天定时从192.168.1.1…...

Python毕业设计选题:基于django+vue的汽车租赁管理网站

开发语言&#xff1a;Python框架&#xff1a;djangoPython版本&#xff1a;python3.7.7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 用户管理 汽车品牌管理 汽车信息管理 汽车租赁管理 汽车商品信息管理 汽车租赁 购物…...

scrapy对接rabbitmq的时候使用post请求

之前做分布式爬虫的时候,都是从push url来拿到爬虫消费的链接,这里提出一个问题,假如这个请求是post请求的呢,我观察了scrapy-redis的源码,其中spider.py的代码是这样写的 1.scrapy-redis源码分析 def make_request_from_data(self, data):"""Returns a Reques…...

Netty 性能优化与调试指南

Netty 是一款高性能的网络通信框架&#xff0c;其高性能得益于良好的设计和优化。但是在实际使用中&#xff0c;如果配置或实现不当&#xff0c;可能会导致性能下降或调试困难。本文将从性能优化和调试两方面入手&#xff0c;详细讲解如何在使用 Netty 时提高应用性能和诊断问题…...

网络安全产品之认识WEB应用防火墙

随着B/S架构的广泛应用&#xff0c;Web应用的功能越来越丰富&#xff0c;蕴含着越来越有价值的信息&#xff0c;应用程序漏洞被恶意利用的可能性越来越大&#xff0c;因此成为了黑客主要的攻击目标。传统防火墙无法解析HTTP应用层的细节&#xff0c;对规则的过滤过于死板&#…...

R学习——因子

目录 1 定义因子&#xff08;factor函数&#xff09; 2因子的作用 一个数据集中的 只需要考虑可以用哪个数据来进行分类就可以了&#xff0c;可以用来分类就可以作为因子。 Cy1这个因子对应的水平level是4 6 8&#xff1a; 1 定义因子&#xff08;factor函数&#xff09; 要…...

2024 亚马逊云科技re:Invent:Werner Vogels架构哲学,大道至简 六大经验助力架构优化

在2024亚马逊云科技re:Invent全球大会第四天的主题演讲中&#xff0c;亚马逊副总裁兼CTO Dr.Werner Vogels分享了 The Way of Simplexity&#xff0c;繁简之道&#xff0c;浓缩了Werner在亚马逊20年构建架构的经验。 Werner表示&#xff0c;复杂性总是会“悄无声息”地渗透进来…...

【代码随想录day58】【C++复健】 117. 软件构建(拓扑排序);47. 参加科学大会(dijkstra(朴素版)精讲)

117. 软件构建&#xff08;拓扑排序&#xff09; 继续边看解析边做题&#xff0c;思考时的问题做个如下的总结&#xff1a; 1. 存边用什么数据结构&#xff1f; 在题目中&#xff0c;我们需要存储节点之间的依赖关系&#xff08;边信息&#xff09;。选择适合的数据结构非常重…...

单目深度估计模型 lite-mono 测试

lite-mono 使用工业数据集kitti 进行训练&#xff0c;目的使用单目摄像头实现物体深度预测&#xff0c;关于kitti数据集的介绍和下载参考 &#xff08;二&#xff09;一文带你了解KITTI数据集-CSDN博客文章浏览阅读2.7w次&#xff0c;点赞64次&#xff0c;收藏294次。文章介绍…...

JAVA基础学习笔记_网络编程

文章目录 网络编程网络编程三要素IPIPv4细节InetAddress 端口号协议 UDPUDP协议(发数据)UDP协议(接受数据)UDP聊天室单播,组播,广播 TCP中文乱码问题代码细节,三次握手和四次挥手 网络编程 计算机之间通过网络进行数据传输 软件结构 C/S,Client/Server,客户端服务器,精美但麻…...

说下JVM中一次完整的GC流程?

大家好&#xff0c;我是锋哥。今天分享关于【说下JVM中一次完整的GC流程&#xff1f;】面试题。希望对大家有帮助&#xff1b; 说下JVM中一次完整的GC流程&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在JVM中&#xff0c;垃圾回收&#xff08;GC&am…...

鸿蒙NEXT开发案例:保质期计算

【引言】 保质期计算应用是一个基于鸿蒙NEXT框架开发的数字和文本统计组件。用户可以输入商品的生产日期和保质期天数&#xff0c;应用会自动计算并展示相关信息&#xff0c;包括保质状态、剩余天数、生产日期和到期日期。 【环境准备】 • 操作系统&#xff1a;Windows 10 …...

LLM并发加速部署方案(llama.cpp、vllm、lightLLM、fastLLM)

大模型并发加速部署 解析当前应用较广的几种并发加速部署方案&#xff01; llama.cpp、vllm、lightllm、fastllm四种框架的对比&#xff1a; llama.cpp&#xff1a;基于C&#xff0c;①请求槽&#xff0c;②动态批处理&#xff0c;③CPU/GPU混合推理vllm&#xff1a;基于Pyth…...

用最小的代价解决mybatis-plus关于批量保存的性能问题

1.问题说明 问题背景说明&#xff0c;在使用达梦数据库时&#xff0c;mybatis-plus的serviceImpl.saveBatch()方法或者updateBatchById()方法的时候&#xff0c;随着数据量、属性字段的增加&#xff0c;效率越发明显的慢。 serviceImpl.saveBatch(); serviceImpl.updateBatch…...

蓝桥杯历届真题 --#递推 翻硬币(C++)

文章目录 思路完整代码结语 原题链接 思路 通过观察测试用例&#xff0c;我们猜测&#xff0c;从左到右依次对比每一个位置上的状态&#xff0c;如果不一样我们就翻一次&#xff0c;最终得到的答案即为正解。 完整代码 //这里是引入了一些常用的头文件,和一些常规操作 //第一…...

BurpSuite-8(FakeIP与爬虫审计)

声明&#xff1a;学习视频来自b站up主 泷羽sec&#xff0c;如涉及侵权马上删除文章 感谢泷羽sec 团队的教学 视频地址&#xff1a;IP伪造和爬虫审计_哔哩哔哩_bilibili 一、FakeIP 1.配置环境 BurpSuite是java环境下编写的&#xff0c;而今天的插件是python编写的&#xff0c…...

JAVA8、Steam、list运用合集

Steam运用 Java Stream API为开发人员提供了一种函数式和声明式的方式来表达复杂的数据转换和操作,使代码更加简洁和富有表现力。 1、使用原始流以获得更好的性能【示例:求和】 使用 int、long 和 double 等基本类型时,请使用IntStream、LongStream 和 DoubleStream 等基本流…...

深入详解人工智能机器学习:强化学习

目录 强化学习概述 强化学习的基本概念 定义 关键组件 强化学习过程 常用算法 应用示例 示例代码 代码解释 应用场景 强化学习核心概念和底层原理 核心概念 底层原理 总结 强化学习概述 强化学习&#xff08;Reinforcement Learning, RL&#xff09;是机器学习中的…...

docker的简单使用

文章目录 docker简介docker架构镜像和容器镜像有关的常用命令容器相关常用命令 docker简介 Docker是一个开源的应用容器引擎&#xff0c;基于Go语言并遵从Apache2.0协议开源。 Docker可以让开方子打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到…...

启动的docker容器里默认运行dockerd

问题 已在Dockerfile里yum install docker 但docker run 启动容器后, docker ps等命令无法执行 ps -aux 没有dockerd 进程 临时解决 另开一个终端 docker exec -it 容器名 bash 手动启 dockerd 默认启动 分析 现在启动容器的默认命令是 /sbin/init sbin/init 是根文件系统…...

Python爬虫技术的最新发展

在互联网的海洋中&#xff0c;数据就像是一颗颗珍珠&#xff0c;而爬虫技术就是我们手中的潜水艇。2024年&#xff0c;爬虫技术有了哪些新花样&#xff1f;让我们一起潜入这个话题&#xff0c;看看最新的发展和趋势。 1. 异步爬虫&#xff1a;速度与激情 随着现代Web应用的复…...

什么是厄尔米特(Hermitian)矩阵?

厄米矩阵&#xff08;Hermitian Matrix&#xff09;定义 在数学和物理中&#xff0c;厄米矩阵是满足以下条件的复方阵&#xff1a; A A † \mathbf{A}\mathbf{A}^\dagger AA† 其中&#xff0c; A † \mathbf{A}^\dagger A†表示矩阵 A \mathbf{A} A的共轭转置&#xff0c;即…...

从零开始:Linux 环境下的 C/C++ 编译教程

个人主页&#xff1a;chian-ocean 文章专栏 前言&#xff1a; GCC&#xff08;GNU Compiler Collection&#xff09;是一个功能强大的编译器集合&#xff0c;支持多种语言&#xff0c;包括 C 和 C。其中 gcc 用于 C 语言编译&#xff0c;g 专用于 C 编译。 Linux GCC or G的安…...

Excel + Notepad + CMD 命令行批量修改文件名

注意&#xff1a;该方式为直接修改原文件的文件名&#xff0c;不会生成新文件 新建Excel文件 A列&#xff1a;固定为 renB列&#xff1a;原文件名称C列&#xff1a;修改后保存的名称B列、C列&#xff0c;需要带文件后缀&#xff0c;为txt文件就是.txt结尾&#xff0c;为png图片…...

1.1 android:监听并处理返回事件

在Android开发过程中&#xff0c;默认执行返回事件是结束当前界面&#xff0c;返回上一个界面&#xff0c;没有任何提示&#xff0c;但用户可能会误操作&#xff0c;这时出现一个提示界面对用户较为友好&#xff0c;接下来&#xff0c;让我们探究返回事件的处理。 一、onBackP…...

解决Ubuntu关机主板不断电的问题(其它使用GRUB的Linux发行版大概率也可用)

前言&#xff1a; 在某些主板上&#xff0c;Ubuntu20.04系统关机并不会连带主板一起断电。 猜测可能是主板太老了。无法识别较新的系统的关机信号&#xff0c;导致无法断电。连带着一些电脑周边设备也不会断电导致状态无法重置&#xff0c;后续会出现一些问题。 目标&#xf…...

【CTF-Web】文件上传漏洞学习笔记(ctfshow题目)

文件上传 文章目录 文件上传 What is Upload-File&#xff1f;Upload-File In CTF Web151 考点&#xff1a;前端校验解题&#xff1a; Web152 考点&#xff1a;后端校验要严密解题&#xff1a; Web153 考点&#xff1a;后端校验 配置文件介绍解题&#xff1a; Web154 考点&am…...

无法正常启动此程序,因为计算机丢失wlanapi.dll

wlanapi.dll丢失怎么办&#xff1f;有没有什么靠谱的修复wlanapi.dll方法_无法启动此程序,因为计算机中丢失wlanapi.dll-CSDN博客 wlanapi.dll是 Windows 操作系统中的一个动态链接库文件&#xff0c;主要与 Windows 无线 LAN (WLAN) API 相关。该DLL提供了许多必要的函数&…...

C++ webrtc开发(非原生开发,linux上使用libdatachannel库)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、libdatachannel库的下载和build二、开始使用 1.2.引入库3.开始使用 总结 前言 使用c开发webrtc在互联网上留下的资料甚少&#xff0c;经过我一段时间的探…...

vue-router路由传参的两种方式(params 和 query )

一、vue-router路由传参问题 1、概念&#xff1a; A、vue 路由传参的使用场景一般应用在父路由跳转到子路由时&#xff0c;携带参数跳转。 B、传参方式可划分为 params 传参和 query 传参&#xff1b; C、而 params 传参又可分为在 url 中显示参数和不显示参数两种方式&#x…...

VBA高级应用30例应用在Excel中的ListObject对象:向表中添加注释

《VBA高级应用30例》&#xff08;版权10178985&#xff09;&#xff0c;是我推出的第十套教程&#xff0c;教程是专门针对高级学员在学习VBA过程中提高路途上的案例展开&#xff0c;这套教程案例与理论结合&#xff0c;紧贴“实战”&#xff0c;并做“战术总结”&#xff0c;以…...

github操作学习笔记(杂乱版)

git开源的分布式版本控制系统&#xff1a; 每次修改文件提交后&#xff0c;都会自动创建一个项目版本 查看git版本看有没有安装成功&#xff1a;git --version 把默认编辑器设置成vim&#xff1a;git config --global core.editor "vim" 1、设置昵称和邮箱&#xff…...

TaskBuilder SQL执行工具

为了方便开发者连接当前任擎服务器上配置的各个数据源对应的数据库进行相关操作&#xff0c;TaskBuilder提供了一个SQL执行工具&#xff0c;点击系统侧边栏里的执行SQL图标 &#xff0c;即可打开该工具&#xff0c;界面如下图所示&#xff1a; 该工具从上至下分为三个区域&a…...

快速掌握Quartz.Net计划任务调度框架,轻松实现定时任务

前言 Quartz.Net是一个开源的作业调度框架&#xff0c;可以用于管理计划任务和定期执行。Quartz.Net提供了丰富的作业计划选项&#xff0c;例如精确或模糊时间表达式、日期和时间限制等。Quartz.Net采用分布式架构&#xff0c;允许在多个计算机上运行任务。 Quartz.Net架构设…...

Linux ufw命令丨Linux网络防火墙ufw命令详解

ufw&#xff08;Uncomplicated Firewall&#xff09;是Ubuntu系统上默认的防火墙组件&#xff0c;它为轻量化配置iptables而开发&#xff0c;提供了一个非常友好的界面用于创建基于IPv4和IPv6的防火墙规则 ufw在Ubuntu 8.04 LTS后的所有发行版中默认可用&#xff0c;它通过命令…...

shell编程(完结)

shell编程&#xff08;完结&#xff09; 声明&#xff01; 学习视频来自B站up主 ​泷羽sec​​ 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章 笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其…...

深入了解Text2SQL开源项目(Chat2DB、SQL Chat 、Wren AI 、Vanna)

深入了解Text2SQL开源项目&#xff08;Chat2DB、SQL Chat 、Wren AI 、Vanna&#xff09; 前言1.Chat2DB2.SQL Chat3.Wren AI4.Vanna 前言 在数据驱动决策的时代&#xff0c;将自然语言查询转化为结构化查询语言&#xff08;SQL&#xff09;的能力变得日益重要。无论是小型创业…...

【Linux】报错:cannot create directory ‘test’: Read-only file system

1 报错 ❤️在使用mkdir test命令创建文件夹的时候,报错如下: mkdir:cannot create directory ‘test’:Read-only file system 2 解决方法 mount -o remount,rw / 🦋上述命令在Linux系统中用于重新挂载(root)文件系统,并将其从只读模式切换到读写模式。 ■ 下面是对…...

python mat是什么文件

.mat就是matlab的文件格式&#xff0c;一般用于matlab和python间的数据传输&#xff0c;python中numpy和scipy提供了一些函数&#xff0c;可以很好的对.mat文件的数据进行读写和处理。 在python中可以使用scipy.io中的函数loadmat()读取mat文件&#xff0c;函数savemat保存文…...

Redis: 一个高效的内存数据存储解决方案

Redis: 一个高效的内存数据存储解决方案 介绍 Redis&#xff08;Remote Dictionary Server&#xff09;是一种开源的高性能键值存储系统。它常被用作缓存、消息队列、会话存储、实时数据分析等多种场景。与传统的关系型数据库不同&#xff0c;Redis 是基于内存的数据存储&…...

AR眼镜_消费级工业AR智能眼镜主板硬件解决方案

AR眼镜的研发是一项复杂的软硬件集成工程&#xff0c;它需要在摄影、音频、交互和连接等多个方面提供卓越的基础体验&#xff0c;因此产品的每个细节都显得尤为重要。 在设计AR眼镜时&#xff0c;重量、体积和散热性能都是必须认真考量的关键因素。在芯片平台的选择上&#xff…...

C# 异常处理

C# 异常处理 异常处理是编程中不可或缺的一部分,它允许程序在遇到错误或意外情况时优雅地处理这些问题,而不是直接崩溃。C# 提供了一套强大的异常处理机制,包括 try-catch 块、finally 块和 throw 语句。本文将深入探讨 C# 中的异常处理,包括如何捕获和处理异常,以及如何…...

图解SSH原理

1. 初见SSH SSH是一种协议标准&#xff0c;其目的是实现安全远程登录以及其它安全网络服务。 SSH仅仅是一协议标准&#xff0c;其具体的实现有很多&#xff0c;既有开源实现的OpenSSH&#xff0c;也有商业实现方案。使用范围最广泛的当然是开源实现OpenSSH。 2. SSH工作原理 …...

如何快速批量把 PDF 转为 JPG 或其它常见图像格式?

在某些特定场景下&#xff0c;将 PDF 转换为 JPG 图片格式却具有不可忽视的优势。例如&#xff0c;当我们需要在不支持 PDF 查看的设备或软件中展示文档内容时&#xff0c;JPG 图片能够轻松被识别和打开&#xff1b;此外&#xff0c;对于一些网络分享或社交媒体发布的需求&…...

在CentOS中安装和卸载mysql

在CentOS7中安装和卸载mysql 卸载mysql1、查看是否安装过mysql2、查看mysql服务状态3、关闭mysql服务4、卸载mysql相关的rpm程序5、删除mysql相关的文件6、删除mysql的配置文件my.cnf 安装mysql1、下载mysql相关的rpm程序2、检查/tmp临时目录权限3、安装mysql前的依赖检查3、安…...

第十二章:异常(2)

六、自定义异常类 1. 定义一个类继承 异常类 (1) 定义异常类如果为运行时异常&#xff0c;则需要继承 RuntimeException class CheckedPasswordException extends RuntimeException{} (2) 定义异常类如果为非运行时异常&#xff0c;则需要继承 Exception class CheckedPass…...