Java八股文——MySQL「锁篇」

讲一下MySQL里有哪些锁?

面试官您好,MySQL中的锁机制非常丰富,它是保证数据一致性和并发安全的核心。我通常会从锁的粒度(加锁范围)锁的模式(功能) 这两个维度来理解它们。

第一维度:按锁的粒度划分

按加锁的范围,MySQL的锁可以分为三级:全局锁、表级锁、行级锁。粒度从大到小,加锁开销从低到高,并发性能则从低到高。

  • 1. 全局锁 (Global Lock)

    • 特点:对整个数据库实例加锁。
    • 具体实现:通过命令FLUSH TABLES WITH READ LOCK; (FTWRL) 来实现。
    • 作用:执行后,整个数据库会处于只读状态。所有的数据更新语句(INSERT, UPDATE, DELETE)、数据定义语句(DDL)和事务提交语句(COMMIT)都会被阻塞。
    • 应用场景:主要用于全库的逻辑备份。通过加全局锁,可以保证在备份期间,获得一个完全一致的数据快照。
  • 2. 表级锁 (Table-level Lock)

    • 特点:对整张数据表加锁。
    • 具体实现
      • 表锁:通过LOCK TABLES ... READ/WRITE;命令可以显式地加表锁。
      • 元数据锁 (Meta Data Lock, MDL):这是MySQL 5.5引入的,由系统自动添加。当对一个表做增删改查时,会自动加上MDL读锁;当要修改表结构(DDL)时,会自动加上MDL写锁。MDL锁主要是为了防止在查询时,有另一个线程来修改表结构,保证数据一致性。
      • 意向锁 (Intention Lock):这是InnoDB引擎特有的、由系统自动管理的表级锁。它不与行锁冲突,它的唯一作用就是“表态”——告诉其他事务,“这张表里有某些行已经被加锁了”。比如,一个事务想加表级写锁,它就不需要去遍历每一行看有没有被锁,只需要检查一下表上有没有意向锁即可,大大提高了效率。
  • 3. 行级锁 (Row-level Lock)

    • 特点:只对某一行或某几行数据加锁。这是InnoDB存储引擎的巨大优势,也是它能支持高并发的关键。行级锁的粒度最细,锁冲突的概率最低,并发性能最好。
    • 具体实现 (InnoDB)
      • 记录锁 (Record Lock):最简单的行锁,就是精确地锁住一条索引记录
      • 间隙锁 (Gap Lock):它锁住的是一个 “间隙”,即两条索引记录之间的开区间。比如,锁住(3, 8)这个区间。它的主要作用是防止幻读,阻止其他事务在这个间隙中插入新的记录。
      • 临键锁 (Next-Key Lock):可以看作是记录锁和间隙锁的结合体。它既锁住了记录本身,又锁住了该记录之前的那个间隙。这是InnoDB在 “可重复读”隔离级别下,默认的行锁算法
第二维度:按锁的模式/功能划分
  • 共享锁 (Shared Lock, S锁):也叫读锁。多个事务可以同时持有同一份数据的S锁,大家可以一起读。
  • 排他锁 (Exclusive Lock, X锁):也叫写锁。它是独占的。只要有一个事务持有了X锁,其他任何事务都不能再获取该数据的任何锁(无论是S锁还是X锁)。
补充:乐观锁与悲观锁
  • 这是一种思想层面的划分。
  • 悲观锁:就是上面提到的所有锁机制,认为冲突总会发生,所以先加锁再操作。
  • 乐观锁:不加锁,而是在更新时通过版本号(version)CAS机制来检查数据是否被修改过。这在应用层实现,不是MySQL数据库自带的锁机制。

总结一下,MySQL通过一个从粗到细(全局->表->行)的锁粒度体系,并结合读写模式(S/X锁),以及在InnoDB中精巧的行锁实现(记录锁、间隙锁、临键锁),为我们提供了非常丰富和强大的并发控制能力。在开发中,理解并善用InnoDB的行级锁,是实现高性能并发事务的关键。


数据库的表锁和行锁有什么作用?

面试官您好,表锁和行锁是数据库为了管理并发访问而采用的两种不同粒度的锁定机制。它们没有绝对的优劣之分,而是分别适用于不同的场景,是在 “加锁开销”“并发性能” 之间做出不同权衡的结果。

1. 表锁 (Table Lock) —— “简单粗暴,开销小,但并发差”
  • 作用与特点

    • 粒度最大:当一个事务对一张表加锁时,它会锁定整张表
    • 实现简单,加锁开销小:因为只需要一个锁来管理整张表,所以加锁和释放锁的逻辑非常简单,系统开销很低。
    • 锁冲突概率最高:这是它最致命的缺点。只要有一个事务锁住了这张表,其他任何想操作这张表的事务(无论是读还是写,取决于锁的模式)都必须等待。这使得并发性能非常差
  • 适用场景

    • 它非常适合那些大批量的、针对全表的操作。比如,ALTER TABLE修改表结构,或者对整张表进行数据迁移、批量更新等。在这些场景下,锁定整张表反而是最简单高效的方式。
    • MyISAM存储引擎主要使用的就是表级锁,这也是为什么MyISAM在写操作频繁的场景下并发性能很差的原因。
2. 行锁 (Row Lock) —— “精准控制,并发好,但开销大”
  • 作用与特点

    • 粒度最细:只锁定被操作的特定一行或几行数据。
    • 并发性能最高:这是它最大的优势。不同的事务可以同时操作同一张表中的不同行,而互不干扰,极大地提高了系统的并发处理能力。
    • 实现复杂,加锁开销大:因为需要为每一行都可能建立锁信息,所以行锁的实现逻辑更复杂,加锁和管理的系统开销也比表锁要大。
    • 可能引发死锁:由于锁的粒度变细,多个事务在操作不同行时,更容易形成复杂的锁等待关系,从而增加了死锁发生的概率。
  • 适用场景

    • 非常适合那些高并发、事务操作只涉及少量行的场景。这几乎是所有现代在线交易系统(OLTP)的典型特征。比如,订单系统、用户账户系统等,每次操作都只是针对一个或几个用户的特定数据。
    • InnoDB存储引擎的巨大优势,就在于它实现了高效的行级锁,这也是它成为MySQL默认和主流存储引擎的核心原因。

总结与权衡

特性表锁 (Table Lock)行锁 (Row Lock)
锁定粒度整张表单行/多行数据
加锁开销
并发性能
锁冲突概率
死锁概率
主要使用者MyISAMInnoDB

一句话总结表锁是用“牺牲并发度”来换取“低开销和简单性”,而行锁是用“更高的系统开销和更复杂的实现”来换取“极高的并发性能”。在今天的互联网应用中,高并发是常态,因此支持行锁的InnoDB引擎成为了绝对的主流。


MySQL两个线程的UPDATE语句同时处理一条数据,会不会有阻塞?

面试官您好,您提出的这个问题,直击了数据库并发控制的核心。

答案是:会的,后一个UPDATE语句会被阻塞。

这背后的根本原因,是MySQL InnoDB存储引擎强大的行级锁机制

1. 详细的执行过程分析

我们来详细地模拟一下这个过程,假设我们有两个独立的事务,事务A和事务B,它们都要执行UPDATE ... WHERE id = 1

  1. 事务A抢先执行

    • 首先,事务A开始执行UPDATE语句。
    • 为了保证数据的一致性和操作的原子性,InnoDB会在定位到id = 1这条记录时,立即为它加上一把排他锁(Exclusive Lock),也就是X锁。这把锁,具体来说,就是一把记录锁(Record Lock)
    • 加上X锁后,事务A开始对这条记录进行修改。
  2. 事务B随后执行

    • 紧接着,事务B也开始执行它自己的UPDATE语句,同样尝试去修改id = 1的记录。
    • 当事务B尝试去获取id = 1这条记录的锁时,它会发现这行记录已经被事务A持有了X锁
    • 锁冲突发生:X锁是排他的,意味着只要它存在,其他任何事务都无法再对这条记录获取任何类型的锁(无论是共享的S锁还是排他的X锁)。
  3. 事务B进入阻塞状态

    • 因此,事务B的UPDATE语句会立即进入阻塞(Waiting)状态。它会一直在这里等待,直到事务A释放这把锁。
2. 阻塞之后会发生什么?
  • 情况一:事务A提交(COMMIT)

    • 当事务A完成所有操作并提交后,它会释放掉所有持有的锁,包括id = 1这条记录上的X锁。
    • 锁被释放的瞬间,正在等待的事务B会被唤醒,它会立即获取到X锁,然后继续执行自己的UPDATE操作。
  • 情况二:事务A回滚(ROLLBACK)

    • 如果事务A因为某种原因回滚了,它同样会释放所有锁。
    • 事务B同样会被唤醒,获取锁,然后执行UPDATE
  • 情况三:锁等待超时

    • 事务B的等待不是无限的。这个等待时间由MySQL的参数innodb_lock_wait_timeout控制(默认是50秒)。
    • 如果事务A长时间不提交也不回滚,导致事务B的等待时间超过了这个阈值,那么事务B的UPDATE语句就会失败,并抛出一个 “Lock wait timeout exceeded” 的错误。
3. 与“读”操作的对比
  • 如果事务B执行的是普通SELECTSELECT * FROM ... WHERE id = 1;

    • 在InnoDB的默认隔离级别(可重复读)下,这个读操作会通过MVCC来执行,它会去读取一个历史快照版本的数据,不会去获取锁。因此,它和事务A的UPDATE不会发生冲突,不会阻塞
  • 如果事务B执行的是加锁读SELECT ... FOR UPDATE

    • 这个操作也需要获取X锁,所以它的行为会和UPDATE一样,同样会被阻塞

总结一下,两个线程(事务)同时UPDATE同一条数据,由于InnoDB行级锁(X锁)的互斥性,必然会导致后一个事务被阻塞,直到前一个事务结束。这是数据库保证写-写操作数据一致性的基本手段。


两条UPDATE语句处理一张表的不同的主键范围的记录,一个<10,一个>15,会不会遇到阻塞?底层是为什么的?

面试官您好,您提出的这个问题非常好,它触及了InnoDB在“可重复读”(Repeatable Read)隔离级别下,范围更新临键锁(Next-Key Lock) 的工作机制。

直接的答案是:在绝大多数情况下,它们不会相互阻塞。但存在一种特殊的边界情况,可能会导致阻塞。

要理解这一点,我们需要先明确InnoDB的默认行锁算法——临键锁。

  • 临键锁 (Next-Key Lock) = 记录锁 (Record Lock) + 间隙锁 (Gap Lock)
    • 它不仅会锁住满足条件的记录本身,还会锁住这条记录之前的那个 “间隙”
    • 它的主要目的是为了防止幻读

下面我们来分两种情况讨论:

情况一:两个UPDATE语句的范围内,都存在实际的数据行(最常见的情况)

假设我们的表中,数据分布是这样的:id1, 5, 8, 16, 20

  • 事务A执行: UPDATE ... WHERE id < 10;

    • 加锁分析:InnoDB会扫描id小于10的范围。
      1. 它会给id=1, 5, 8这三条记录加上X型的记录锁
      2. 同时,它会给这些记录之间的间隙,以及id=8id=16之间的间隙,都加上X型的间隙锁
    • 最终锁定的范围:大致可以理解为 (-∞, 1], (1, 5], (5, 8], (8, 16)。 注意,16这条记录本身没有被锁,但它之前的间隙被锁了。
  • 事务B执行: UPDATE ... WHERE id > 15;

    • 加锁分析:InnoDB会扫描id大于15的范围。
      1. 它会给id=16, 20这两条记录加上X型的记录锁
      2. 同时,它会给id=16id=20的间隙,以及id=20到正无穷的间隙,都加上X型的间隙锁
    • 最终锁定的范围:大致可以理解为 (8, 16], (16, 20], (20, +∞)。注意,这里的(8, 16]和事务A的(8, 16),实际上是对同一个间隙加锁,但由于事务B要锁id=16这条记录,它会成功,因为事务A没有锁住这条记录。
  • 结论:在这种情况下,两个事务加锁的记录间隙完全不重叠的。因此,它们不会相互阻塞,可以并行执行。

情况二:两个UPDATE语句的范围内,没有任何数据行(特殊的边界情况)

这是一个容易被忽略的、但能体现理解深度的特例。假设我们的表中,数据是 id = 20, 30

  • 事务A执行: UPDATE ... WHERE id < 10;

    • 加锁分析:InnoDB扫描id < 10的范围,发现没有任何记录
    • 间隙锁的行为:为了防止有其他事务插入id < 10的数据(防止幻读),它仍然需要加一个间隙锁。它会找到第一个大于10的记录(即id=20),然后锁住从负无穷到id=20之间的这个巨大间隙。
    • 最终锁定的范围(-∞, 20)。注意,是开区间,不包括20这条记录。
  • 事务B执行: UPDATE ... WHERE id > 15;

    • 加锁分析:InnoDB扫描id > 15的范围。
      1. 它首先要定位到大于15的第一条记录,也就是id=20
      2. 它尝试对id=20这条记录以及它之前的间隙 (..., 20] 加临键锁。
    • 锁冲突发生:当它尝试在id=20之前的间隙(也就是(..., 20)这个区间)加锁时,发现这个间隙已经被事务A的间隙锁锁住了
  • 结论:在这种特殊情况下,虽然两个UPDATE的条件范围(<10>15)在逻辑上没有任何交集,但由于间隙锁的存在,它们可能会去争抢同一个“间隙”的锁,从而导致事务B被事务A阻塞

总结

  • 绝大多数数据分布正常的情况下,两个UPDATE操作不同范围的记录,由于行锁和间隙锁的范围不重叠,不会发生阻塞
  • 但在一些边界或数据稀疏的特殊情况下,由于间隙锁可能会锁定一个比查询范围更大的“空隙”,导致两个看似无关的UPDATE语句,也可能发生锁冲突和阻塞

能分析到第二种情况,并解释清楚间隙锁在其中的作用,就能充分展示您对InnoDB锁机制的深刻理解。


如果2个范围不是主键或索引?还会阻塞吗?

面试官您好,您提出的这个问题,其答案与上一个问题截然相反。

答案是:会的,后一个UPDATE语句会被阻塞。

这背后的根本原因,正如您所分析的:UPDATE语句的WHERE条件中,使用的列没有索引时,MySQL无法进行高效的定位,只能退化为全表扫描。而在InnoDB的“可重复读”隔离级别下,全表扫描会给扫描过的每一条记录都加上行锁(临键锁)。

1. 发生了什么?—— 从索引定位到全表扫描
  • 有索引时:当WHERE条件是主键或索引列时,InnoDB可以利用B+树,精确地、快速地定位到需要修改的那几行记录,然后只对这几行以及它们周围的间隙加锁。
  • 没有索引时:当WHERE条件是一个普通列时(比如status列),InnoDB不知道哪些行的status满足条件。它唯一的办法,就是从聚簇索引的第一行开始,逐行地向后扫描,直到表的末尾,然后对每一行都判断其status值是否符合条件。这个过程,就是全表扫描
2. 为什么全表扫描会锁住整张表?

这是InnoDB为了保证事务的隔离性数据的一致性而必须采取的措施。

  • 加锁过程:在全表扫描的过程中,InnoDB为了确保它正在检查的行不会被其他事务修改(以避免不可重复读等问题),它会对自己扫描过的每一条记录,都加上X型的临键锁(Next-Key Lock)
  • 最终结果:当这个全表扫描结束后,相当于表中的每一条记录,以及记录之间的每一个间隙,都被加上了锁。从效果上看,这就等同于锁住了整张表
3. 场景分析
  • 事务A执行:UPDATE ... WHERE status < 10;

    1. 由于status列没有索引,InnoDB开始全表扫描
    2. 它从第一行开始,扫描一行,加一个临键锁;再扫描下一行,再加一个临键锁……
    3. 当事务A完成扫描并修改了满足条件的行后,它已经持有了整张表的行锁和间隙锁
  • 事务B执行:UPDATE ... WHERE status > 15;

    1. 事务B开始执行,它也需要进行全表扫描。
    2. 当它尝试去扫描并锁定第一行记录时,发现这行记录已经被事务A的锁锁住了
    3. 锁冲突发生,事务B立即进入阻塞状态,等待事务A提交或回滚。
结论与实践建议
  • 结论:当UPDATEDELETE语句的WHERE条件列没有索引时,InnoDB会从行级锁 “升级” 为事实上的 表级锁,导致严重的锁竞争和性能问题。
  • 实践建议
    • 这是我们在SQL开发中必须极力避免的情况。
    • 对于所有会出现在UPDATEDELETE语句的WHERE子句中的列,都应该建立合适的索引
    • 在上线前,对所有核心的写操作SQL,都应该使用EXPLAIN来检查其执行计划,确保type列不是ALL(全表扫描),并且key列显示它用上了正确的索引。

这个例子也从反面印证了索引对于写操作的重要性——它不仅提升查询性能,更是缩小写操作锁范围、保证高并发写入的关键。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/909809.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/909809.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

B站精品课程

【Python并发编程】线程&#xff0c;进程&#xff0c;协程&#xff0c;线程安全&#xff0c;多线程&#xff0c;死锁&#xff0c;线程池等与案例解析&#xff0c;从入门到精通 https://www.bilibili.com/video/BV1EfdcYmEff/?spm_id_from333.337.search-card.all.click&v…

# ubuntu中安装使用五笔输入法

先 清理旧输入法并重新安装 fcitx5 五笔输入法&#x1f447; &#x1f4e6; 第一步&#xff1a;清理旧的 Fcitx5 及相关输入法组件 sudo apt purge fcitx* mozc* ibus* -y sudo apt autoremove --purge -y&#x1f4dd; 说明&#xff1a; fcitx* 会清除旧版本 Fcitx/Fcitx5。…

LSM树与B+树优缺点分析

1. LSM树优化了顺序写&#xff0c;因此写性能很好&#xff0c;但在查询上&#xff1a; 需要从Level 0到Level n一直顺序查下去。极端情况是LSM树中不存在该数据&#xff0c;则需要遍历L0->Ln&#xff0c;最后返回空集。 解决方法是用布隆过滤器优化查询。 2. B树范围查询性…

【成都鱼住未来身份证】 身份证读取与解析———未来之窗行业应用跨平台架构——智能编程——仙盟创梦IDE

读取身份证开发配置 function readerid鱼住未来科技(){const webUrl http:// "127.0.0.1:30004" /api/info$.ajax({url: webUrl,type: GET,dataType: json,success: function (result) {// processContent.text(web api接口&#xff1a; webUrl 读取身份证信息…

开启并连接redis以及端口占用问题

开启命令行 redis-server.exe redis.windows.conf 端口占用问题 查看端口&#xff1a; 输入命令行&#xff1a; netstat -ano | findstr :6379 找到并停止pid号&#xff1a; 这个要用到cmd管理员身份打开 taskkill /f /pid 你的端口号 重新开启就行了 再用另一个cmd进行连…

MCP数据可视化服务器配置依赖

# requirements.txt # MCP数据可视化服务器依赖包# 核心MCP包 mcp>=0.1.0# 数据处理 pandas>=2.0.0 numpy>=1.24.0# 可视化 matplotlib>=3.7.0 seaborn>=0.12.0# 异步支持 asyncio-mqtt>=0.13.0# JSON处理 jsonschema>=4.17.0# 图像处理 Pillow>=9.5.0…

量化面试绿皮书:14. 钟表零件

文中内容仅限技术学习与代码实践参考&#xff0c;市场存在不确定性&#xff0c;技术分析需谨慎验证&#xff0c;不构成任何投资建议。 14. 钟表零件 一个时钟(顺时针编号为 1-12)从墙上掉了下来&#xff0c;摔成三块你发现每块上的数字之和是相等的。 Q: 每块上的数字是多少&…

AndroidR平台ToastPresenter引出BinderProxy泄漏

一、问题描述 针对SA8155车机系统Qnx+Android,自动化测试模拟发送CAN信号测试,压测报出多例BinderProxy leak引起system_server重启 问题1 [CRASH] system_server osVersion: V1.2.***,提交时间:2025-06-05 ***,复现了2次java.lang.AssertionError: Binder ProxyMap has…

windows11中切换到其他桌面再切回当前桌面,任务栏的WPS有好几个窗口

感谢知乎的网友 原文链接 新建一个后缀为 .reg 的文本文件&#xff0c;将以下内容粘贴进去&#xff0c;保存&#xff0c;然后双击运行 Windows Registry Editor Version 5.00[HKEY_CURRENT_USER\Software\kingsoft\Office\6.0\wpsoffice\Application Settings]"enable_m…

从汇编的角度揭开C++ this指针的神秘面纱(下)

<接上篇> 我们接着来看一段C的代码&#xff1a; class A { public:int func(int j){return j _i;} private:int _i; };int main() {A a;a.func(3);return 0; } 这里定义了一个类A&#xff0c;在main函数中定义了A类的对像a。同时用a调用了成员函数func。我们来看一…

Kafka代码模板

Kafka 服务器&#xff08;Broker&#xff09; 的配置 server.properties # broker.id: 每个 Kafka Broker 的唯一标识符。broker.id 必须在整个 Kafka 集群中唯一。 broker.id0# 配置 Kafka Broker 监听客户端请求的地址和端口。这个配置决定了 Kafka 服务将接受来自生产者、…

最大子数组和C++

给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 子数组是数组中的一个连续部分。 示例 1&#xff1a; 输入&#xff1a;nums [-2,1,-3,4,-1,2,1,-5,4] 输出&#xff1a;…

centos 7单机安装ceph并创建rbd块设备

1. 安装依赖包 新增阿里云源ceph下载地址 vim /etc/yum.repos.d/ceph.repo [ceph] nameceph baseurlhttp://mirrors.aliyun.com/ceph/rpm-jewel/el7/x86_64/ gpgcheck0 [ceph-noarch] namecephnoarch baseurlhttp://mirrors.aliyun.com/ceph/rpm-jewel/el7/noarch/ gpgcheck…

Jenkins搭建、权限管理、参数化、流水线等详细教程!

部署Jenkins 一、jenkins 安装 官网&#xff1a; https://jenkins.io yum 安装 jenkins *jenkins 依赖 java 环境 #注意2.346之后的版本不再支持jdk8 卸载旧jenkins #查询以前是否安装jenkins rpm -qa |grep jenkins #卸载 jenkins yum -y remove jenkins rpm -e jenkins…

百度飞桨(PaddlePaddle)案例分享:基于 PaddleOCR 的图像文字提取系统

一、案例背景 在实际教学、办公及政务系统中&#xff0c;纸质材料&#xff08;如手写作文、表格、试卷等&#xff09;仍广泛存在。为提升信息处理效率&#xff0c;采用 OCR&#xff08;Optical Character Recognition&#xff09;技术将图像中的文字提取为可编辑文本已成为刚需…

python操控鼠标

在已知屏幕坐标的情况下&#xff0c;可以通过 Python 的 pyautogui 或 pynput 等库实现网页上的鼠标点击操作。以下是具体步骤和代码示例&#xff1a; 1. 使用 PyAutoGUI&#xff08;推荐&#xff09; pyautogui 是一个简单易用的库&#xff0c;可以直接通过屏幕坐标控制鼠标点…

UV 与 Bun 深度解析

UV 与 Bun 深度解析&#xff1a;现代开发工具的安装与使用指南 什么是 UV&#xff1f; UV&#xff08;Ultra-Velocity&#xff09;是由 Astral 公司&#xff08;Ruff 的创建者&#xff09;开发的超高速 Python 包管理工具&#xff1a; 用 Rust 编写&#xff0c;速度极快&…

【算力网络】多样化算力感知

一、算力网络 ​ 算力网络&#xff08;Computing Power Network&#xff09;是我国率先提出的原创性技术理念&#xff0c;其核心是通过高速网络整合分散的算力资源&#xff08;如云端、边缘、终端等&#xff09;&#xff0c;实现算力的动态感知、智能调度和一体化服务&#x…

Greenplum/PostgreSQL pg_hba.conf 认证方法详解

Greenplum/PostgreSQL pg_hba.conf 认证方法详解 pg_hba.conf 文件中的 METHOD 字段指定了客户端认证方式&#xff0c;以下是各种认证方法的详细说明和配置示例。 常用认证方法 1. trust - 无条件允许连接 说明&#xff1a;不需要密码&#xff0c;完全信任连接 适用场景&am…

分布式数据库中间件-Sharding-JDBC

前言 学习视频&#xff1a;深入Sharding-JDBC分库分表从入门到精通【黑马程序员】本内容仅用于个人学习笔记&#xff0c;如有侵扰&#xff0c;联系删除 1、概述 1.1、分库分表是什么 小明是一家初创电商平台的开发人员&#xff0c;他负责卖家模块的功能开发&#xff0c;其中…