<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Java on Evorsio</title><link>https://blog.evorsio.com/categories/java/</link><description>Recent content in Java on Evorsio</description><generator>Hugo -- gohugo.io</generator><language>zh</language><lastBuildDate>Tue, 28 Apr 2026 19:24:00 +1200</lastBuildDate><atom:link href="https://blog.evorsio.com/categories/java/index.xml" rel="self" type="application/rss+xml"/><item><title>Z 垃圾收集器 (ZGC)</title><link>https://blog.evorsio.com/p/z-garbage-collector/</link><pubDate>Tue, 28 Apr 2026 19:24:00 +1200</pubDate><guid>https://blog.evorsio.com/p/z-garbage-collector/</guid><description>&lt;h1 id="z-垃圾收集器-zgc"&gt;Z 垃圾收集器 (ZGC)
&lt;/h1&gt;&lt;h2 id="动机"&gt;动机
&lt;/h2&gt;&lt;p&gt;ZGC（JEP 333）被设计用于低延迟和高可扩展性，并自 JDK 15（JEP 377）起已可用于生产环境。&lt;/p&gt;
&lt;p&gt;ZGC 的大部分工作是在应用线程运行时完成的，只会短暂地暂停这些线程。ZGC 的停顿时间通常以微秒计；相比之下，默认垃圾收集器 G1 的停顿时间范围从毫秒到秒级不等。ZGC 的低停顿时间与堆大小无关：工作负载可以使用从几百 MB 到数 TB 的堆大小，并仍然保持低停顿时间。&lt;/p&gt;
&lt;p&gt;对于许多工作负载而言，仅使用 ZGC 就足以解决所有与垃圾回收相关的延迟问题。这在具备足够资源（即内存和 CPU），以确保 ZGC 回收内存的速度快于并发运行的应用线程消耗内存的速度时效果良好。然而，ZGC 当前会将所有对象统一存储，不区分年龄，因此每次运行时都必须对所有对象进行回收。&lt;/p&gt;
&lt;p&gt;弱分代假说（weak generational hypothesis）指出：年轻对象往往很快死亡，而老对象则会长期存活。因此，回收年轻对象所需资源更少且能回收更多内存，而回收老对象则需要更多资源且回收的内存较少。因此，通过更频繁地回收年轻对象，可以提升使用 ZGC 的应用性能。&lt;/p&gt;
&lt;h2 id="描述"&gt;描述
&lt;/h2&gt;&lt;h3 id="启用分代-zgc"&gt;启用分代 ZGC
&lt;/h3&gt;&lt;p&gt;为了确保平稳过渡，我们最初将使分代 ZGC 与非分代 ZGC 并存。命令行选项 &lt;code&gt;-XX:+UseZGC&lt;/code&gt; 将选择非分代 ZGC；要选择分代 ZGC，需要额外添加 &lt;code&gt;-XX:+ZGenerational&lt;/code&gt; 选项：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-plain" data-lang="plain"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ java -XX:+UseZGC -XX:+ZGenerational ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;在未来的某个版本中，我们计划将分代 ZGC 设为默认值，此时 &lt;code&gt;-XX:-ZGenerational&lt;/code&gt; 将用于选择非分代 ZGC。在更晚的版本中，我们计划移除非分代 ZGC，此时 &lt;code&gt;ZGenerational&lt;/code&gt; 选项将被废弃。&lt;/p&gt;
&lt;h3 id="设计"&gt;设计
&lt;/h3&gt;&lt;p&gt;分代 ZGC 将堆划分为两个逻辑分代：年轻代用于存放新分配的对象，而老年代用于存放长期存活的对象。每个分代都独立于另一个分代进行回收，因此 ZGC 可以专注于回收更“高收益”的年轻对象。&lt;/p&gt;
&lt;p&gt;与非分代 ZGC 一样，所有垃圾回收都在应用程序运行的同时并发执行，并且应用程序的停顿时间通常小于一毫秒。由于 ZGC 在应用运行的同时读取和修改对象图，因此必须确保应用程序始终看到一致的对象图视图。ZGC 通过染色指针（colored pointers）、读屏障（load barriers）和写屏障（store barriers）来实现这一点。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;染色指针（colored pointer）&lt;/strong&gt; 是一种指向堆中对象的指针，它在包含对象内存地址的同时，还携带用于编码对象已知状态的元数据。这些元数据描述了对象是否已知存活、地址是否正确等信息。ZGC 始终使用 64 位对象指针，因此可以为多 TB 的堆提供足够的元数据位和地址空间。当对象字段引用另一个对象时，ZGC 使用染色指针来实现该引用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;读屏障（load barrier）&lt;/strong&gt; 是 ZGC 注入到应用程序中的一段代码，用于在应用读取对象字段（该字段引用另一个对象）时执行。读屏障会解析存储在染色指针中的元数据，并在应用使用该引用对象之前可能执行一些操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;非分代 ZGC 同时使用染色指针和读屏障。分代 ZGC 还额外使用写屏障，以高效地跟踪不同分代之间的引用。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;写屏障（store barrier）&lt;/strong&gt; 是 ZGC 注入到应用程序中的一段代码，用于在应用向对象字段写入引用时执行。分代 ZGC 在染色指针中增加了新的元数据位，使写屏障能够判断该字段是否已经被记录为可能包含跨分代引用。染色指针使得分代 ZGC 的写屏障比传统分代写屏障更高效。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;写屏障的引入，使分代 ZGC 可以将“可达对象标记”的工作从读屏障转移到写屏障中。也就是说，写屏障可以利用染色指针中的元数据位，高效判断在写入前该字段所引用的对象是否需要被标记。&lt;/p&gt;
&lt;p&gt;将标记（marking）从读屏障中移出，使得对其进行优化变得更容易，这一点非常重要，因为读屏障通常比写屏障执行得更频繁。现在，当读屏障解释一个染色指针时，如果对象已被搬迁，它只需要更新对象地址，并更新元数据以表示该地址已被确认正确。后续的读屏障会根据这些元数据进行判断，不再重复检查该对象是否已被搬迁。&lt;/p&gt;
&lt;p&gt;分代 ZGC 在染色指针中使用不同的标记与搬迁（relocation）元数据位集合，从而使各个分代可以独立进行回收。&lt;/p&gt;
&lt;p&gt;接下来的章节描述了区分分代 ZGC 与非分代 ZGC，以及与其他垃圾收集器的关键设计概念：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;无多重内存映射（No multi-mapped memory）&lt;/li&gt;
&lt;li&gt;优化的屏障（Optimized barriers）&lt;/li&gt;
&lt;li&gt;双缓冲记忆集（Double-buffered remembered sets）&lt;/li&gt;
&lt;li&gt;无需额外堆内存的对象搬迁（Relocations without additional heap memory）&lt;/li&gt;
&lt;li&gt;紧凑堆区域（Dense heap regions）&lt;/li&gt;
&lt;li&gt;大对象（Large objects）&lt;/li&gt;
&lt;li&gt;完整垃圾回收（Full garbage collections）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="多重映射内存multi-mapped-memory"&gt;多重映射内存（multi-mapped memory）
&lt;/h3&gt;&lt;p&gt;非分代 ZGC 使用多重映射内存（multi-mapped memory）来降低读屏障的开销。而分代 ZGC 则改为在读屏障和写屏障中使用显式代码实现。&lt;/p&gt;
&lt;p&gt;对于用户而言，这一变化的主要优势在于：更容易衡量堆所使用的内存量。在多重映射情况下，同一段堆内存会被映射到三个独立的虚拟地址范围中，因此像 &lt;code&gt;ps&lt;/code&gt; 这样的工具报告的堆内存使用量大约是实际使用量的三倍。&lt;/p&gt;
&lt;p&gt;对于 GC 本身而言，这一变化意味着染色指针中的元数据位不再需要位于与堆可访问地址范围对应的指针部分。这使得可以增加更多元数据位，并且也为将最大堆大小从非分代 ZGC 的 16TB 限制进一步提升提供了可能性。&lt;/p&gt;
&lt;p&gt;在分代 ZGC 中，存储在对象字段中的对象引用以染色指针形式实现。而存储在 JVM 栈中的对象引用则以“无色指针”（colorless pointers）形式实现，即不包含元数据位，存在于硬件栈或 CPU 寄存器中。读屏障和写屏障负责在染色指针与无色指针之间进行相互转换。&lt;/p&gt;
&lt;p&gt;由于在硬件栈或 CPU 寄存器中不会出现染色指针，因此可以采用更特殊的染色指针布局，只要染色指针与无色指针之间的转换足够高效即可。分代 ZGC 使用的染色指针布局将元数据放在指针的低位，而对象地址放在高位。这样可以最大程度减少读屏障中的机器指令数量。在 x64 架构上，通过精心设计的编码方式，一个移位指令即可同时完成“判断是否需要处理该指针”以及“移除元数据位”的操作。&lt;/p&gt;
&lt;h3 id="优化屏障optimized-barriers"&gt;优化屏障（Optimized barriers）
&lt;/h3&gt;&lt;p&gt;随着写屏障（store barriers）的引入，以及读屏障（load barriers）新增的职责，更多 GC 代码将与编译后的应用代码交织在一起。为了最大化吞吐量，这些屏障需要被高度优化。分代 ZGC 的许多关键设计决策都涉及染色指针（colored pointer）方案和屏障机制。&lt;/p&gt;
&lt;p&gt;用于优化屏障的一些技术包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;快速路径与慢速路径&lt;/li&gt;
&lt;li&gt;最小化读屏障职责&lt;/li&gt;
&lt;li&gt;记忆集屏障（remembered-set barriers）&lt;/li&gt;
&lt;li&gt;SATB 标记屏障（SATB marking barriers）&lt;/li&gt;
&lt;li&gt;融合写屏障检查（fused store barrier checks）&lt;/li&gt;
&lt;li&gt;写屏障缓冲区（store barrier buffers）&lt;/li&gt;
&lt;li&gt;屏障补丁（barrier patching）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="快速路径与慢速路径"&gt;快速路径与慢速路径
&lt;/h4&gt;&lt;p&gt;ZGC 将屏障拆分为两部分。快速路径检查在应用程序使用引用对象之前是否需要执行额外的 GC 工作。慢速路径执行这些额外工作。所有对象访问都会执行快速路径检查。由于必须非常快，这部分代码会直接插入到即时编译（JIT）后的应用程序代码中。慢速路径只在少数情况下执行。当进入慢速路径时，被访问对象指针的颜色会被修改，使得后续对同一指针的访问在一段时间内不会再次触发慢速路径。因此，慢速路径不需要高度优化，为了可维护性，它们以 JVM 中的 C++ 函数形式实现。&lt;/p&gt;
&lt;p&gt;在非分代 ZGC 中，这是读屏障（load barriers）的拆分方式。在分代 ZGC 中，同样的机制也应用于写屏障（store barriers）及其相关的 GC 工作。&lt;/p&gt;
&lt;h4 id="最小化读屏障load-barrier职责"&gt;最小化读屏障（load barrier）职责
&lt;/h4&gt;&lt;p&gt;在非分代 ZGC 中，读屏障负责：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;更新 GC 已搬迁对象的过期引用&lt;/li&gt;
&lt;li&gt;将加载的对象标记为存活（因为应用正在访问该对象，因此认为其存活）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在分代 ZGC 中，需要同时跟踪两个分代，并在染色指针（colored pointer）与无色指针之间进行转换。为了降低复杂度，并优化读屏障的快速路径，将标记职责从读屏障转移到写屏障。&lt;/p&gt;
&lt;p&gt;在分代 ZGC 中，读屏障负责：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;移除染色指针（colored pointer）中的元数据位&lt;/li&gt;
&lt;li&gt;更新 GC 已搬迁对象的过期引用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;写屏障（store barrier）负责：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;向指针添加元数据位以生成染色指针（colored pointer）&lt;/li&gt;
&lt;li&gt;维护记忆集（remembered set），用于跟踪老年代到年轻代的引用&lt;/li&gt;
&lt;li&gt;将对象标记为存活&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="记忆集屏障remembered-set-barriers"&gt;记忆集屏障（remembered-set barriers）
&lt;/h4&gt;&lt;p&gt;当分代 ZGC 回收年轻代时，只会访问年轻代中的对象。但老年代中的对象可能包含指向年轻代对象的引用，这些引用在回收过程中必须被处理，原因有两个：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GC 标记根（GC marking roots）：这些引用可能是使年轻代对象仍然可达的唯一路径，因此必须作为对象图的根来处理，以确保所有存活对象都能被标记&lt;/li&gt;
&lt;li&gt;过期引用：在回收年轻代时，对象会被移动，但老年代中的引用不会立即更新，而是在应用访问时由读屏障惰性更新。如果应用未访问这些引用，GC 需要在后续阶段统一修复这些过期引用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;老年代到年轻代的引用集合称为记忆集（remembered set）。记忆集包含所有位于老年代中的内存地址，这些地址可能包含指向年轻代对象的引用。写屏障（store barrier）会向记忆集添加条目。当一个引用被写入对象字段时，该字段被认为可能包含老年代到年轻代的引用。写屏障的慢速路径会过滤掉对年轻代字段的写入，因为只有老年代中的地址是需要关注的。慢速路径不会根据写入的值进行过滤，该值可能指向年轻代或老年代对象。垃圾收集器在使用记忆集时，会检查对象字段的当前值。&lt;/p&gt;
&lt;p&gt;这一切保证了写屏障（store barrier）在维护记忆集时具有“只执行一次”的特性。这意味着，在两个连续的年轻代标记阶段之间，每个被写入的对象字段，写屏障慢速路径只会执行一次。当某个字段第一次被写入时，会发生以下步骤：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;快速路径检查即将被覆盖的字段原值&lt;/li&gt;
&lt;li&gt;颜色信息表明该字段在上一次年轻代标记阶段之后未被写入&lt;/li&gt;
&lt;li&gt;进入慢速路径&lt;/li&gt;
&lt;li&gt;将该字段地址加入记忆集（remembered set）&lt;/li&gt;
&lt;li&gt;将新的指针值染色后写入字段&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;新的指针值会被染色，使后续快速路径检查能够识别该字段已经执行过慢速路径处理。&lt;/p&gt;
&lt;h4 id="satb-标记屏障satb-marking-barriers"&gt;SATB 标记屏障（SATB marking barriers）
&lt;/h4&gt;&lt;p&gt;与非分代 ZGC 不同，分代 ZGC 使用起始快照（SATB，snapshot-at-the-beginning）标记算法。在标记阶段开始时，垃圾收集器会对 GC 根（GC roots）进行快照；在标记阶段结束时，所有在标记开始时从这些根可达的对象都能被保证找到并标记为存活。&lt;/p&gt;
&lt;p&gt;为实现这一点，当对象图中的引用关系被破坏时，垃圾收集器必须能够获知。因此，写屏障（store barrier）会将即将被覆盖的字段值上报给垃圾收集器；垃圾收集器随后会标记该引用对象，并继续访问并标记从该对象可达的其他对象。&lt;/p&gt;
&lt;p&gt;在一次标记周期内，写屏障只需要在某个字段第一次被写入时，上报该字段即将被覆盖的值。对同一字段的后续写入，只是替换一个垃圾收集器已经保证能够找到的值，因为 SATB 特性保证了这些对象在本次标记中已经被处理或会被处理。SATB 特性进一步支持了写屏障在标记语义上的“只执行一次”性质。&lt;/p&gt;
&lt;h4 id="融合写屏障检查fused-store-barrier-checks"&gt;融合写屏障检查（fused store barrier checks）
&lt;/h4&gt;&lt;p&gt;写屏障的记忆集维护和标记功能存在很多相似之处，它们都使用染色指针（colored pointer）的快速路径检查，并且都具有各自的“只执行一次”特性。因此，不再为每种条件设置独立的快速路径检查，而是将它们融合为一个统一的快速路径检查。如果任意一个条件不满足，就会进入慢速路径，并执行所需的 GC 工作。&lt;/p&gt;
&lt;h4 id="写屏障缓冲区store-barrier-buffers"&gt;写屏障缓冲区（store barrier buffers）
&lt;/h4&gt;&lt;p&gt;将屏障拆分为快速路径与慢速路径，并结合指针染色，可以减少对 C++ 慢速路径函数的调用次数。分代 ZGC 通过在快速路径与慢速路径之间引入一个由 JIT 编译的中间路径来进一步降低开销。该中间路径会将即将被覆盖的字段值以及对象字段地址存入写屏障缓冲区，然后直接返回到应用代码，而不会进入代价较高的慢速路径。只有当写屏障缓冲区被填满时，才会触发慢速路径。这种方式将从编译代码切换到 C++ 慢速路径的开销进行了摊销。&lt;/p&gt;
&lt;h4 id="屏障补丁barrier-patching"&gt;屏障补丁（barrier patching）
&lt;/h4&gt;&lt;p&gt;读屏障（load barrier）和写屏障（store barrier）在执行检查时，会访问垃圾收集器在不同阶段切换时更新的全局变量或线程本地变量。不同 CPU 架构在访问这些变量时的开销不同。&lt;/p&gt;
&lt;p&gt;在分代 ZGC 中，通过在可能的情况下对屏障代码进行补丁优化来降低这部分开销。全局状态值会被编码到屏障的机器指令中作为立即数，而不再需要通过访问全局变量或线程本地变量来获取当前状态。当垃圾收集器切换阶段时（例如开始年轻代标记阶段），相关方法首次执行时会对这些立即数进行更新。这进一步降低了屏障的运行开销。&lt;/p&gt;
&lt;h3 id="双缓冲记忆集double-buffered-remembered-sets"&gt;双缓冲记忆集（double-buffered remembered sets）
&lt;/h3&gt;&lt;p&gt;许多垃圾收集器使用一种称为卡表标记（card table marking）的记忆集技术来跟踪分代间引用。当应用线程写入对象字段时，也会同时将卡表（card table）中的某个字节标记为“脏”（dirty）。通常，卡表中一个字节对应堆中约 512 字节的地址范围。为了找到所有老年代到年轻代的引用，垃圾收集器必须定位并访问所有属于这些“脏字节”对应地址范围内的对象字段。&lt;/p&gt;
&lt;p&gt;相比之下，分代 ZGC 使用位图（bitmap）来精确记录对象字段位置，其中每一位表示一个可能的对象字段地址。每个老年代区域都有一对记忆集位图（remembered-set bitmaps）。其中一个位图由应用线程通过写屏障（store barrier）进行写入并保持活跃，另一个位图则作为垃圾收集器的只读副本，保存当前所有可能指向年轻代的老年代引用。这两个位图会在每次年轻代收集开始时进行原子交换。该机制的一个好处是应用线程不需要等待位图被清空。垃圾收集器可以在处理并清空一个位图的同时，另一个位图继续被应用线程并发写入。另一个好处是由于应用线程和 GC 线程操作不同位图，因此减少了它们之间对额外内存屏障（memory barrier）的需求。其他使用卡表标记的分代收集器（如 G1）在标记卡表时需要执行内存屏障，这可能导致写屏障性能更差。&lt;/p&gt;
&lt;h3 id="无需额外堆内存的对象迁移relocations-without-additional-heap-memory"&gt;无需额外堆内存的对象迁移（relocations without additional heap memory）
&lt;/h3&gt;&lt;p&gt;其他 HotSpot 垃圾收集器中的年轻代收集通常使用“转移式回收（scavenging）”模型：在一次遍历中找到并移动存活对象。在垃圾收集器完全知道哪些对象存活之前，年轻代中的所有对象都必须被处理完成。这类收集器只能在所有对象迁移完成后才能回收内存。因此，它们需要预估存活对象所需的内存量，并确保在 GC 开始时有足够空间。如果估算错误，就需要更昂贵的回收方式，例如对未迁移对象进行原地固定（pinning）导致碎片化，或暂停所有应用线程执行全堆 Full GC。&lt;/p&gt;
&lt;p&gt;分代 ZGC 使用两次遍历：第一次遍历用于访问并标记所有可达对象，第二次遍历用于迁移已标记对象。由于在迁移阶段开始之前 GC 已经拥有完整的存活信息，它可以按区域（region）粒度分配迁移工作。一旦某个区域内的所有存活对象都被迁移出去，该区域就被认为已完成回收，可以重新作为迁移目标区域或用于应用线程分配内存。即使没有新的空闲区域可用，ZGC 仍然可以通过将对象压缩到正在迁移的区域中继续执行。这使得分代 ZGC 可以在不依赖额外堆内存的情况下完成年轻代的迁移和压缩。&lt;/p&gt;
&lt;h3 id="密集堆区域dense-heap-regions"&gt;密集堆区域（dense heap regions）
&lt;/h3&gt;&lt;p&gt;当从年轻代迁移对象时，不同区域中的存活对象数量及其占用内存会存在差异。例如，最近分配的区域通常包含更多存活对象。&lt;/p&gt;
&lt;p&gt;ZGC 会分析年轻代区域的密度（density），以决定哪些区域值得回收，哪些区域过于“满”或回收成本过高。未被选择回收的区域会被原地晋升：其中的对象保持在原位置不移动，这些区域要么继续保留在年轻代作为幸存者区域（survivor regions），要么被晋升到老年代。这些幸存区域中的对象会获得“第二次死亡机会”，希望在下一次年轻代回收开始时，其中更多对象已经死亡，从而使更多区域可以被回收。&lt;/p&gt;
&lt;p&gt;这种对高密度区域进行原地老化（aging）的方式，可以降低年轻代回收的整体开销。&lt;/p&gt;
&lt;h3 id="大对象large-objects"&gt;大对象（large objects）
&lt;/h3&gt;&lt;p&gt;ZGC 已经能够很好地处理大对象。通过将虚拟内存与物理内存解耦，并预留大量虚拟地址空间，ZGC 通常可以避免 G1 中可能导致大对象分配困难的碎片问题。&lt;/p&gt;
&lt;p&gt;在分代 ZGC 中，这一点进一步增强：允许大对象直接在年轻代中分配。由于区域可以在不移动对象的情况下被老化，因此没有必要为了避免昂贵的迁移而将大对象强制分配到老年代。相反，如果大对象生命周期较短，可以在年轻代中直接回收；如果生命周期较长，也可以低成本地晋升到老年代。&lt;/p&gt;
&lt;h3 id="全垃圾收集full-garbage-collections"&gt;全垃圾收集（full garbage collections）
&lt;/h3&gt;&lt;p&gt;当回收老年代时，年轻代中的对象可能会引用老年代中的对象，这些引用被视为老年代对象图的根。由于年轻代对象变化频繁，不对年轻代到老年代的引用进行持续跟踪。相反，这些引用通过在老年代标记阶段同时执行一次年轻代回收来发现。当年轻代回收发现指向老年代的引用时，会将其传递给老年代标记过程。&lt;/p&gt;
&lt;p&gt;这次额外的年轻代回收仍然作为一次正常的年轻代回收执行，并会将存活对象保留在幸存区域中。这会带来一个影响：年轻代中的幸存对象不会参与老年代回收阶段中的引用处理和类卸载。因此，可能会出现这样的情况：应用释放了对象图的最后引用，调用系统级垃圾回收，然后期望某些弱引用被清除或入队，或者某些类被卸载，但实际上并没有立即发生。&lt;/p&gt;
&lt;p&gt;为了缓解这个问题，当应用显式触发垃圾回收时，会在老年代回收开始之前先执行一次额外的年轻代回收，将所有存活对象提前晋升到老年代。&lt;/p&gt;
&lt;h2 id="替代方案"&gt;替代方案
&lt;/h2&gt;&lt;h3 id="更简单的屏障与指针染色方案"&gt;更简单的屏障与指针染色方案
&lt;/h3&gt;&lt;p&gt;当前的读屏障（load barrier）和写屏障（store barrier）实现并不容易理解。一个更简单的版本可能更易维护，但代价是更高的读写屏障开销。我们评估了大约十种不同的屏障实现方式，但没有一种在性能上优于当前基于移位操作的读屏障设计。未来仍然值得继续研究并分析这种“性能与复杂度”之间的权衡。&lt;/p&gt;
&lt;h3 id="继续使用多重映射内存multi-mapped-memory"&gt;继续使用多重映射内存（multi-mapped memory）
&lt;/h3&gt;&lt;p&gt;可以通过继续使用多重映射内存（multi-mapped memory）来避免颜色指针中“无色根”的设计，从而采用更简单的实现方案。如果相比非分代 ZGC 需要更多的指针元数据位，那么最大堆大小将受到限制。另一种方式是采用混合方案：部分元数据位通过多重映射内存实现，另一部分则由读写屏障进行移除和添加。&lt;/p&gt;
&lt;h3 id="测试"&gt;测试
&lt;/h3&gt;&lt;p&gt;ZGC 实现中为无色指针（colorless pointer）和染色指针（colored pointer）使用了不同的 C++ 类型，从而保证两者之间不会发生隐式转换。染色指针仅限于 GC 代码和屏障使用。只要运行时系统通过 HotSpot 的访问接口和屏障来访问对象指针，它就只会看到可解引用的无色指针。运行时可见的对象指针类型始终是无色指针。我们在不同的对象指针类型中注入了大量验证代码，以便快速发现指针损坏或屏障缺失的问题。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;标准垃圾收集算法测试集将用于验证正确性。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="风险与假设"&gt;风险与假设
&lt;/h2&gt;&lt;h3 id="实现复杂度"&gt;实现复杂度
&lt;/h3&gt;&lt;p&gt;分代 ZGC（Generational ZGC）中的屏障和染色指针（colored pointer）比非分代 ZGC 更复杂。分代 ZGC 还会并发运行两个垃圾收集器；这两个收集器相对独立，但在一些复杂机制上仍然会相互交互，从而增加实现复杂度。&lt;/p&gt;
&lt;p&gt;由于额外的复杂性，从长期来看，我们计划通过完全用分代 ZGC 替代原有的非分代 ZGC，从而降低维护成本。&lt;/p&gt;
&lt;h3 id="分代-zgc-与非分代-zgc-的性能差异"&gt;分代 ZGC 与非分代 ZGC 的性能差异
&lt;/h3&gt;&lt;p&gt;我们认为分代 ZGC（Generational ZGC）比其前身更适合大多数使用场景。一些工作负载甚至可能由于资源使用更低而获得吞吐量提升。例如，在 Apache Cassandra 基准测试中，分代 ZGC 只需要四分之一的堆大小，却能达到四倍吞吐量，同时仍将停顿时间控制在 1 毫秒以内。&lt;/p&gt;
&lt;p&gt;某些本质上是非分代特性的工作负载可能会出现轻微性能下降。我们认为这类工作负载的比例足够小，不足以支撑长期维护两套独立 ZGC 实现的成本。&lt;/p&gt;
&lt;p&gt;另一个潜在开销来源是更复杂的 GC 屏障（GC barriers）。我们预计这部分开销大多会被避免频繁回收老年代对象所带来的收益抵消。&lt;/p&gt;
&lt;p&gt;另一个开销来源是同时运行两个垃圾收集器。需要合理平衡它们的触发频率和 CPU 使用，以避免对应用造成过度影响。&lt;/p&gt;
&lt;p&gt;与 GC 开发的常规情况一样，未来的改进和优化将由基准测试和用户反馈驱动。我们计划在首次发布之后仍持续改进分代 ZGC。&lt;/p&gt;</description></item><item><title>Garbage-First（G1）垃圾收集器</title><link>https://blog.evorsio.com/p/garbage-first-garbage-collector/</link><pubDate>Tue, 28 Apr 2026 18:24:00 +1200</pubDate><guid>https://blog.evorsio.com/p/garbage-first-garbage-collector/</guid><description>&lt;h1 id="garbage-firstg1垃圾收集器"&gt;Garbage-First（G1）垃圾收集器
&lt;/h1&gt;&lt;h2 id="简介"&gt;简介
&lt;/h2&gt;&lt;p&gt;Garbage-First（G1）垃圾收集器面向多处理器机器设计，可扩展到大容量内存。它力图在高概率下满足垃圾回收的停顿时间目标，同时在几乎无需配置的情况下实现高吞吐量。G1 旨在在当前目标应用和环境中，在延迟与吞吐量之间提供最佳平衡，这些应用和环境具有以下特征：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;堆大小可达数十 GB 或更大，且 Java 堆中超过 50% 被存活数据占用。&lt;/li&gt;
&lt;li&gt;对象分配和晋升（promotion）的速率会随时间显著变化。&lt;/li&gt;
&lt;li&gt;堆中存在大量内存碎片。&lt;/li&gt;
&lt;li&gt;需要可预测的停顿时间目标，且停顿时间不超过几百毫秒，从而避免长时间的垃圾回收暂停。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;G1 在应用程序运行的同时执行部分工作。它通过占用本可供应用程序使用的处理器资源，来换取更短的回收停顿时间。&lt;/p&gt;
&lt;p&gt;这一点最明显地体现在：当应用程序运行时，会有一个或多个垃圾回收线程同时处于活跃状态。因此，与以吞吐量为优先的收集器相比，虽然 G1 的垃圾回收停顿通常更短，但应用程序的整体吞吐量也往往会略有降低。&lt;/p&gt;
&lt;p&gt;G1 是默认的垃圾收集器。&lt;/p&gt;
&lt;p&gt;G1 收集器通过多种方式实现高性能，并尝试满足停顿时间目标，这些方式将在后续章节中进行说明。&lt;/p&gt;
&lt;h2 id="启用-g1"&gt;启用 G1
&lt;/h2&gt;&lt;p&gt;Garbage-First 垃圾收集器是默认收集器，因此通常不需要进行任何额外操作。你可以通过在命令行中添加 &lt;code&gt;-XX:+UseG1GC&lt;/code&gt; 来显式启用它。&lt;/p&gt;
&lt;h2 id="基本概念"&gt;基本概念
&lt;/h2&gt;&lt;p&gt;G1 是一种分代的、增量式的、并行的、主要是并发的、会产生 Stop-The-World（STW）暂停的、并通过回收（evacuating）方式工作的垃圾收集器，它会在每次 STW 暂停中监控暂停时间目标。与其他收集器类似，G1 将堆划分为（虚拟的）新生代和老年代。空间回收主要集中在新生代，因为在该区域进行回收效率最高，同时也会偶尔在老年代进行空间回收。&lt;/p&gt;
&lt;p&gt;某些操作始终在 Stop-The-World 暂停中执行，以提升吞吐量。而一些在应用程序停止时会耗时较长的操作，例如整个堆级别的操作（如全局标记），则会与应用程序并行、并发执行。为了在空间回收过程中保持较短的 STW 暂停，G1 以增量方式、分步骤并行地执行空间回收。G1 通过跟踪之前应用行为和垃圾回收暂停的信息来建立成本模型，从而实现可预测性，并使用这些信息来决定每次暂停中执行的工作量。例如，G1 会优先回收最有效率的区域（即主要充满垃圾的区域，因此得名 Garbage-First）。&lt;/p&gt;
&lt;p&gt;G1 主要通过“疏散（evacuation）”来回收空间：将选定内存区域中的存活对象复制到新的内存区域中，并在此过程中对其进行压缩。在疏散完成后，原先被存活对象占用的空间会被应用程序重新用于分配。&lt;/p&gt;
&lt;p&gt;Garbage-First 收集器不是实时收集器。它试图在较长时间范围内以较高概率满足设定的暂停时间目标，但对于单次暂停来说，并不能保证绝对确定地满足该目标。&lt;/p&gt;
&lt;h3 id="堆布局"&gt;堆布局
&lt;/h3&gt;&lt;p&gt;G1 将堆划分为一组大小相等的堆区域（heap regions），每个区域都是一段连续的虚拟内存范围，如图 7-1 所示。区域是内存分配和内存回收的基本单位。在任何给定时刻，这些区域可以是空的（浅灰色），或者被分配给某个特定的分代：新生代或老年代。当有内存请求到来时，内存管理器会分配空闲区域，并将其分配给某个分代，然后将其作为可用空间返回给应用程序，供其进行分配。&lt;/p&gt;
&lt;p&gt;&lt;img alt="G1 垃圾收集器堆布局" class="gallery-image" data-flex-basis="333px" data-flex-grow="139" height="341" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.evorsio.com/p/garbage-first-garbage-collector/grbgcltncyl.png" width="474"&gt;&lt;/p&gt;
&lt;p&gt;新生代包含 Eden 区域（红色）和 Survivor 区域（带 “S” 的红色）。这些区域的功能与其他收集器中的对应连续空间相同，但不同之处在于，在 G1 中这些区域在内存中通常以非连续的方式分布。老年代区域（浅蓝色）构成老年代。对于跨越多个区域的对象，老年代区域可能是巨型对象（humongous）（带 “H”的浅蓝色）。&lt;/p&gt;
&lt;p&gt;应用程序始终在新生代中进行分配，也就是 Eden 区域中进行分配，但“巨型对象”除外，这类对象会直接在老年代中分配。&lt;/p&gt;
&lt;h3 id="垃圾收集周期"&gt;垃圾收集周期
&lt;/h3&gt;&lt;p&gt;从高层次来看，G1 收集器在两个阶段之间交替运行。仅年轻代阶段（young-only phase）包含垃圾回收操作，这些操作会逐步将当前可用内存填充为老年代中的对象。空间回收阶段（space-reclamation phase）则是在处理年轻代的同时，逐步回收老年代中的空间。随后，该周期会再次从仅年轻代阶段开始。&lt;/p&gt;
&lt;p&gt;&lt;img alt="垃圾收集周期概览" class="gallery-image" data-flex-basis="357px" data-flex-grow="149" height="300" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.evorsio.com/p/garbage-first-garbage-collector/jgrbg_frst_hp.png" width="447"&gt;&lt;/p&gt;
&lt;p&gt;以下列表详细描述了 G1 垃圾收集周期的各个阶段、它们的停顿以及阶段之间的转换过程：&lt;/p&gt;
&lt;h4 id="仅年轻代阶段young-only-phase"&gt;&lt;strong&gt;仅年轻代阶段（Young-only phase）&lt;/strong&gt;
&lt;/h4&gt;&lt;p&gt;该阶段从若干次“普通年轻代收集（Normal young collections）”开始，这些收集会将对象逐步晋升到老年代。当老年代的占用率达到某个阈值（即“堆占用触发阈值 / Initiating Heap Occupancy threshold”）时，系统会从该阶段过渡到空间回收阶段（space-reclamation phase）。此时，G1 会调度一次“并发开始收集（Concurrent Start young collection）”，而不是普通的年轻代收集。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Concurrent Start（并发开始）&lt;/strong&gt;：
这种收集在执行普通年轻代收集的同时，还会启动标记（marking）过程。并发标记用于确定老年代区域中当前所有可达（存活）的对象，这些对象将在后续的空间回收阶段中被保留。
在标记尚未完全结束时，仍然可能发生普通的年轻代收集。标记最终通过两个特殊的 Stop-The-World（STW）停顿完成：Remark 和 Cleanup。&lt;/p&gt;
&lt;p&gt;Concurrent Start 停顿也可能判断不需要继续进行标记：在这种情况下，会发生一个简短的并发标记撤销（undo）阶段，然后继续仅年轻代阶段。在这种情况下，不会发生 Remark 和 Cleanup 停顿。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Remark（重新标记）&lt;/strong&gt;：
该停顿用于最终完成标记本身，并执行引用处理和类卸载，回收完全空的区域，并清理内部数据结构。在 Remark 和 Cleanup 之间，G1 会计算后续在并发过程中回收选定老年代区域空间所需的信息，这些工作将在 Cleanup 阶段最终完成。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cleanup（清理）&lt;/strong&gt;：
该停顿用于判断是否真的进入空间回收阶段。如果进入空间回收阶段，则仅年轻代阶段会以一次“准备混合收集（Prepare Mixed young collection）”结束。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="空间回收阶段space-reclamation-phase"&gt;&lt;strong&gt;空间回收阶段（Space-reclamation phase）&lt;/strong&gt;
&lt;/h4&gt;&lt;p&gt;该阶段由多次年轻代收集组成，这些收集除了处理年轻代区域外，还会回收部分老年代区域中的存活对象。这些收集也称为“混合收集（Mixed collections）”。当 G1 判断继续回收更多老年代区域所带来的收益不足以抵消成本时，空间回收阶段结束。&lt;/p&gt;
&lt;p&gt;在空间回收结束后，整个收集周期会重新回到新的仅年轻代阶段作为开始。&lt;/p&gt;
&lt;p&gt;作为备用机制，如果在收集存活信息的过程中应用程序耗尽内存，G1 会像其他收集器一样执行一次原地的 Stop-The-World 全堆压缩（Full GC）。&lt;/p&gt;
&lt;h3 id="垃圾收集停顿与收集集合collection-set"&gt;垃圾收集停顿与收集集合（Collection Set）
&lt;/h3&gt;&lt;p&gt;G1 在 Stop-The-World（STW）停顿中执行垃圾收集和空间回收操作。存活对象通常会从源区域复制到堆中的一个或多个目标区域，同时对这些被移动对象的引用进行调整。&lt;/p&gt;
&lt;p&gt;对于非巨型（non-humongous）区域，一个对象的目标区域是根据该对象所在的源区域来确定的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;新生代（年轻代）的对象（eden 和 survivor 区域中的对象）会根据其年龄被复制到 survivor 区域或老年代区域。&lt;/li&gt;
&lt;li&gt;来自老年代区域的对象会被复制到其他老年代区域。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;位于巨型（humongous）区域中的对象则以不同方式处理。G1 只会判断这些对象是否存活，如果不存活，则回收其占用的空间。G1 只有在非常慢的“最后手段”收集过程中才会移动巨型对象。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Remembered Set（记忆集）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;为了对收集集合（collection set）中的区域进行疏散（evacuation），G1 维护了一个记忆集（remembered set）：它记录了堆中&lt;strong&gt;位于收集集合之外、但包含指向收集集合内部引用的位置集合&lt;/strong&gt;。当垃圾回收期间收集集合中的对象被移动时，所有来自收集集合外部、指向该对象的引用都必须被更新为指向对象的新位置。&lt;/p&gt;
&lt;p&gt;记忆集条目使用近似位置来节省内存：通常来说，彼此接近的引用往往指向彼此接近的对象。G1 在逻辑上将堆划分为卡片（card），默认大小为 512 字节。记忆集条目是这些卡片索引的压缩表示。&lt;/p&gt;
&lt;p&gt;G1 最初以“按区域（per-region）”的方式管理记忆集：每个区域都包含一个本地区域的记忆集，即可能包含指向该区域引用的位置集合。在垃圾回收期间，会基于这些区域记忆集生成整个收集集合的记忆集。&lt;/p&gt;
&lt;p&gt;记忆集主要是延迟创建的：在 Remark 与 Cleanup 停顿之间，G1 会为所有收集集合候选区域重建其记忆集。除此之外，G1 始终维护年轻代区域的记忆集，因为它们在每次回收中都会被处理，并且默认情况下也会对部分巨型对象进行维护，以便进行主动回收。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Collection Set（收集集合）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;收集集合是指用于回收空间的源区域集合。根据垃圾收集类型的不同，收集集合由不同类型的区域组成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在仅年轻代阶段（Young-Only phase）中，收集集合仅包含年轻代区域，以及可能可以回收的巨型对象所在区域。&lt;/li&gt;
&lt;li&gt;在空间回收阶段（Space-Reclamation phase）中，收集集合包含年轻代区域、可能可回收的巨型对象区域，以及来自候选集合中的部分老年代区域。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;收集集合候选区域（collection set candidate regions）是那些在空间回收阶段中&lt;strong&gt;高度可能被回收&lt;/strong&gt;的区域。G1 会在 Remark 停顿期间根据它们包含的存活数据量以及与其他区域的连接关系来选择这些区域。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;存活数据少（即空闲空间多）的区域优先于大部分数据存活的区域&lt;/li&gt;
&lt;li&gt;连接性低的区域优先于连接性高的区域&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因为回收这些“更高效”的区域所需的工作量更小。G1 会从候选区域中剔除那些对可回收空间贡献不大的区域，例如那些可回收空间少于 &lt;code&gt;-XX:G1HeapWastePercent&lt;/code&gt; 指定比例的区域。这些区域在本次空间回收阶段中将不会被回收。&lt;/p&gt;
&lt;p&gt;在 Remark 与 Cleanup 停顿之间，G1 会开始为后续回收做准备，而 Cleanup 停顿则完成这些工作，并根据效率对区域进行排序。那些回收成本更低、同时可释放空间更多的区域，会在后续的 Mixed 收集中被优先回收。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;垃圾收集过程（Garbage Collection Process）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;一次垃圾收集由四个阶段组成：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Pre Evacuate Collection Set（疏散前准备阶段）
该阶段执行垃圾收集的一些准备工作：将 TLAB（线程本地分配缓冲区）从 mutator 线程中分离、根据《Java 堆大小调整》中描述的方式选择本次收集集合（collection set），以及其他一些较小的准备操作。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Merge Heap Roots（合并堆根）
在该阶段，G1 会从收集集合区域中创建一个统一的记忆集（remembered set），以便后续进行更容易的并行处理。这一步会去除各个独立记忆集中大量重复项，否则这些重复项需要在之后以更高成本进行过滤处理。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Evacuate Collection Set（疏散收集集合）
这是主要的工作阶段：G1 从根（roots）开始移动对象。根引用是指来自收集集合之外的引用，包括：&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;JVM 内部数据结构中的引用（外部根 external roots）&lt;/li&gt;
&lt;li&gt;代码中的引用（代码根 code roots）&lt;/li&gt;
&lt;li&gt;Java 堆其余部分中的引用（堆根 heap roots）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于所有根引用，G1 会将收集集合中被引用的对象复制到其目标区域，并递归处理其引用，将指向收集集合内对象的引用作为新的根继续处理，直到不再存在新的根为止。&lt;/p&gt;
&lt;p&gt;各个子阶段的执行时间可以通过 &lt;code&gt;-Xlog:gc+phases=debug&lt;/code&gt; 日志观察，包括：Ext Root Scanning、Code Root Scan、Scan Heap Roots 和 Object Copy 等子阶段。&lt;/p&gt;
&lt;p&gt;G1 还可能会为可选的收集集合重复执行主要的疏散阶段。&lt;/p&gt;
&lt;ol start="4"&gt;
&lt;li&gt;Post Evacuate Collection Set（疏散后处理阶段）
该阶段包含清理工作，包括引用处理，以及为后续 mutator（应用线程）阶段做准备。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这些阶段对应于使用 &lt;code&gt;-Xlog:gc+phases=info&lt;/code&gt; 时所打印的各个阶段。&lt;/p&gt;
&lt;h2 id="garbage-first-内部机制garbage-first-internals"&gt;Garbage-First 内部机制（Garbage-First Internals）
&lt;/h2&gt;&lt;p&gt;本节描述 Garbage-First（G1）垃圾收集器的一些重要细节。&lt;/p&gt;
&lt;h3 id="java-堆大小调整java-heap-sizing"&gt;Java 堆大小调整（Java Heap Sizing）
&lt;/h3&gt;&lt;p&gt;G1 在调整 Java 堆大小时遵循标准规则，使用以下参数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-XX:InitialHeapSize&lt;/code&gt;：Java 堆初始大小&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-XX:MaxHeapSize&lt;/code&gt;：Java 堆最大大小&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-XX:MinHeapFreeRatio&lt;/code&gt;：用于确定最小空闲内存百分比&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-XX:MaxHeapFreeRatio&lt;/code&gt;：用于确定调整后最大空闲内存百分比&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;G1 垃圾收集器仅在 &lt;strong&gt;Remark（重新标记）停顿&lt;/strong&gt; 和 &lt;strong&gt;Full GC（完整垃圾回收）停顿&lt;/strong&gt;期间考虑根据这些选项调整 Java 堆大小。该过程可能会向操作系统释放内存，或从操作系统申请内存。&lt;/p&gt;
&lt;p&gt;堆扩展发生在垃圾收集停顿期间，而内存释放则发生在停顿之后，并与应用程序并发执行。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;仅年轻代阶段的分代大小调整（Young-Only Phase Generation Sizing）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;G1 总是在一次普通的年轻代收集结束时，为下一个 mutator（应用线程）阶段确定年轻代的大小。通过这种方式，G1 可以基于对实际停顿时间的长期观察，满足使用 &lt;code&gt;-XX:MaxGCPauseTimeMillis&lt;/code&gt; 和 &lt;code&gt;-XX:GCPauseIntervalMillis&lt;/code&gt; 设置的停顿时间目标。&lt;/p&gt;
&lt;p&gt;该计算会考虑相似大小的年轻代在以往回收中所花费的时间，例如包括以下信息：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在垃圾收集期间需要复制的对象数量&lt;/li&gt;
&lt;li&gt;这些对象之间的相互关联程度&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;-XX:GCPauseIntervalMillis&lt;/code&gt; 和 &lt;code&gt;-XX:MaxGCPauseTimeMillis&lt;/code&gt; 选项共同定义了最小应用程序利用率（Minimum Mutator Utilization, MMU）。G1 会尝试在每一个长度为 &lt;code&gt;-XX:GCPauseIntervalMillis&lt;/code&gt; 的时间窗口内，使垃圾收集停顿时间最多占用 &lt;code&gt;-XX:MaxGCPauseTimeMillis&lt;/code&gt; 毫秒。&lt;/p&gt;
&lt;p&gt;如果没有其他约束，G1 会在 &lt;code&gt;-XX:G1NewSizePercent&lt;/code&gt; 和 &lt;code&gt;-XX:G1MaxNewSizePercent&lt;/code&gt; 所定义的范围之间自适应地调整年轻代大小，以满足停顿时间目标。有关如何修复长时间停顿的更多信息，请参见《Garbage-First 垃圾收集器调优》。&lt;/p&gt;
&lt;p&gt;另外，也可以使用 &lt;code&gt;-XX:NewSize&lt;/code&gt; 与 &lt;code&gt;-XX:MaxNewSize&lt;/code&gt; 分别设置年轻代的最小和最大大小。&lt;/p&gt;
&lt;blockquote class="alert alert-note"&gt;
 &lt;div class="alert-header"&gt;
 &lt;span class="alert-icon"&gt;📝&lt;/span&gt;
 &lt;span class="alert-title"&gt;备注&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="alert-body"&gt;
 &lt;p&gt;只指定其中一个后续选项（-XX:NewSize 或 -XX:MaxNewSize）会将年轻代大小固定为通过该参数传入的精确值。&lt;/p&gt;
&lt;p&gt;这会禁用停顿时间控制（pause time control）。&lt;/p&gt;
 &lt;/div&gt;
 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;空间回收阶段的分代大小调整（Space-Reclamation Phase Generation Sizing）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在空间回收阶段（space-reclamation phase）中，G1 会尝试在单次垃圾收集停顿中，最大化老年代空间的回收量。年轻代的大小通常会被设置为允许的最小值，一般由 &lt;code&gt;-XX:G1NewSizePercent&lt;/code&gt; 决定，同时也会考虑 MMU（最小应用程序利用率）规范。&lt;/p&gt;
&lt;p&gt;在该阶段的每一次 mixed 收集开始时，G1 会从收集集合候选区域中选择一部分区域加入到收集集合中。这些额外加入的老年代区域由三部分组成：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;最小老年代区域集合
用于确保疏散（evacuation）进度的基本集合。该集合的大小由“收集集合候选区域数量 ÷ 空间回收阶段长度（由 &lt;code&gt;-XX:G1MixedGCCountTarget&lt;/code&gt; 决定）”来计算。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;额外老年代区域集合
如果 G1 预测在完成最小集合回收后仍然有剩余时间，则会从候选区域中继续加入老年代区域，直到预测使用约 80% 的剩余停顿时间为止。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可选收集集合（Optional collection set）
在完成前两部分之后，如果本次停顿仍然有时间，G1 会逐步疏散这部分可选区域。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;前两个集合会在一次初始收集过程中完成，而可选集合则会在剩余时间内逐步处理。这种方式既保证了空间回收的进度，又提高了停顿时间控制的成功率，同时降低了可选集合管理带来的额外开销。&lt;/p&gt;
&lt;p&gt;当收集集合候选区域不再有可用区域时，空间回收阶段结束。&lt;/p&gt;
&lt;p&gt;更多关于 G1 使用多少老年代区域以及如何避免较长 mixed 收集停顿的信息，请参见&lt;a class="link" href="https://docs.oracle.com/en/java/javase/21/gctuning/garbage-first-garbage-collector-tuning.html#GUID-90E30ACA-8040-432E-B3A0-1E0440AB556A" target="_blank" rel="noopener"
 &gt;《Garbage-First 垃圾收集器调优》&lt;/a&gt;。&lt;/p&gt;
&lt;h3 id="周期性垃圾回收periodic-garbage-collections"&gt;周期性垃圾回收（Periodic Garbage Collections）
&lt;/h3&gt;&lt;p&gt;如果由于应用程序处于空闲状态而长时间没有发生垃圾回收，虚拟机可能会长时间持有大量未使用的内存，而这些内存本可以被其他用途使用。为了避免这种情况，G1 可以通过 &lt;code&gt;-XX:G1PeriodicGCInterval&lt;/code&gt; 参数强制定期执行垃圾回收。&lt;/p&gt;
&lt;p&gt;该参数用于指定 G1 进行垃圾回收的最小时间间隔（单位为毫秒）。如果自上一次垃圾回收停顿以来已经超过该时间，且当前没有并发回收周期正在进行，则 G1 会触发额外的垃圾回收，其可能行为如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在仅年轻代阶段（Young-Only phase）期间：
G1 会通过一次 Concurrent Start 停顿启动并发标记（concurrent marking）；如果指定了 &lt;code&gt;-XX:-G1PeriodicGCInvokesConcurrent&lt;/code&gt;，则会触发一次 Full GC。&lt;/li&gt;
&lt;li&gt;在空间回收阶段（Space Reclamation phase）期间：
G1 会继续空间回收阶段，并触发与当前进度相匹配的垃圾回收停顿类型。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;-XX:G1PeriodicGCSystemLoadThreshold&lt;/code&gt; 参数可以用于进一步限制是否触发周期性垃圾回收：如果 JVM 所在系统（例如容器）通过 &lt;code&gt;getloadavg()&lt;/code&gt; 返回的一分钟平均系统负载高于该阈值，则不会执行周期性垃圾回收。&lt;/p&gt;
&lt;p&gt;更多关于周期性垃圾回收的信息，请参见&lt;a class="link" href="https://openjdk.org/jeps/346" target="_blank" rel="noopener"
 &gt;JEP 346：《Promptly Return Unused Committed Memory from G1》&lt;/a&gt;。&lt;/p&gt;
&lt;h3 id="确定初始堆占用率determining-initiating-heap-occupancy"&gt;确定初始堆占用率（Determining Initiating Heap Occupancy）
&lt;/h3&gt;&lt;p&gt;初始堆占用率百分比（Initiating Heap Occupancy Percent，IHOP）是触发一次 Concurrent Start 收集的阈值，它被定义为老年代大小的一个百分比。&lt;/p&gt;
&lt;p&gt;G1 默认会通过观察标记（marking）所花费的时间，以及在标记周期中老年代通常的内存分配情况，自动计算一个最优的 IHOP。这一特性称为 &lt;strong&gt;自适应 IHOP（Adaptive IHOP）&lt;/strong&gt;。如果该功能处于启用状态，那么 &lt;code&gt;-XX:InitiatingHeapOccupancyPercent&lt;/code&gt; 选项仅在系统还没有足够观测数据以准确预测 IHOP 阈值时，作为初始值使用，其含义是当前老年代大小的一个百分比。可以通过 &lt;code&gt;-XX:-G1UseAdaptiveIHOP&lt;/code&gt; 关闭这一行为。在这种情况下，&lt;code&gt;-XX:InitiatingHeapOccupancyPercent&lt;/code&gt; 的值将始终决定该触发阈值。&lt;/p&gt;
&lt;p&gt;在内部实现中，自适应 IHOP 的目标是将“初始堆占用率”设置为：当老年代占用达到一个值时，空间回收阶段的第一次 mixed 垃圾回收刚好开始。这个目标值通常等于当前最大老年代容量减去 &lt;code&gt;-XX:G1HeapReservePercent&lt;/code&gt; 所预留的额外缓冲空间。&lt;/p&gt;
&lt;h3 id="标记marking"&gt;标记（Marking）
&lt;/h3&gt;&lt;p&gt;G1 的标记使用一种称为 &lt;strong&gt;“起始快照（Snapshot-At-The-Beginning，SATB）”&lt;/strong&gt; 的算法。它会在初始标记（Initial Mark）停顿时对堆创建一个虚拟快照，在标记开始时处于存活状态的所有对象，在整个标记过程中都被认为是存活的。这意味着，在标记过程中变为死亡（不可达）的对象，在空间回收时仍然会被当作存活对象处理（某些情况除外）。与其他收集器相比，这可能会导致一些额外的内存被“错误保留”。然而，SATB 可以在一定程度上提供更好的延迟表现，尤其是在 Remark 停顿期间。那些在标记期间被过于保守地认为存活的对象，会在下一次标记过程中被回收。&lt;/p&gt;
&lt;p&gt;关于标记相关问题的更多信息，请参见&lt;a class="link" href="https://docs.oracle.com/en/java/javase/21/gctuning/garbage-first-garbage-collector-tuning.html#GUID-90E30ACA-8040-432E-B3A0-1E0440AB556A" target="_blank" rel="noopener"
 &gt;《Garbage-First 垃圾收集器调优》&lt;/a&gt;。&lt;/p&gt;
&lt;h3 id="极度紧张堆空间情况下的行为behavior-in-very-tight-heap-situations"&gt;极度紧张堆空间情况下的行为（Behavior in Very Tight Heap Situations）
&lt;/h3&gt;&lt;p&gt;当应用程序长期保持大量对象存活，以至于疏散（evacuation）无法找到足够空间进行对象复制时，就会发生 &lt;strong&gt;疏散失败（Evacuation Failure）&lt;/strong&gt;。疏散失败意味着 G1 会尝试完成当前垃圾收集：已经成功移动的对象保持在新位置，而尚未移动的对象不会再被复制，只是对对象之间的引用进行调整。疏散失败可能会带来一定额外开销，但通常其速度仍接近一次普通的年轻代收集。在发生该失败的垃圾收集完成后，G1 会正常恢复应用程序执行，而不会立即采取其他措施。G1 会假设疏散失败发生在垃圾收集接近尾声时，即大部分对象已经被移动，并且剩余空间足够支撑应用继续运行，直到标记完成并进入空间回收阶段。&lt;/p&gt;
&lt;p&gt;如果这一假设不成立，那么 G1 最终会触发一次 Full GC。这种收集会对整个堆进行原地压缩，可能非常缓慢。&lt;/p&gt;
&lt;p&gt;关于分配失败或 Full GC 早于 OOM 发生的问题，请参见&lt;a class="link" href="https://docs.oracle.com/en/java/javase/21/gctuning/garbage-first-garbage-collector-tuning.html#GUID-90E30ACA-8040-432E-B3A0-1E0440AB556A" target="_blank" rel="noopener"
 &gt;《Garbage-First 垃圾收集器调优》&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;巨型对象（Humongous Objects）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;巨型对象是指大小大于或等于一个 Region（区域）一半的对象。当前 Region 的大小会根据 G1 的“自动调优默认值（Ergonomic Defaults for G1 GC）”来确定，除非通过 &lt;code&gt;-XX:G1HeapRegionSize&lt;/code&gt; 参数显式设置。&lt;/p&gt;
&lt;p&gt;这些巨型对象在某些情况下会被特殊处理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;分配方式&lt;/strong&gt;
每个巨型对象都会被分配到老年代中一段连续的 Region 序列中。对象本身的起始位置总是位于该序列中第一个 Region 的开头。该序列中最后一个 Region 可能存在剩余空间，但这部分空间在整个对象被回收之前无法用于其他分配。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;回收方式&lt;/strong&gt;
通常情况下，巨型对象只能在标记结束后的 Cleanup 停顿中被回收，或者在 Full GC 中如果它们已不可达时被回收。
但对于某些特殊情况（例如 primitive 类型数组，如 bool、各种整数类型以及浮点数数组），G1 有一个特殊优化：在任何垃圾回收停顿中，如果这些巨型对象没有被大量对象引用，G1 会尝试主动回收它们。该行为默认开启，可以通过 &lt;code&gt;-XX:G1EagerReclaimHumongousObjects&lt;/code&gt; 关闭。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;分配对 GC 的影响&lt;/strong&gt;
巨型对象的分配可能会导致垃圾回收提前发生。G1 在每次巨型对象分配时都会检查 IHOP（Initiating Heap Occupancy）阈值，如果当前堆占用超过该阈值，则可能立即触发一次 Initial Mark young collection。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;移动行为（非常重要）&lt;/strong&gt;
巨型对象只有在极端情况下才会被移动：
当第一次 Full GC 仍无法为巨型对象分配足够的连续空间时，G1 会在同一次停顿中触发第二次 Full GC 进行“最后手段”的回收尝试。这个过程非常慢。由于包含巨型对象尾部的 Region 可能存在不可用空间，即使经过这些处理，仍然可能导致 JVM 因为内存不足而退出（OutOfMemoryError）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="g1-gc-的自适应默认值ergonomic-defaults-for-g1-gc"&gt;G1 GC 的自适应默认值（Ergonomic Defaults for G1 GC）
&lt;/h2&gt;&lt;p&gt;本主题概述了 G1 中最重要的一些默认配置及其默认取值。这些默认值在不使用任何额外参数的情况下，提供了对 G1 行为和资源使用情况的基本预期。&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;选项与默认值&lt;/th&gt;
 &lt;th style="text-align: left"&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;-XX:MaxGCPauseMillis=200&lt;/code&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;最大停顿时间目标。&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;-XX:GCPauseTimeInterval=&amp;lt;ergo&amp;gt;&lt;/code&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;最大停顿时间间隔目标。默认情况下 G1 不设置该目标，允许在极端情况下连续执行垃圾回收（back-to-back）。&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;-XX:ParallelGCThreads=&amp;lt;ergo&amp;gt;&lt;/code&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;垃圾回收停顿期间用于并行工作的最大线程数。该值由 JVM 运行所在机器的可用线程数推导而来：如果可用 CPU 线程数小于等于 8，则直接使用该值；否则使用“超过 8 的线程数的五分之八”加上 8 作为最终线程数。在每次停顿开始时，该线程数还会受到最大堆大小限制：G1 不会为每 &lt;code&gt;-XX:HeapSizePerGCThread&lt;/code&gt; 大小的 Java 堆容量分配超过一个线程。&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;-XX:ConcGCThreads=&amp;lt;ergo&amp;gt;&lt;/code&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;并发标记阶段使用的最大线程数。默认值为 &lt;code&gt;-XX:ParallelGCThreads / 4&lt;/code&gt;。&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;-XX:+G1UseAdaptiveIHOP&lt;/code&gt; &lt;code&gt;-XX:InitiatingHeapOccupancyPercent=45&lt;/code&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;控制初始堆占用率（IHOP）的默认设置：启用自适应 IHOP；在最初几个收集周期中，G1 会使用老年代 45% 的占用率作为标记起始阈值。&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;-XX:G1HeapRegionSize=&amp;lt;ergo&amp;gt;&lt;/code&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;堆区域（Region）的大小。默认值基于最大堆大小计算，目标是生成约 2048 个区域，最大值经过调优不超过 32 MB。用户指定值必须是 2 的幂，合法范围为 1 MB 到 512 MB。&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;-XX:G1NewSizePercent=5&lt;/code&gt; &lt;code&gt;-XX:G1MaxNewSizePercent=60&lt;/code&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;年轻代大小的范围，占当前 Java 堆的百分比，在这两个值之间动态变化。&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;-XX:G1HeapWastePercent=5&lt;/code&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;收集集合候选区域中允许未回收空间的比例（百分比）。当候选区域中的可回收空间低于该值时，G1 会停止空间回收阶段。&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;-XX:G1MixedGCCountTarget=8&lt;/code&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;空间回收阶段的期望长度，以垃圾收集次数（collections）为单位。&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;-XX:G1MixedGCLiveThresholdPercent=85&lt;/code&gt;&lt;/td&gt;
 &lt;td style="text-align: left"&gt;老年代区域中存活对象比例超过该百分比的区域，不会在本次空间回收阶段被收集。&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote class="alert alert-note"&gt;
 &lt;div class="alert-header"&gt;
 &lt;span class="alert-icon"&gt;📝&lt;/span&gt;
 &lt;span class="alert-title"&gt;备注&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="alert-body"&gt;
 &lt;p&gt;&lt;code&gt;&amp;lt;ergo&amp;gt;&lt;/code&gt; 表示该实际取值是根据运行环境通过“自适应调优（ergonomics）”自动决定的。&lt;/p&gt;
 &lt;/div&gt;
 &lt;/blockquote&gt;
&lt;h2 id="与其他收集器的比较comparison-to-other-collectors"&gt;与其他收集器的比较（Comparison to Other Collectors）
&lt;/h2&gt;&lt;p&gt;这是 G1 与其他垃圾收集器之间主要差异的总结：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;**Parallel GC（并行收集器）**只能在一次整体操作中压缩并回收老年代空间。相比之下，G1 将这项工作分摊到多次更短的收集过程中逐步完成。这显著缩短了停顿时间，但可能会以吞吐量下降为代价。&lt;/li&gt;
&lt;li&gt;G1 会在并发过程中执行部分老年代空间回收工作。&lt;/li&gt;
&lt;li&gt;由于其并发特性，G1 可能比上述收集器具有更高的开销，从而影响整体吞吐量。&lt;/li&gt;
&lt;li&gt;ZGC 的目标是提供更小的停顿时间，但代价是进一步降低吞吐量。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于其工作方式，G1 具有一些机制来提升垃圾回收效率：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;G1 可以在任意一次垃圾回收中回收老年代中一些完全空的大区域。这可以避免许多不必要的垃圾回收，在较低开销下释放大量空间。&lt;/li&gt;
&lt;li&gt;G1 可以选择性地在 Java 堆中并发去重重复字符串。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;回收老年代中完全空的大对象（humongous objects）的机制始终是启用的。可以通过 &lt;code&gt;-XX:-G1EagerReclaimHumongousObjects&lt;/code&gt; 禁用该功能。&lt;/p&gt;
&lt;p&gt;字符串去重默认是关闭的，可以通过 &lt;code&gt;-XX:+UseStringDeduplication&lt;/code&gt; 启用。&lt;/p&gt;</description></item><item><title>Java 八股</title><link>https://blog.evorsio.com/p/java-interview-notes/</link><pubDate>Sun, 19 Apr 2026 23:00:00 +1200</pubDate><guid>https://blog.evorsio.com/p/java-interview-notes/</guid><description>&lt;h1 id="java-后端开发八股"&gt;Java 后端开发八股
&lt;/h1&gt;&lt;h2 id="基础语法"&gt;基础语法
&lt;/h2&gt;&lt;h3 id="基本类型"&gt;基本类型
&lt;/h3&gt;&lt;p&gt;8 种基本类型，分为四类&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;类型类别&lt;/th&gt;
 &lt;th&gt;数据类型&lt;/th&gt;
 &lt;th&gt;占用字节&lt;/th&gt;
 &lt;th&gt;默认值&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;整数&lt;/td&gt;
 &lt;td&gt;byte&lt;/td&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;0&lt;/td&gt;
 &lt;td&gt;最小整数类型&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;整数&lt;/td&gt;
 &lt;td&gt;short&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;0&lt;/td&gt;
 &lt;td&gt;短整型&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;整数&lt;/td&gt;
 &lt;td&gt;int&lt;/td&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;0&lt;/td&gt;
 &lt;td&gt;常用整数类型&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;整数&lt;/td&gt;
 &lt;td&gt;long&lt;/td&gt;
 &lt;td&gt;8&lt;/td&gt;
 &lt;td&gt;0L&lt;/td&gt;
 &lt;td&gt;长整数类型&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;浮点&lt;/td&gt;
 &lt;td&gt;float&lt;/td&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;0.0f&lt;/td&gt;
 &lt;td&gt;单精度浮点&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;浮点&lt;/td&gt;
 &lt;td&gt;double&lt;/td&gt;
 &lt;td&gt;8&lt;/td&gt;
 &lt;td&gt;0.0d&lt;/td&gt;
 &lt;td&gt;双精度浮点（默认）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;字符&lt;/td&gt;
 &lt;td&gt;char&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;&amp;lsquo;\u0000&amp;rsquo;&lt;/td&gt;
 &lt;td&gt;Unicode 字符&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;布尔&lt;/td&gt;
 &lt;td&gt;boolean&lt;/td&gt;
 &lt;td&gt;1（JVM 依实现）&lt;/td&gt;
 &lt;td&gt;false&lt;/td&gt;
 &lt;td&gt;逻辑值 true/false&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="object-类有哪些方法"&gt;Object 类有哪些方法？
&lt;/h3&gt;&lt;p&gt;共 1 1 个，去掉重载一共有 9 种方法&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;方法&lt;/th&gt;
 &lt;th&gt;返回类型&lt;/th&gt;
 &lt;th&gt;作用&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;getClass()&lt;/td&gt;
 &lt;td&gt;Class&lt;?&gt;&lt;/td&gt;
 &lt;td&gt;获取运行时类信息&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;hashCode()&lt;/td&gt;
 &lt;td&gt;int&lt;/td&gt;
 &lt;td&gt;返回对象哈希值&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;equals(Object obj)&lt;/td&gt;
 &lt;td&gt;boolean&lt;/td&gt;
 &lt;td&gt;判断对象是否相等&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;toString()&lt;/td&gt;
 &lt;td&gt;String&lt;/td&gt;
 &lt;td&gt;返回对象字符串表示&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;clone()&lt;/td&gt;
 &lt;td&gt;Object&lt;/td&gt;
 &lt;td&gt;克隆对象（需实现 Cloneable）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;finalize()&lt;/td&gt;
 &lt;td&gt;void&lt;/td&gt;
 &lt;td&gt;GC 回收前调用（已过时）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;wait()&lt;/td&gt;
 &lt;td&gt;void&lt;/td&gt;
 &lt;td&gt;线程等待（需在同步块中）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;wait(long timeout)&lt;/td&gt;
 &lt;td&gt;void&lt;/td&gt;
 &lt;td&gt;带超时等待&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;wait(long timeout, int nanos)&lt;/td&gt;
 &lt;td&gt;void&lt;/td&gt;
 &lt;td&gt;更精细等待&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;notify()&lt;/td&gt;
 &lt;td&gt;void&lt;/td&gt;
 &lt;td&gt;唤醒一个等待线程&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;notifyAll()&lt;/td&gt;
 &lt;td&gt;void&lt;/td&gt;
 &lt;td&gt;唤醒所有等待线程&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="string-s--new-stringhello会创建几个对象"&gt;&lt;code&gt;String s = new String(&amp;quot;hello&amp;quot;);&lt;/code&gt;会创建几个对象?
&lt;/h3&gt;&lt;p&gt;1 个或 2 个对象&lt;/p&gt;
&lt;p&gt;分情况讨论:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;常量池没有 &amp;ldquo;hello&amp;rdquo;： 创建 2 个对象：常量池 &amp;ldquo;hello&amp;rdquo; 和 堆中 new String(&amp;ldquo;hello&amp;rdquo;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;常量池已有 &amp;ldquo;hello&amp;rdquo;： 创建 1 个对象：堆中 new String(&amp;ldquo;hello&amp;rdquo;)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="创建对象实例的方式有几种"&gt;创建对象实例的方式有几种？
&lt;/h3&gt;&lt;p&gt;4 种&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;方式&lt;/th&gt;
 &lt;th&gt;示例&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;1. new 关键字&lt;/td&gt;
 &lt;td&gt;User u = new User();&lt;/td&gt;
 &lt;td&gt;最常用，直接调用构造方法&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;2. 反射机制&lt;/td&gt;
 &lt;td&gt;User u = (User) Class.forName(&amp;ldquo;User&amp;rdquo;).newInstance();&lt;/td&gt;
 &lt;td&gt;运行时创建对象&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;3. Clone 克隆&lt;/td&gt;
 &lt;td&gt;User u2 = (User) u1.clone();&lt;/td&gt;
 &lt;td&gt;通过对象复制创建（浅拷贝）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;4. 反序列化&lt;/td&gt;
 &lt;td&gt;User u = (User) ObjectInputStream.readObject();&lt;/td&gt;
 &lt;td&gt;从文件/网络恢复对象&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="为什么-equals-和-hashcode-要同时重写"&gt;为什么 equals() 和 hashcode() 要同时重写？
&lt;/h3&gt;&lt;p&gt;JDK 规范中，如果两个对象 &lt;strong&gt;equals() 返回 true（逻辑相等）&lt;/strong&gt;，那么它们的 &lt;strong&gt;hashCode 必须相同&lt;/strong&gt;；反之不成立，因为可能发生哈希冲突。&lt;/p&gt;
&lt;p&gt;在 HashSet / HashMap 中，hashCode 决定“存放位置”，equals 决定“是否重复”，如果只重写一个，会导致逻辑不一致，出现重复数据或查找失败。&lt;/p&gt;
&lt;h3 id="-和-equals-的区别"&gt;== 和 equals() 的区别
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;==&lt;/code&gt; 比较的是引用地址（或基本类型值），&lt;code&gt;equals()&lt;/code&gt; 在 Object 类中默认比较地址，但在包装类中可以重写为比较内容，因此一般用于对象逻辑相等判断。&lt;/p&gt;
&lt;h3 id="抽象类和接口的区别"&gt;抽象类和接口的区别
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;对比项&lt;/th&gt;
 &lt;th&gt;抽象类（abstract class）&lt;/th&gt;
 &lt;th&gt;接口（interface）&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;是否可以实例化&lt;/td&gt;
 &lt;td&gt;❌ 不可以&lt;/td&gt;
 &lt;td&gt;❌ 不可以&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;方法&lt;/td&gt;
 &lt;td&gt;可以有抽象方法 + 具体方法&lt;/td&gt;
 &lt;td&gt;抽象方法 + default/static 方法（JDK8+）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;变量&lt;/td&gt;
 &lt;td&gt;可以有普通成员变量&lt;/td&gt;
 &lt;td&gt;只能是常量（public static final）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;构造方法&lt;/td&gt;
 &lt;td&gt;✔ 有&lt;/td&gt;
 &lt;td&gt;❌ 没有&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;继承方式&lt;/td&gt;
 &lt;td&gt;单继承&lt;/td&gt;
 &lt;td&gt;多实现&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;访问修饰符&lt;/td&gt;
 &lt;td&gt;可以任意&lt;/td&gt;
 &lt;td&gt;方法默认 public&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id="为什么在-java-8-之后接口中可以有-defaultstatic-方法呢"&gt;为什么在 Java 8 之后接口中可以有 default/static 方法呢？
&lt;/h4&gt;&lt;p&gt;Java 8 之后接口引入 default 和 static 方法，是为了在不破坏已有实现类的情况下扩展接口能力，同时支持函数式编程和工具方法集中管理。default 方法属于给实现类用的或重写的“默认行为”，static 方法属于属于接口本身的工具方法。&lt;/p&gt;
&lt;h3 id="类是什么"&gt;类是什么？
&lt;/h3&gt;&lt;p&gt;类（Class）是面向对象编程（OOP）中用来描述对象的结构和行为的基本构造单元。&lt;/p&gt;
&lt;h3 id="接口是什么"&gt;接口是什么？
&lt;/h3&gt;&lt;p&gt;接口（Interface）是面向对象编程（OOP）中用于定义行为规范的一种抽象机制。&lt;/p&gt;
&lt;h3 id="抽象类是什么"&gt;抽象类是什么？
&lt;/h3&gt;&lt;p&gt;抽象类（Abstract Class）是面向对象编程（OOP）中用于描述“部分抽象对象”的一种类类型。&lt;/p&gt;
&lt;h3 id="谈谈你对面向对象的理解"&gt;谈谈你对面向对象的理解
&lt;/h3&gt;&lt;p&gt;与面向过程相比，面向对象是一种以“对象”为中心来组织软件设计的编程思想，将数据与行为封装在一起，通过封装、继承和多态来模拟现实世界，从而降低系统复杂度并提升可扩展性。&lt;/p&gt;
&lt;h4 id="oop-的核心是什么"&gt;OOP 的核心是什么？
&lt;/h4&gt;&lt;p&gt;一切皆“对象”&lt;/p&gt;
&lt;p&gt;现实世界 → 抽象 → 对象 → 程序模型 ==&amp;gt; 人、车、订单、商品 → 都可以抽象成对象&lt;/p&gt;
&lt;h4 id="oop-三大核心特性"&gt;OOP 三大核心特性
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;封装（Encapsulation）：把数据和行为封装在一起，对外隐藏内部实现&lt;/li&gt;
&lt;li&gt;继承（Inheritance）：子类复用父类的属性和方法，实现代码复用&lt;/li&gt;
&lt;li&gt;多态（Polymorphism）：同一行为，不同实现，子类可以重写父类方法&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="stringbuilder-和-stringbuffer-的区别"&gt;StringBuilder 和 StringBuffer 的区别
&lt;/h3&gt;&lt;p&gt;StringBuffer 线程安全（方法使用 synchronized 修饰），StringBuilder 非线程安全&lt;/p&gt;
&lt;h3 id="error-和-exception-的区别"&gt;Error 和 Exception 的区别
&lt;/h3&gt;&lt;p&gt;Error 是 JVM 层面的严重错误，通常表示系统级问题，程序一般无法处理；Exception 是程序运行过程中可能出现的异常情况，程序可以捕获并处理。&lt;/p&gt;
&lt;p&gt;Exception 又分为：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;受检异常（Checked Exception）：编译期必须处理（try-catch 或 throws），否则无法通过编译&lt;/li&gt;
&lt;li&gt;运行时异常（RuntimeException）：编译期不强制处理，运行时抛出，通常由程序逻辑错误引起，但也可以捕获处理&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;graph TD
 A[Throwable] --&gt; B[Error]
 A --&gt; C[Exception]

 B --&gt; B1[OutOfMemoryError]
 B --&gt; B2[StackOverflowError]
 B --&gt; B3[NoClassDefFoundError]

 C --&gt; D[Checked Exception]
 C --&gt; E[RuntimeException]

 D --&gt; D1[IOException]
 D --&gt; D2[SQLException]
 D --&gt; D3[FileNotFoundException]

 E --&gt; E1[NullPointerException]
 E --&gt; E2[ArrayIndexOutOfBoundsException]
 E --&gt; E3[ClassCastException]
 E --&gt; E4[ArithmeticException]&lt;/pre&gt;&lt;h3 id="对象的组成"&gt;对象的组成
&lt;/h3&gt;&lt;p&gt;由三大部分组成， 对象头（Object Header），实例数据（Instance Data），对齐填充（Padding）&lt;/p&gt;
&lt;h5 id="对象头"&gt;对象头
&lt;/h5&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Mark Word （8 个字节）&lt;/p&gt;
&lt;p&gt;&lt;img alt="markword" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="C:\\Users\\Admin\\Downloads\\markword.png"&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Klass Pointer （ 8 个字节，如果开启了指针压缩（默认）是 4 个字节）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数组长度（length，如果是数组对象）&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h5 id="实例数据"&gt;实例数据
&lt;/h5&gt;&lt;p&gt;class User {
int id; // 4 字节
long age; // 8 字节
Object obj; // 4 字节（引用）
}&lt;/p&gt;
&lt;h5 id="对齐填充"&gt;对齐填充
&lt;/h5&gt;&lt;p&gt;保证对象总大小是 8 字节的整数倍， 因为 JVM 内存分配是按 8 字节对齐的&lt;/p&gt;
&lt;p&gt;在 64 位 JVM（开启指针压缩）下，User 对象包含&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;12 字节对象头（Mark Word + Klass Pointer）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;16 字节实例数据（long 8B + int 4B + obj 引用 4B，JVM 会重排对齐）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对齐填充 4 字节&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;最终大小为 &lt;strong&gt;32 字节&lt;/strong&gt;。&lt;/p&gt;
&lt;h5 id="反射的原理"&gt;反射的原理
&lt;/h5&gt;&lt;p&gt;在运行时通过 Class 元信息 + 方法表 + 常量池解析，动态调用方法或访问字段的一套机制。&lt;/p&gt;
&lt;h2 id="多线程"&gt;多线程
&lt;/h2&gt;&lt;h3 id="进程和线程的区别"&gt;进程和线程的区别
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;对比维度&lt;/th&gt;
 &lt;th&gt;进程&lt;/th&gt;
 &lt;th&gt;线程&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;定义&lt;/td&gt;
 &lt;td&gt;程序的一次执行实例，是资源分配的基本单位&lt;/td&gt;
 &lt;td&gt;进程中的执行单元，是 CPU 调度的基本单位&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;资源&lt;/td&gt;
 &lt;td&gt;拥有独立的内存空间和系统资源&lt;/td&gt;
 &lt;td&gt;共享所属进程的内存和资源&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;调度&lt;/td&gt;
 &lt;td&gt;由操作系统进行调度&lt;/td&gt;
 &lt;td&gt;由 CPU 进行调度&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;开销&lt;/td&gt;
 &lt;td&gt;创建和切换开销大&lt;/td&gt;
 &lt;td&gt;创建和切换开销小&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;独立性&lt;/td&gt;
 &lt;td&gt;进程之间相互独立&lt;/td&gt;
 &lt;td&gt;线程之间共享资源&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;稳定性&lt;/td&gt;
 &lt;td&gt;一个进程崩溃一般不影响其他进程&lt;/td&gt;
 &lt;td&gt;一个线程崩溃可能导致整个进程崩溃&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;通信方式&lt;/td&gt;
 &lt;td&gt;进程间通信（IPC），较复杂&lt;/td&gt;
 &lt;td&gt;线程间可直接共享内存，通信简单&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="线程的分类"&gt;线程的分类
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;用户线程（User Thread）由用户程序创建和管理，JVM 主要执行的线程&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;守护线程（Daemon Thread）为用户线程提供服务的后台线程，如 GC 线程&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="线程的创建方式"&gt;线程的创建方式
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;继承 Thread 类&lt;/strong&gt;，重写 &lt;code&gt;run()&lt;/code&gt; 方法&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实现 Runnable 接口&lt;/strong&gt;，重写 &lt;code&gt;run()&lt;/code&gt; 方法&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实现 Callable 接口 + FutureTask&lt;/strong&gt;，重写 &lt;code&gt;call()&lt;/code&gt; 方法（可返回结果）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;通过线程池创建线程&lt;/strong&gt;（ExecutorService）&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="线程的生命周期"&gt;线程的生命周期
&lt;/h3&gt;&lt;p&gt;通过&lt;code&gt;java.lang.Thread.State&lt;/code&gt;枚举定义的&lt;/p&gt;
&lt;p&gt;&lt;img alt="thread-life" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="C:\\Users\\Admin\\Downloads\\thread-life.png"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;新建 -&amp;gt; 可运行：调用 Thread 对象的 start()方法。&lt;/li&gt;
&lt;li&gt;可运行 -&amp;gt; 运行：被系统选中，获取 CPU 执行权。&lt;/li&gt;
&lt;li&gt;运行 -&amp;gt; 阻塞：请求获取无法马上获取的资源。&lt;/li&gt;
&lt;li&gt;运行 -&amp;gt; 等待：调用 Object 类的 wait()方法。&lt;/li&gt;
&lt;li&gt;运行 -&amp;gt; 超时等待：调用 Thread.sleep(long)或 Object.wait(long)方法，或者期待 join(long)的结束，或者锁定某个对象的 LockSupport.parkNanos()或 LockSupport.parkUntil()方法。&lt;/li&gt;
&lt;li&gt;运行 -&amp;gt; 终止：线程终止。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="start和run方法有什么区别"&gt;&lt;code&gt;start()&lt;/code&gt;和&lt;code&gt;run()&lt;/code&gt;方法有什么区别
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;code&gt;start()&lt;/code&gt; 是启动一个新线程，JVM 会为该线程分配独立的执行栈并调用 run() 方法&lt;/li&gt;
&lt;li&gt;&lt;code&gt;run()&lt;/code&gt; 只是普通方法调用，不会创建线程，直接在当前线程中执行。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="多线程安全问题和产生原因"&gt;多线程安全问题和产生原因
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;存在多个线程同时操作共享资源&lt;/li&gt;
&lt;li&gt;对共享资源的操作不是原子的&lt;/li&gt;
&lt;li&gt;线程执行由于 CPU 调度具有不确定性&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;解决方案：加锁（synchronized / Lock）保证同一时刻只有一个线程访问临界区&lt;/p&gt;
&lt;h3 id="synchronized-的底层原理"&gt;Synchronized 的底层原理
&lt;/h3&gt;&lt;h4 id="称呼层面"&gt;称呼层面
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;隐式锁&lt;/strong&gt;：由 JVM 自动加锁与释放，无需手动控制&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;悲观锁&lt;/strong&gt;：默认认为会发生竞争，访问前先加锁&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;非公平锁&lt;/strong&gt;：不保证先来先得，线程获取锁具有随机性&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可重入锁&lt;/strong&gt;：同一线程可以重复获取同一把锁&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="状态层面"&gt;状态层面
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;无锁&lt;/strong&gt;（001）: 对象初始状态，没有线程竞争&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;偏向锁&lt;/strong&gt;（101）：无竞争时偏向第一个线程，减少 CAS 开销 （在 JDK 16 被彻底移除）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;轻量级锁&lt;/strong&gt;（00）：有少量竞争，通过 CAS 自旋获取锁&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重量级锁&lt;/strong&gt;（10）：竞争激烈时升级为 Monitor 阻塞队列&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="语法层面"&gt;语法层面
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;
&lt;h5 id="作用于代码块编译后"&gt;作用于代码块（编译后）
&lt;/h5&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;monitorenter&lt;/code&gt;：进入同步块获取 Monitor&lt;/p&gt;
&lt;p&gt;&lt;code&gt;monitorexit&lt;/code&gt;：退出同步块释放 Monitor&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;
&lt;h5 id="作用于方法编译后"&gt;作用于方法（编译后）
&lt;/h5&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;方法的方法表中有 flags: ACC_SYNCHRONIZED&lt;/p&gt;
&lt;h4 id="jvm-层面"&gt;JVM 层面
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;synchronized 底层依赖 Mark Word 与 Monitor 实现&lt;/li&gt;
&lt;li&gt;对象头的 Mark Word 中存储锁状态标志&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;​ 倒数 2 位：锁标志位（lock flag）&lt;/p&gt;
&lt;p&gt;​ 第 3 位：偏向锁标志位（biased_lock）&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;在多线程竞争下，锁会发生升级（锁膨胀）以优化性能&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;​ 先尝试偏向锁 (MarkWord 标记线程 ID)&lt;/p&gt;
&lt;p&gt;​ 有竞争时升级为轻量级锁(CAS+自旋+线程栈中 Lock Record)&lt;/p&gt;
&lt;p&gt;​ 多线程竞争时升级为重量级锁(ObjectMonitor（操作系统互斥量），线程进入阻塞状态（BLOCKED）)&lt;/p&gt;
&lt;p&gt;&lt;img alt="image-20260418184939926" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="C:\\Users\\Admin\\Desktop\\blog\\object-monitor.png"&gt;&lt;/p&gt;
&lt;h3 id="threadlocalmap-的底层原理"&gt;ThreadLocalMap 的底层原理
&lt;/h3&gt;&lt;h4 id="对象的四种引用方式"&gt;对象的四种引用方式
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;强引用：永不回收&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;软引用：内存不够才回收&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;弱引用：发现即回收&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;虚引用：不影响对象生命周期，用于回收通知&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="threadlocalmap-结构"&gt;ThreadLocalMap 结构
&lt;/h4&gt;&lt;p&gt;Entry:
key → WeakReference&lt;ThreadLocal&gt;
value → 强引用&lt;/p&gt;
&lt;h4 id="threadlocal-的-key-为什么是弱引用"&gt;ThreadLocal 的 key 为什么是弱引用
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;如果 key 是强引用，Thread → ThreadLocalMap → Entry → ThreadLocal，即使 tl = null，ThreadLocal 仍然被 Map 强引用， &lt;strong&gt;永远无法回收 → 内存泄漏&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;用弱引用之后 WeakReference(ThreadLocal)，下一次 GC：key → null， ThreadLocal 对象可以被回收。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="threadlocal-的-value-为什么是强引用"&gt;ThreadLocal 的 value 为什么是强引用
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;ThreadLocal 的 value 使用强引用，是因为它存储的是线程实际使用的数据，必须在使用期间保持稳定，不能被 GC 随意回收。&lt;/li&gt;
&lt;li&gt;因此设计上采用 key 使用弱引用避免 ThreadLocal 泄漏，而 value 使用强引用保证数据的正确性，并通过惰性清理机制处理 key 为 null 时的内存泄漏问题。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;ThreadLocal 的设计本质是一种基于 GC 约束的工程权衡。它通过弱引用 key 来解决 ThreadLocal 被 ThreadLocalMap 强引用导致的无意识内存泄漏问题，使 ThreadLocal 对象在外部失去引用后可以正常被 GC 回收。但 value 仍然使用强引用，以保证线程在执行期间数据的稳定性，避免业务数据被 GC 意外回收。这种设计的副作用是 key 被回收后 value 仍然残留在线程中，因此 ThreadLocal 将清理责任部分转移给开发者，通过在合适时机显式调用 remove() 来避免 value 泄漏。&lt;/p&gt;
&lt;h3 id="java-集合框架"&gt;Java 集合框架
&lt;/h3&gt;&lt;p&gt;Java 集合主要分为三大类接口体系：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Collection（单列集合）：用于存储 &lt;strong&gt;单个元素的集合&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;List（有序、可重复）：ArrayList，LinkedList&lt;/li&gt;
&lt;li&gt;Set（无序、不可重复）：HashSet，LinkedHashSet&lt;/li&gt;
&lt;li&gt;Queue（先进先出）：&lt;strong&gt;PriorityQueue&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Map（双列集合）：用于存储&lt;strong&gt;键值对（key-value）结构&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;HashMap&lt;/li&gt;
&lt;li&gt;LinkedHashMap&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="arraylist-扩容机制和底层原理"&gt;ArrayList 扩容机制和底层原理
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;ArrayList 底层基于 Object[] 动态数组实现，默认是空数组。&lt;/li&gt;
&lt;li&gt;第一次添加元素时才初始化容量，一般会变为 10。&lt;/li&gt;
&lt;li&gt;当数组容量不足时（即 size 超过当前数组长度），会触发扩容机制，扩容规则是原容量的 1.5 倍。扩容过程包括创建一个更大的新数组，将旧数组中的元素通过数组拷贝方式（System.arraycopy）复制到新数组中，最后用新数组替换旧数组引用。&lt;/li&gt;
&lt;li&gt;由于底层是数组结构，所以 ArrayList 查询效率较高，但插入和删除需要移动元素，性能较低，同时扩容时会有额外的拷贝开销。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="arraylist-和-linkedlist-的区别"&gt;ArrayList 和 LinkedList 的区别
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;ArrayList 底层是基于动态数组实现的，支持通过下标快速访问元素，因此查询效率为 O(1)，但在插入和删除时需要移动元素，效率较低。&lt;/li&gt;
&lt;li&gt;LinkedList 底层是双向链表结构，查询需要从头遍历，因此效率为 O(n)，但在插入和删除时只需要修改节点指针，因此效率较高。&lt;/li&gt;
&lt;li&gt;同时 ArrayList 内存占用较小，而 LinkedList 因为每个节点需要保存前后指针，内存开销更大。总体来说 ArrayList 适合查询多的场景，LinkedList 适合插入删除多的场景。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="arraylist-线程不安全体现和解决方案"&gt;ArrayList 线程不安全体现和解决方案
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;ArrayList 线程不安全的原因在于其 add 操作中的 size++ 不是原子操作，多线程同时修改会导致数据丢失或覆盖，同时扩容过程中也可能发生并发冲突。&lt;/li&gt;
&lt;li&gt;此外，在遍历过程中如果发生结构修改，还会触发 fail-fast 机制，抛出 ConcurrentModificationException。解决方案包括使用 Vector（方法级加锁，性能较差）、Collections.synchronizedList（对 ArrayList 进行同步包装，但迭代需手动加锁），以及 CopyOnWriteArrayList（写时复制，读不加锁，适合读多写少场景，是推荐方案）。&lt;/li&gt;
&lt;li&gt;ArrayList 有自己的内部迭代器实现（ListIterator），属于 fail-fast 机制。在使用普通迭代器（Iterator）遍历集合时，如果对集合结构进行修改（如 add 或 remove），会导致 modCount 和 expectedModCount 不一致，从而触发 ConcurrentModificationException。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="copyonwritearraylist-底层实现和原理"&gt;CopyOnWriteArrayList 底层实现和原理
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;CopyOnWriteArrayList 底层只有一个核心字段：&lt;code&gt;volatile Object[] array&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;核心思想: 写时复制（Copy On Write）,读：直接用旧数组（不加锁）, 写：复制新数组，在新数组上修改，再替换引用。&lt;/li&gt;
&lt;li&gt;写操作加锁，在 JDK 6 以前用的 ReentrantLock，JDK 7 及以后改为 synchronized，写操作很简单，不需要 ReentrantLock 的复杂能力，synchronized 已经优化得很好了，性能已经不差 ReentrantLock。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="hashmap-底层原理和实现"&gt;HashMap 底层原理和实现
&lt;/h3&gt;&lt;p&gt;HashMap 的底层结构是 &lt;strong&gt;数组 + 链表 + 红黑树&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id="扩容机制"&gt;扩容机制
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;HashMap 的扩容本质就是 &lt;strong&gt;数组扩容 + 重新分布（rehash）&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;默认初始容量是 16，负载因子是 0.75，当元素数量超过 &lt;code&gt;容量 × 负载因子&lt;/code&gt; 时就会触发扩容。扩容后容量变为原来的 2 倍，然后把原来所有元素重新计算位置（Java 8 之后做了优化，不是完全重新 hash，而是根据原 index + oldCap 判断去留，减少计算成本）。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="两个参数"&gt;两个参数
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;初始容量（capacity）&lt;/strong&gt;：默认 16，决定桶数组大小&lt;/p&gt;
&lt;blockquote class="alert alert-note"&gt;
 &lt;div class="alert-header"&gt;
 &lt;span class="alert-icon"&gt;📝&lt;/span&gt;
 &lt;span class="alert-title"&gt;备注&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="alert-body"&gt;
 &lt;p&gt;HashMap 的初始容量默认是 16，但如果初始化时传入的不是 2 的幂，底层会通过 &lt;code&gt;tableSizeFor()&lt;/code&gt; 方法调整为大于等于该值的最小 2 的幂。这样做的目的是为了让 &lt;code&gt;(n - 1) &amp;amp; hash&lt;/code&gt; 的位运算更高效且分布更均匀。&lt;/p&gt;
 &lt;/div&gt;
 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;负载因子（load factor）&lt;/strong&gt;：默认 0.75，决定扩容阈值&lt;/p&gt;
&lt;blockquote class="alert alert-note"&gt;
 &lt;div class="alert-header"&gt;
 &lt;span class="alert-icon"&gt;📝&lt;/span&gt;
 &lt;span class="alert-title"&gt;备注&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="alert-body"&gt;
 &lt;p&gt;0.75 是在空间利用率和查询/插入性能之间的经验折中值。负载因子越大，HashMap 扩容越晚，桶内冲突概率越高（链表或红黑树变长），从而可能降低 &lt;code&gt;get()&lt;/code&gt; 和 &lt;code&gt;put()&lt;/code&gt; 的性能；但同时可以减少扩容次数，降低 rehash 的开销。&lt;/p&gt;
 &lt;/div&gt;
 &lt;/blockquote&gt;
&lt;p&gt;扩容阈值 = capacity × loadFactor&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="两个算法"&gt;两个算法
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;计算元素脚标的算法：数组长度 -1 与 hashcode 值做与运算 &lt;code&gt;(index) = (n - 1) &amp;amp; hash&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;计算 hash 值的算法：&lt;strong&gt;Key 的 hashcode 值无符号右移十六位做异或运算&lt;/strong&gt; &lt;code&gt;hash = h ^ (h &amp;gt;&amp;gt;&amp;gt; 16)&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="成员方法"&gt;成员方法
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;put()&lt;/code&gt;：插入 key-value&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get()&lt;/code&gt;：根据 key 查 value&lt;/li&gt;
&lt;li&gt;&lt;code&gt;remove()&lt;/code&gt;：删除元素&lt;/li&gt;
&lt;li&gt;&lt;code&gt;resize()&lt;/code&gt;：扩容方法&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hash()&lt;/code&gt;：计算 key 的 hash 值（扰动函数，减少冲突）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="hashmap-和-hashtable-的区别"&gt;HashMap 和 HashTable 的区别
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;HashMap 是线程不安全的，多线程环境下同时 put 可能导致数据覆盖、死循环（早期扩容链表反转问题）。
Hashtable 是线程安全的，它的方法基本都加了 &lt;code&gt;synchronized&lt;/code&gt; 锁，但代价是性能较低。现在一般不推荐使用 Hashtable，多线程场景通常用 &lt;code&gt;ConcurrentHashMap&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;HashMap 允许一个 null key 和多个 null value，因为它对 null key 做了特殊处理，不走 hash 计算，而是固定放在 0 号桶。
Hashtable 不允许任何 null key 或 null value，因为它在调用 hash 方法时直接做了 null 检查，避免空指针异常。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="hashmap-中-put-方法的执行流程"&gt;HashMap 中 put 方法的执行流程
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;对 key 进行 hash 计算&lt;/li&gt;
&lt;li&gt;根据 hash 定位数组下标&lt;/li&gt;
&lt;li&gt;如果该位置为空 → 直接插入&lt;/li&gt;
&lt;li&gt;如果不为空 → 发生冲突：
&lt;ul&gt;
&lt;li&gt;key 相同 → 直接覆盖 value&lt;/li&gt;
&lt;li&gt;key 不同 → 挂到链表后面&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;链表长度 ≥ 8 且数组长度 ≥ 64 → 转红黑树&lt;/li&gt;
&lt;li&gt;插入完成后判断是否需要扩容&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="hashmap-线程不安全的体现和解决方案"&gt;HashMap 线程不安全的体现和解决方案
&lt;/h3&gt;&lt;p&gt;体现&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;并发 put 导致数据覆盖&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;两个线程同时操作同一个桶&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;扩容时结构可能异常（JDK7 更严重）&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;多线程 resize 可能导致链表形成环（死循环）&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;size 统计不准确&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;多线程同时修改 size 导致计数错误&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;解决方案&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;使用 ConcurrentHashMap&lt;/strong&gt;（推荐）&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;JDK8：CAS + synchronized（锁粒度更细）&lt;/li&gt;
&lt;li&gt;高并发性能好&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;使用 Collections.synchronizedMap()&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;给整个 Map 加一把大锁&lt;/li&gt;
&lt;li&gt;简单但性能差&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="concurrenthashmap-底层实现和原理"&gt;ConcurrentHashMap 底层实现和原理
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;code&gt;put()&lt;/code&gt; 桶空 CAS + 桶非空 Synchronized&lt;/li&gt;
&lt;li&gt;JDK 7 分段锁（segment），JDK 8 锁链表头节点 + 红黑树树根节点&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="concurrenthashmap-是如何保证线程安全的"&gt;ConcurrentHashMap 是如何保证线程安全的？
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;JDK 7：底层通过 Segment，继承自 ReentrantLock，初始化时有 16 个 Segment，每个 Segment 内部维护 HashEntry 数组（初始容量一般为 2），整体并不是只能存 32 个元素，而是每个 Segment 都可以扩容并存储大量元素，16 个 Segment 只是默认并发度配置。并发控制通过对 Segment 加锁实现，但锁的粒度较大（Segment 级别），在高并发下容易产生竞争，从而影响性能。&lt;/li&gt;
&lt;li&gt;JDK 8：底层采用数组+链表+红黑树结构，通过 CAS + Synchronized 保证线程安全。空桶情况下使用 CAS 进行无锁插入，发生哈希冲突时对桶进行加锁，锁的对象是链表的头节点或红黑树对应的 TreeBin 节点，锁粒度从 Segment 级别细化为桶级别，从而提升并发性能。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="concurrenthashmap-是为何不允许键值为-null"&gt;ConcurrentHashMap 是为何不允许键值为 null？
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;无法区分“key 不存在”和“value 为 null”：&lt;/p&gt;
&lt;p&gt;在 ConcurrentHashMap 中，&lt;code&gt;get(key)&lt;/code&gt; 返回 null 在语义上是模糊的，它既可能表示 key 不存在，也可能表示 key 存在但 value 为 null。在单线程结构里可以通过额外判断来区分，但在并发环境下，这种状态可能在不同线程之间瞬间变化，导致判断结果不可靠，从而引发语义混乱。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;并发操作下 null 无法保证一致性&lt;/p&gt;
&lt;p&gt;ConcurrentHashMap 的 put、remove、resize 都是并发执行的，如果允许 value 为 null，那么一个线程写入 null 的过程中，另一个线程可能同时读取或修改该桶状态，导致无法判断当前看到的 null 是“真实值”、“未完成写入”还是“被删除后的状态”，从而破坏并发读写的一致性语义。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;简化底层实现（CAS + volatile + 红黑树结构）&lt;/p&gt;
&lt;p&gt;ConcurrentHashMap 的核心机制依赖 CAS、volatile 和桶级锁来实现高并发，如果允许 null，会导致 CAS 无法区分“空桶”和“值为 null”的状态，volatile 读到 null 时也无法判断语义，红黑树与链表结构中还需要额外处理 null 节点情况，因此设计上直接禁止 null，从而简化并发控制逻辑并避免边界复杂性。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="jvm"&gt;JVM
&lt;/h2&gt;&lt;p&gt;User.java →（编译）→ User.class → &lt;strong&gt;类加载子系统&lt;/strong&gt;(加载,验证,准备,解析,初始化) → &lt;strong&gt;运行时数据区子系统(程序计数器，方法区，Java 堆，虚拟机栈，本地方法栈) ← 执行引擎子系统&lt;/strong&gt;（方法启动执行和垃圾回收）&lt;/p&gt;
&lt;h3 id="类加载器子系统"&gt;类加载器子系统
&lt;/h3&gt;&lt;p&gt;负责把 &lt;code&gt;.class&lt;/code&gt; 文件加载进 JVM。&lt;/p&gt;
&lt;p&gt;流程包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;加载（Loading）：读取 class 文件，生成 Class 对象&lt;/li&gt;
&lt;li&gt;验证（Verification）：检查字节码是否合法、安全&lt;/li&gt;
&lt;li&gt;准备（Preparation）：为 static 变量分配内存并赋默认值&lt;/li&gt;
&lt;li&gt;解析（Resolution）：符号引用转为直接引用&lt;/li&gt;
&lt;li&gt;初始化（Initialization）：执行 &lt;code&gt;&amp;lt;clinit&amp;gt;&lt;/code&gt;，初始化 static 变量&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="双亲委派"&gt;双亲委派
&lt;/h4&gt;&lt;h5 id="流程"&gt;流程
&lt;/h5&gt;&lt;p&gt;当一个类加载器收到类加载请求时，不会自己先加载，而是先委托给父加载器处理，逐层向上递归，直到启动类加载器（Bootstrap ClassLoader）。如果父加载器无法完成加载，子加载器才会尝试自己加载该类。&lt;/p&gt;
&lt;h5 id="好处"&gt;好处
&lt;/h5&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;避免类的重复加载&lt;/strong&gt;
同一个类不会被不同类加载器重复加载，保证 JVM 中 Class 的唯一性（同一个类在不同加载器下会被认为是不同类）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;保证核心类安全性&lt;/strong&gt;
防止用户自定义类覆盖 Java 核心类，例如 &lt;code&gt;java.lang.String&lt;/code&gt;，因为核心类优先由 Bootstrap ClassLoader 加载。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;保证类加载的层次结构稳定&lt;/strong&gt;
加载顺序具有严格的父子关系，结构清晰，避免混乱的类依赖加载问题。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="为什么-tomcat-和-jdbc-打破了双亲委派"&gt;为什么 tomcat 和 jdbc 打破了双亲委派？
&lt;/h3&gt;&lt;p&gt;tomcat:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Tomcat 是 Web 容器，一个核心需求是：不同 Web 应用之间必须隔离，且允许同名类版本不同，如果遵循双亲委派会导致所有类都会先交给父加载器（AppClassLoader / ExtClassLoader），&lt;strong&gt;所有应用共享同一份类 -&amp;gt; 无法隔离版本&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tomcat 的解决方案：自定义类加载器 + “反向委派”, Tomcat 设计了 WebAppClassLoader：加载顺序变成&lt;strong&gt;先自己找 → 找不到再委派父类&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;目的: 实现 Web 应用隔离（不同 war 包互不影响）,支持同名类不同版本共存, 避免全局污染（尤其是 lib 冲突）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;jdbc:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;JDBC 的核心问题是：接口在 JDK 中，但实现类在第三方驱动中。如果严格双亲委派：DriverManager 在 Bootstrap ClassLoader，MySQL Driver 在 AppClassLoader，Bootstrap 不认识 AppClassLoader 加载的类。&lt;/li&gt;
&lt;li&gt;解决方式：SPI（服务发现机制），JDBC 使用：&lt;code&gt;ServiceLoader + Thread Context ClassLoader&lt;/code&gt;, DriverManager 在启动时不会自己加载具体 Driver, 而是通过：&lt;code&gt;Thread.currentThread().getContextClassLoader()&lt;/code&gt;去加载第三方驱动。&lt;/li&gt;
&lt;li&gt;本质：JDBC 并不是直接破坏双亲委派，而是&lt;strong&gt;绕过默认委派路径，改用线程上下文类加载器主动加载 SPI 实现类&lt;/strong&gt;，从而实现“接口在上层，实现在下层”的解耦结构。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="运行时数据区runtime-data-area"&gt;运行时数据区（Runtime Data Area）
&lt;/h3&gt;&lt;p&gt;JVM 的内存结构，用来存放运行时数据：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;堆（Heap）&lt;/strong&gt;：存对象实例（new 出来的东西）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;方法区（Method Area / MetaSpace）&lt;/strong&gt;：类信息、常量池、static 变量&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;虚拟机栈（Stack）&lt;/strong&gt;：方法调用栈帧（局部变量、方法调用）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;程序计数器（PC Register）&lt;/strong&gt;：记录当前线程执行到哪一行&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;本地方法栈（Native Stack）&lt;/strong&gt;：JNI 调用&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="执行引擎子系统execution-engine"&gt;执行引擎子系统（Execution Engine）
&lt;/h3&gt;&lt;p&gt;负责真正“执行代码”。&lt;/p&gt;
&lt;p&gt;包含：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;解释器（Interpreter）：逐行解释执行 bytecode&lt;/li&gt;
&lt;li&gt;JIT 编译器（Just-In-Time Compiler）：热点代码编译成本地机器码&lt;/li&gt;
&lt;li&gt;GC（垃圾回收器）：回收堆内存对象&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="如何判断一个对象为垃圾对象"&gt;如何判断一个对象为垃圾对象？
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;没有任何“GC Roots”可达的对象，就是垃圾对象。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;GC Roots 常见来源：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;虚拟机栈中的局部变量引用（方法里的对象）&lt;/li&gt;
&lt;li&gt;方法区中的静态变量（static）&lt;/li&gt;
&lt;li&gt;方法区中的常量&lt;/li&gt;
&lt;li&gt;JNI（Native 方法）引用&lt;/li&gt;
&lt;li&gt;正在运行的线程对象&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="内存泄漏和内存溢出有什么区别"&gt;内存泄漏和内存溢出有什么区别？
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;内存泄漏：对象&lt;strong&gt;不再使用&lt;/strong&gt;，但&lt;strong&gt;仍然被引用&lt;/strong&gt;，GC 回收不了，导致内存占用越来越高，最终可能导致 OOM。
&lt;ul&gt;
&lt;li&gt;static 集合一直存对象&lt;/li&gt;
&lt;li&gt;ThreadLocal 没 remove&lt;/li&gt;
&lt;li&gt;缓存无限增长&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;内存溢出（OutOfMemoryError）：JVM 申请不到更多内存了
&lt;ul&gt;
&lt;li&gt;内存泄漏积累&lt;/li&gt;
&lt;li&gt;加载超大对象&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="垃圾回收算法有哪些"&gt;垃圾回收算法有哪些？
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;标记清除：标记所有可达对象，清除未标记对象。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;优点：简单&lt;/li&gt;
&lt;li&gt;缺点：1. 内存碎片严重 2.清理效率不稳定&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;标记复制（新生代常用 s0 s1）：内存分两块，一边用，一边空，存活对象复制到另一块。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;优点：没有碎片，分配快&lt;/li&gt;
&lt;li&gt;缺点：内存浪费一半&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;标记整理（老年代常用）：标记存活对象, 向一端移动，清理边界外内存。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;优点：没有碎片，利用率高。&lt;/li&gt;
&lt;li&gt;缺点：移动对象成本高&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;分代收集&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="垃圾回收器有哪些"&gt;垃圾回收器有哪些？
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;串行垃圾回收器：
&lt;ul&gt;
&lt;li&gt;Serial 新生代 + Serial Old 老年代&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;并行垃圾回收器:
&lt;ul&gt;
&lt;li&gt;Parallel Scavenge 新生代 + Parallel Old 老年代 （JDK 8 默认）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;并发垃圾回收器:
&lt;ul&gt;
&lt;li&gt;ParNew 新生代 + CMS 老年代&lt;/li&gt;
&lt;li&gt;G1 （JDK 9 之后默认）&lt;/li&gt;
&lt;li&gt;ZGC&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;G1 特点和实现：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;堆被划分为多个 Region&lt;/li&gt;
&lt;li&gt;不再严格分代&lt;/li&gt;
&lt;li&gt;优先回收&lt;strong&gt;垃圾最多的区域&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;可预测停顿时间（比如 -XX:MaxGCPauseMillis）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;卡表和记忆集，三色标记法，SATB（Snapshot At The Beginning 解决漏标问题）&lt;/p&gt;
&lt;p&gt;ZGC 特点和实现：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;GC 停顿时间：&lt;strong&gt;通常 &amp;lt; 10ms&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;大部分工作都放到&lt;strong&gt;与用户线程并发执行&lt;/strong&gt;， 只有极少阶段需要 STW&lt;/li&gt;
&lt;li&gt;支持 &lt;strong&gt;TB 级堆内存&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;内存多重映射，染色指针技术，读屏障&lt;/p&gt;
&lt;h3 id="jvm-常用参数"&gt;JVM 常用参数
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;-Xmx1024M 最大堆内存
-Xms1024M 初始化堆内存,正常和最大堆内存相同,减少动态改变的内存损
-Xmn384M 年轻代内存&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;-XX:+PrintGCDetails 打印 gc 信息,可参考 gc 的比例进行调优
-XX:+UseConcMarkSweepGC 老年代使用 cms,标记-清除算法会产生碎片
-XX:+UseParNewGC 年轻代使用并行收集器
-XX:SurvivorRatio=6&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="jvm-调优"&gt;JVM 调优
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;哪些情况会导致 Full GC&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;晋升失败（Survivor 区对象无法进入老年代）&lt;/li&gt;
&lt;li&gt;大对象直接进入老年代（Eden 无法容纳）&lt;/li&gt;
&lt;li&gt;空间分配担保失败（Minor GC 前老年代预估空间不足）&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;项目中哪些情况会导致 OOM&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;静态对象未释放，比如 &lt;code&gt;ThreadLocal&lt;/code&gt; 未调用 &lt;code&gt;remove&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;资源未关闭：数据库连接、网络连接、文件流未使用 &lt;code&gt;try-with-resources&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;一次性加载大量数据：如一次查出百万数据到 &lt;code&gt;List&lt;/code&gt;，或大文件全部加载到内存&lt;/li&gt;
&lt;li&gt;堆内存设置过小：&lt;code&gt;-Xmx&lt;/code&gt; 配置不合理，无法支撑运行负载&lt;/li&gt;
&lt;li&gt;线程池或线程使用不合理：无限制创建线程或队列无界，导致线程数暴涨&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="java-web"&gt;Java Web
&lt;/h2&gt;&lt;h3 id="过滤器filter和拦截器interceptor的区别"&gt;过滤器(Filter)和拦截器(Interceptor)的区别
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;执行时机&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;​ Filter 是 Servlet 规范提供的，作用于 Servlet 容器层面，在&lt;code&gt;DispatcherServlet&lt;/code&gt;执行前就会执行&lt;/p&gt;
&lt;p&gt;​ Interceptor 是 Spring 框架提供的，作用于 Spring MVC 层，在&lt;code&gt;HandlerMapping&lt;/code&gt;匹配之后，Controller 执行前调用&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;实现方式&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;​ Filter 实现&lt;code&gt;javax.servlet.Filter&lt;/code&gt;接口，依赖&lt;code&gt;web.xml&lt;/code&gt;或注解进行注册&lt;/p&gt;
&lt;p&gt;​ Interceptor 实现&lt;code&gt;HandlerInterceptor&lt;/code&gt;接口，通过实现&lt;code&gt;WebMvcConfigurer&lt;/code&gt;的&lt;code&gt;addInterceptors()&lt;/code&gt;方法注册&lt;/p&gt;
&lt;p&gt;总结： 过滤器是 Servlet 规范定义的，依赖 Web 容器（如 Tomcat），在请求进入 Servlet 之前和响应发出之后工作，更底层; 拦截器是 Spring MVC 框架提供的，在请求进入 Controller 之前和视图渲染之后工作，更贴近业务&lt;/p&gt;
&lt;h2 id="常用框架"&gt;常用框架
&lt;/h2&gt;&lt;h3 id="谈谈你对-spring-的理解"&gt;谈谈你对 Spring 的理解
&lt;/h3&gt;&lt;h4 id="广义上"&gt;广义上
&lt;/h4&gt;&lt;p&gt;Spring 指的是 &lt;strong&gt;Spring 全家桶生态（Spring Ecosystem）&lt;/strong&gt;，不仅仅是一个框架，而是一整套企业级开发解决方案。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Spring Framework&lt;/strong&gt;（核心基础）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spring Boot&lt;/strong&gt;（快速开发、自动配置）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spring MVC&lt;/strong&gt;（Web 框架）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spring Data&lt;/strong&gt;（数据访问统一封装）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spring Cloud&lt;/strong&gt;（微服务治理）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spring Security&lt;/strong&gt;（安全认证授权）&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="狭义上"&gt;狭义上
&lt;/h4&gt;&lt;p&gt;Spring 指的是 &lt;strong&gt;Spring Framework 核心容器&lt;/strong&gt;，主要解决的是对象如何创建、如何管理、如何协作的问题。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;IoC（控制反转）：对象的创建和管理交给 Spring 容器，通过 &lt;strong&gt;DI（依赖注入）&lt;/strong&gt; 完成对象装配，解耦对象之间的依赖关系。&lt;/li&gt;
&lt;li&gt;AOP（面向切面编程）：在不修改业务代码的情况下增强功能，如日志、事务、权限、监控，解耦横切逻辑。&lt;/li&gt;
&lt;li&gt;Bean 生命周期管理：Bean 的创建 → 初始化 → 使用 → 销毁，统一由容器管理。&lt;/li&gt;
&lt;li&gt;事件机制 &amp;amp; 扩展机制：支持事件发布监听模式（ApplicationEvent），提供强扩展能力（BeanPostProcessor）&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="谈谈你对-aop-的理解"&gt;谈谈你对 AOP 的理解
&lt;/h3&gt;&lt;p&gt;AOP（面向切面编程）是一种在不修改业务代码的情况下，对日志、事务、权限等横切逻辑进行统一增强的编程思想，本质是通过切面和切点定义增强范围，并借助动态代理将增强逻辑织入目标方法中，实现解耦与复用。&lt;/p&gt;
&lt;h4 id="jdk-动态代理"&gt;JDK 动态代理
&lt;/h4&gt;&lt;p&gt;基于 Java 反射机制实现，要求目标类必须实现接口。通过 &lt;code&gt;InvocationHandler&lt;/code&gt; 对方法调用进行拦截，在方法执行前后织入增强逻辑。&lt;/p&gt;
&lt;h4 id="cglib-动态代理"&gt;CGLib 动态代理
&lt;/h4&gt;&lt;p&gt;基于继承实现代理，通过生成目标类的子类实现方法拦截，使用 &lt;code&gt;MethodInterceptor&lt;/code&gt; 进行增强处理。&lt;/p&gt;
&lt;p&gt;Spring AOP 默认优先使用 JDK 动态代理，只有在没有接口时才使用 CGLIB。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.evorsio&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;java.lang.reflect.Proxy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * @author Evorsio
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * @since 2026/4/18
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JdkProxy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Student&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;study&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Zhangsan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Student&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;study&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;张三正在学习&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Zhangsan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zhangsan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Zhangsan&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ClassLoader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;classLoader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zhangsan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getClass&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getClassLoader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;interfaces&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zhangsan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getClass&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInterfaces&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Student&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Student&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Proxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newProxyInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;classLoader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;interfaces&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;准备开始学习&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zhangsan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;学习完成&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;study&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;控制台输出&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;C:&lt;span class="se"&gt;\U&lt;/span&gt;sers&lt;span class="se"&gt;\A&lt;/span&gt;dmin&lt;span class="se"&gt;\.&lt;/span&gt;jdks&lt;span class="se"&gt;\m&lt;/span&gt;s-17.0.18&lt;span class="se"&gt;\b&lt;/span&gt;in&lt;span class="se"&gt;\j&lt;/span&gt;ava.exe &lt;span class="s2"&gt;&amp;#34;-javaagent:D:\JetBrains\IntelliJ IDEA\lib\idea_rt.jar=60217&amp;#34;&lt;/span&gt; -Dfile.encoding&lt;span class="o"&gt;=&lt;/span&gt;UTF-8 -classpath D:&lt;span class="se"&gt;\J&lt;/span&gt;etBrainsProjects&lt;span class="se"&gt;\I&lt;/span&gt;deaProjects&lt;span class="se"&gt;\j&lt;/span&gt;ava-demo&lt;span class="se"&gt;\t&lt;/span&gt;arget&lt;span class="se"&gt;\c&lt;/span&gt;lasses com.evorsio.JdkProxy
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;准备开始学习
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;张三正在学习
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;学习完成
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Process finished with &lt;span class="nb"&gt;exit&lt;/span&gt; code &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="谈谈你对-ioc控制反转的理解"&gt;谈谈你对 IoC（控制反转）的理解
&lt;/h3&gt;&lt;p&gt;IoC（控制反转）是一种设计思想，将对象的创建和依赖关系的控制权交给容器管理，在 Spring 中通过依赖注入(DI)实现，从而实现对象之间的解耦和统一管理。&lt;/p&gt;
&lt;h3 id="依赖注入方式"&gt;依赖注入方式
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;字段注入：（&lt;code&gt;@Autowired&lt;/code&gt;&lt;strong&gt;Spring 提供的按类型注入&lt;/strong&gt;，&lt;code&gt;@Resource&lt;/code&gt;&lt;strong&gt;JDK 提供的按名称优先注入&lt;/strong&gt;。）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;构造器注入：（推荐）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Setter 方法注入&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="循环依赖问题和解决办法"&gt;循环依赖问题和解决办法
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Autowired&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;B&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Autowired&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="三个缓存"&gt;三个缓存
&lt;/h4&gt;&lt;p&gt;Spring 通过&lt;strong&gt;三级缓存机制&lt;/strong&gt;解决单例 Bean 的循环依赖：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;一级缓存（&lt;code&gt;singletonObjects = new ConcurrentHashMap(256)&lt;/code&gt;）：已初始化完成的 Bean&lt;/li&gt;
&lt;li&gt;二级缓存（&lt;code&gt;earlySingletonObjects = new ConcurrentHashMap(16)&lt;/code&gt;）：提前暴露的半成品 Bean 引用（可能是原始对象或代理对象）&lt;/li&gt;
&lt;li&gt;三级缓存（&lt;code&gt;singletonFactories = new HashMap(16)&lt;/code&gt;）：用于生成早期 Bean 的工厂对象（支持 AOP 代理提前暴露）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;流程&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Spring 创建 A 时，先从一级缓存 &lt;code&gt;singletonObjects&lt;/code&gt; 获取 A，未命中，则标记 A 为“正在创建”，进入创建流程。&lt;/li&gt;
&lt;li&gt;A 实例化（构造方法执行）后，Spring 不会直接暴露对象，而是将 &lt;code&gt;ObjectFactory(A)&lt;/code&gt; 放入三级缓存 &lt;code&gt;singletonFactories&lt;/code&gt;，用于后续生成 A 的早期引用。&lt;/li&gt;
&lt;li&gt;A 执行 &lt;code&gt;populateBean&lt;/code&gt; 进行属性填充时，发现依赖 B，触发 &lt;code&gt;getBean(B)&lt;/code&gt;，开始创建 B。&lt;/li&gt;
&lt;li&gt;B 创建流程与 A 一致：实例化后将 &lt;code&gt;ObjectFactory(B)&lt;/code&gt; 放入三级缓存，并开始属性填充。&lt;/li&gt;
&lt;li&gt;B 在 &lt;code&gt;populateBean&lt;/code&gt; 时发现依赖 A，此时触发获取 A：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;一级缓存无&lt;/li&gt;
&lt;li&gt;二级缓存无&lt;/li&gt;
&lt;li&gt;三级缓存存在 A 的 ObjectFactory
Spring 调用 &lt;code&gt;getObject()&lt;/code&gt; 得到 A 的早期引用（可能是代理对象），并放入二级缓存 &lt;code&gt;earlySingletonObjects&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="6"&gt;
&lt;li&gt;B 完成初始化后进入一级缓存；A 随后完成属性填充与初始化，最终进入一级缓存，同时清理二级、三级缓存中的 A，循环依赖解决完成。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="四个方法"&gt;四个方法
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;&lt;code&gt;getBean()&lt;/code&gt; -&amp;gt; &lt;code&gt;doGetBean()&lt;/code&gt; -&amp;gt; &lt;code&gt;getSingleton()&lt;/code&gt; 从缓存中获取 Bean 对象。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;createBean()&lt;/code&gt; -&amp;gt; &lt;code&gt;doGetBean()&lt;/code&gt; -&amp;gt; &lt;code&gt;createBeanInstance()&lt;/code&gt; 创建 Bean 对象。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;populateBean()&lt;/code&gt;初始化 Bean 对象&lt;/li&gt;
&lt;li&gt;&lt;code&gt;addSingleton()&lt;/code&gt; 将 Bean 对象保存到缓存中&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果需要循环依赖，可以手动开启 &lt;code&gt;spring.main.allow-circular-references=true&lt;/code&gt;，&lt;/p&gt;
&lt;p&gt;默认在 Spring Boot 2.6 之后是关闭的&lt;/p&gt;
&lt;h3 id="spring-常用注解"&gt;Spring 常用注解
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;IoC 相关注解: &lt;code&gt;@Component&lt;/code&gt; &lt;code&gt;@Autowired&lt;/code&gt; &lt;code&gt;@Configuration&lt;/code&gt; &lt;code&gt;@Bean&lt;/code&gt; &lt;code&gt;@Value&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;AOP 相关注解: &lt;code&gt;@Transactional&lt;/code&gt; &lt;code&gt;@Aspect&lt;/code&gt; &lt;code&gt;@Before&lt;/code&gt; &lt;code&gt;@After&lt;/code&gt; &lt;code&gt;@AfterReturning&lt;/code&gt; &lt;code&gt;@AfterThrowing&lt;/code&gt; &lt;code&gt;@Around&lt;/code&gt; &lt;code&gt;@Pointcut&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="spring-bean-的作用域有哪些"&gt;Spring Bean 的作用域有哪些？
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;singleton（单例，默认）&lt;/li&gt;
&lt;li&gt;prototype（原型）：每次获取都会创建一个新对象，不由容器统一管理完整生命周期。&lt;/li&gt;
&lt;li&gt;request（Web 环境）：每个 HTTP 请求创建一个 Bean，请求结束后销毁。&lt;/li&gt;
&lt;li&gt;session（Web 环境）：每个 HTTP Session 创建一个 Bean，Session 结束后销毁。&lt;/li&gt;
&lt;li&gt;application：整个 Web 应用生命周期内只有一个 Bean，类似 ServletContext 级别。&lt;/li&gt;
&lt;li&gt;websocket：每个 WebSocket 会话对应一个 Bean。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="spring-bean-的生命周期有哪些"&gt;Spring Bean 的生命周期有哪些？
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.evorsio.springdemo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * @author Evorsio
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * @since 2026/4/18
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;userA: 使用userA对象: User{&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;username=&amp;#39;&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;\&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;}&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;setUsername&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;userA: 调用setter方法,对username属性进行赋值&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;User&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;userA: 调用无参构造&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;userA: 调用有参构造&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;userA: 调用初始化方法,对userA对象进行初始化&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;userA: 调用销毁方法&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.evorsio.springdemo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.jspecify.annotations.Nullable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.springframework.beans.BeansException&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.springframework.beans.factory.config.BeanPostProcessor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * @author Evorsio
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * @since 2026/4/18
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyBeanPostProcessor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BeanPostProcessor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Nullable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;postProcessBeforeInitialization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;beanName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;throws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BeansException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;myBeanPostProcessor: 对&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;beanName&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;对象初始化前执行的操作&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BeanPostProcessor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;postProcessBeforeInitialization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;beanName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Nullable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;postProcessAfterInitialization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;beanName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;throws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BeansException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;myBeanPostProcessor: 对&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;beanName&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;对象初始化后执行的操作&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BeanPostProcessor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;postProcessAfterInitialization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;beanName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;beans&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;http://www.springframework.org/schema/beans&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="na"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;http://www.w3.org/2001/XMLSchema-instance&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="na"&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&amp;#34;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;bean&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;userA&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;com.evorsio.springdemo.User&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;init-method=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;init&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;destroy-method=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;destroy&amp;#34;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;property&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;username&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;zhangsan&amp;#34;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/bean&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;bean&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;myBeanPostProcessor&amp;#34;&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;com.evorsio.springdemo.MyBeanPostProcessor&amp;#34;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/beans&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.evorsio.springdemo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.springframework.context.support.ClassPathXmlApplicationContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SpringDemoApplication&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ClassPathXmlApplicationContext&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ClassPathXmlApplicationContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;spring.xml&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;userA&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userA&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;流程&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;C:&lt;span class="se"&gt;\U&lt;/span&gt;sers&lt;span class="se"&gt;\A&lt;/span&gt;dmin&lt;span class="se"&gt;\.&lt;/span&gt;jdks&lt;span class="se"&gt;\m&lt;/span&gt;s-17.0.18&lt;span class="se"&gt;\b&lt;/span&gt;in&lt;span class="se"&gt;\j&lt;/span&gt;ava.exe ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;com.evorsio.springdemo.SpringDemoApplication
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1. userA: 调用无参构造
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2. userA: 调用setter方法,对username属性进行赋值
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3. myBeanPostProcessor: 对userA对象初始化前执行的操作
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4. userA: 调用初始化方法,对userA对象进行初始化
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;5. myBeanPostProcessor: 对userA对象初始化后执行的操作
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;6. userA: 使用userA对象: User&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;zhangsan&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;7. userA: 调用销毁方法
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Process finished with &lt;span class="nb"&gt;exit&lt;/span&gt; code &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="spring-cloud"&gt;Spring Cloud
&lt;/h2&gt;&lt;h3 id="项目中使用了哪些-spring-cloud-组件"&gt;项目中使用了哪些 Spring Cloud 组件？
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;Nacos 注册中心 + 配置中心&lt;/li&gt;
&lt;li&gt;OpenFeign 声明式远程调用&lt;/li&gt;
&lt;li&gt;Spring Cloud Gateway 全局网关&lt;/li&gt;
&lt;li&gt;Sentinel 限流熔断降级&lt;/li&gt;
&lt;li&gt;LoadBalancer 负载均衡&lt;/li&gt;
&lt;li&gt;Sleuth 链路追踪( Spring Boot 3 中被移除 ，改用 Micrometer Tracing + OpenTelemtry ) + Zipkin 进行链路可视化。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="open-feign-和-feign-的区别"&gt;Open Feign 和 Feign 的区别
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;Feign 是 Netflix 早期的声明式 HTTP 客户端，不支持 Spring MVC 注解，不再维护。&lt;/li&gt;
&lt;li&gt;OpenFeign 是 Spring Cloud 对 Feign 的增强版本，深度集成了 Spring 生态，支持 Spring MVC 注解、服务发现、负载均衡和熔断机制，是目前微服务中主流的远程调用方式，社区依然活跃。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="实际开发过程中-openfeign-请求头丢失的问题"&gt;实际开发过程中 OpenFeign 请求头丢失的问题
&lt;/h3&gt;&lt;p&gt;消费方通过 OpenFeign 调用生产方接口时，Feign 底层会&lt;strong&gt;重新发起一个新的 HTTP 请求&lt;/strong&gt;，而不是在原请求基础上进行转发，原始请求中的 Header（如 Token、用户信息、TraceId 等）不会自动携带到新的 Feign 请求中，导致请求头信息丢失或不一致。&lt;/p&gt;
&lt;p&gt;Spring 中的请求上下文是通过 &lt;strong&gt;RequestContextHolder&lt;/strong&gt;（基于 ThreadLocal）存储的，在 Feign 调用过程中不会自动传播，因此需要通过 RequestInterceptor 手动从 &lt;strong&gt;RequestContextHolder&lt;/strong&gt; 获取原始请求 Header 并进行透传。&lt;/p&gt;
&lt;p&gt;基本用法：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;导入依赖: spring-cloud-starter-alibaba-nacos-discovery&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;配置 Nacos 地址: &lt;code&gt;spring.cloud.nacos.discovery.server-addr = localhost:8848&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@EnableFeignClients&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@SpringBootApplication&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderApplication&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@FeignClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;stock-nacos&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fallback&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StockFeignFallback&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;StockFeignClient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;/stock/reduce&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;reduceStock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StockFeignFallback&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StockFeignClient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;reduceStock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;库存服务降级，当前不可用&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="项目中哪些场景使用到了-spring-cloud-gateway-的功能"&gt;项目中哪些场景使用到了 Spring Cloud Gateway 的功能？
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;项目中将网关作为一个独立的功能进行部署，基于路径断言将请求通过负载均衡的方式进行分发。&lt;/li&gt;
&lt;li&gt;全局的跨域问题处理（由于浏览器的同源策略导致），使用 &lt;code&gt;spring.cloud.gateway.globalcors.cors-configurations.[/**].allowed-origins=*&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;通过实现网关的全局过滤进行身份验证&lt;/li&gt;
&lt;li&gt;配置限流&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;组成：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Route（路由）: 定义请求转发规则&lt;/li&gt;
&lt;li&gt;Predicate（断言）: 判断请求是否匹配（路径、Header、参数）&lt;/li&gt;
&lt;li&gt;Filter（过滤器）: 请求前后处理逻辑（鉴权、日志、限流）&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="有了-nginx-为什么还需要网关呢"&gt;有了 Nginx 为什么还需要网关呢？
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;Nginx 主要负责：反向代理，静态资源托管，负载均衡，SSL/TLS 等，只管“流量怎么走”，不关心“业务是什么”。&lt;/li&gt;
&lt;li&gt;Spring Cloud Gateway 负责：统一 API 入口，路由转发，JWT 鉴权 / 登录校验等，关注“业务请求如何被处理”，服务于微服务。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="请求过来之后如何进行流量控制"&gt;请求过来之后如何进行流量控制？
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;客户端削峰填谷： 前端限流（按钮置灰），请求缓存&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;网关层限流：RequestRateLimiter&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;spring&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;cloud&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;gateway&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;order-service&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;lb://order-service&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;predicates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;Path=/order/**&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;filters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# =========================&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 限流 RequestRateLimiter&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# =========================&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;RequestRateLimiter&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;redis-rate-limiter.replenishRate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 每秒放入令牌数（QPS）&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;redis-rate-limiter.burstCapacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 最大突发流量&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;key-resolver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;#{@ipKeyResolver}&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;应用层限流： Sentinel（ 限制 QPS 或者线程数 ）&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@SentinelResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;getOrder&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;blockHandler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;blockHandlerMethod&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fallback&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;fallbackMethod&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;getOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;正常业务逻辑&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;blockHandlerMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BlockException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;请求过多，请稍后重试&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;fallbackMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;系统异常，已降级处理&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;服务熔断与降级：Open Feign 熔断降级&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="nacos-作为服务注册和配置中心的原理"&gt;Nacos 作为服务注册和配置中心的原理
&lt;/h3&gt;&lt;h4 id="启动参数"&gt;启动参数
&lt;/h4&gt;&lt;p&gt;-Dnacos.standalone=true&lt;/p&gt;
&lt;h4 id="服务注册"&gt;服务注册
&lt;/h4&gt;&lt;p&gt;客户端（服务提供者）启动后：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;向 Nacos Server 发送注册请求&lt;/li&gt;
&lt;li&gt;请求内容包含：serviceName、ip、port、metadata&lt;/li&gt;
&lt;li&gt;数据通过 HTTP REST 接口发送&lt;/li&gt;
&lt;li&gt;Server 使用 request 对象接收参数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注册完成后：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;服务实例被存入 Nacos 内存注册表&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="服务健康检测"&gt;服务健康检测
&lt;/h4&gt;&lt;p&gt;Nacos Server 会定时执行健康检查任务：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;检查所有注册实例的心跳时间&lt;/li&gt;
&lt;li&gt;判断实例是否存活&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;判断规则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当前时间 - 最后心跳时间 &amp;gt; 15 秒 → 标记为不健康&lt;/li&gt;
&lt;li&gt;当前时间 - 最后心跳时间 &amp;gt; 30 秒 → 从注册表移除实例&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="服务心跳任务client"&gt;服务心跳任务（Client）
&lt;/h4&gt;&lt;p&gt;客户端在服务注册后会启动心跳任务：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每 5 秒发送一次心跳请求&lt;/li&gt;
&lt;li&gt;请求接口：beat（REST）&lt;/li&gt;
&lt;li&gt;通过定时 + 延迟任务实现&lt;/li&gt;
&lt;li&gt;作用：告诉 Server 当前服务仍然存活&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="客户端服务发现"&gt;客户端服务发现
&lt;/h4&gt;&lt;p&gt;服务消费者（Nacos Client）调用服务时：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;向 Nacos Server 发送 REST 请求&lt;/li&gt;
&lt;li&gt;获取服务实例列表&lt;/li&gt;
&lt;li&gt;将结果缓存到本地（serviceInfoMap）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;同时：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在本地启动定时任务&lt;/li&gt;
&lt;li&gt;周期性拉取服务端最新注册表&lt;/li&gt;
&lt;li&gt;更新本地缓存&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="nacos-1x-和-2x-的区别"&gt;Nacos 1.x 和 2.x 的区别
&lt;/h3&gt;&lt;p&gt;1.x 基于 HTTP + 定时任务（心跳、轮询）；2.x 引入 gRPC 长连接 + 事件驱动模型，支持服务变更实时推送。&lt;/p&gt;
&lt;h3 id="除了-nacos-还有那些注册中心"&gt;除了 Nacos 还有那些注册中心
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;Eureka（Netflix）：AP（高可用），去中心化设计（Peer-to-Peer，无主节点，节点对等，数据通过复制实现同步）。&lt;/li&gt;
&lt;li&gt;Zookeeper（Apache）：CP（强一致），Leader 选举机制（集群选举主节点负责协调，保证一致性）。&lt;/li&gt;
&lt;li&gt;Nacos：AP/CP 可切换，默认 AP；同时支持注册中心 + 配置中心，采用临时实例（心跳）+ 长轮询/推送机制实现服务发现。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="mysql"&gt;MySQL
&lt;/h2&gt;&lt;h3 id="如何进行-sql-优化"&gt;如何进行 SQL 优化
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;慢查询定位：开启慢查询日志定位慢 SQL，通常 0.5 秒（默认 10 秒）开始，但应该根据业务类型和性能要求调整。&lt;/li&gt;
&lt;li&gt;explain 指令查看执行计划：
&lt;ul&gt;
&lt;li&gt;id: SQL 执行的顺序与层级, id 相同：从上到下执行, id 不同：数字大的先执行（子查询）。&lt;/li&gt;
&lt;li&gt;type: 查询类型一旦为 ALL（全表扫描）则必须优化，合理取值 ref（普通索引查询）,eq_ref（唯一索引 join）,range（范围查询）,index（对整个索引进行扫描）。&lt;/li&gt;
&lt;li&gt;key：真正使用到的索引&lt;/li&gt;
&lt;li&gt;key_len：索引使用的长度&lt;/li&gt;
&lt;li&gt;rows：为了获取结果所需要扫描的行数&lt;/li&gt;
&lt;li&gt;extra：主要用于分析分组和排序操作，using index（使用覆盖索引，不需要回表查询数据行，性能好），using where（where 的条件没有用到索引），using filesort（使用磁盘排序），using index condition（使用索引下推优化，在存储引擎层提前过滤数据，减少回表次数）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;可以通过 &lt;code&gt;key&lt;/code&gt; 和 &lt;code&gt;key_len&lt;/code&gt; 判断是否命中了索引以及索引是否被完整使用，从而发现索引是否失效；通过 &lt;code&gt;type&lt;/code&gt; 判断 SQL 的访问方式和扫描类型，评估是否存在全表扫描或全索引扫描等优化空间；再结合 &lt;code&gt;extra&lt;/code&gt; 字段判断执行细节，例如 &lt;code&gt;Using index&lt;/code&gt; 表示覆盖索引无需回表，&lt;code&gt;Using where&lt;/code&gt; 表示条件可能未充分利用索引，&lt;code&gt;Using filesort&lt;/code&gt; 表示排序或分组未走索引需要优化，整体通过这些字段综合判断 SQL 是否需要优化以及优化方向。&lt;/p&gt;
&lt;h3 id="合理创建索引"&gt;合理创建索引
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;表数据量达到一定规模（ 15 万以上），才具备明显优化意义&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;考虑性价比更高的复合索引设计&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;尽量让查询走覆盖索引以减少回表&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;需要重点关注索引失效的场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;未遵循最左匹配原则&lt;/li&gt;
&lt;li&gt;模糊查询中 &lt;code&gt;%&lt;/code&gt; 在左边&lt;/li&gt;
&lt;li&gt;对索引字段使用函数或发生类型转换&lt;/li&gt;
&lt;li&gt;范围查询导致右边索引失效&lt;/li&gt;
&lt;li&gt;以及 &lt;code&gt;is not null&lt;/code&gt; 等导致扫描范围过大的情况&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在关联查询中，应尽量选择小表作为驱动表，并为关联字段创建索引以提升 join 查询效率。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;编写 SQL 语句时避免使用 select *，防止全表扫描或多余回表查询。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;表关联查询优先使用 inner join，避免不必要的 left/right join，如需使用也应以小表为驱动表。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;排序字段尽量保持一致的排序规则（避免一列升序一列降序），以便索引生效。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;建表时结合字段内容选择合适类型&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数值：&lt;code&gt;TINYINT&lt;/code&gt;：很小的整数（状态位、标志位），&lt;code&gt;INT&lt;/code&gt;：常用整数（默认选择），&lt;code&gt;BIGINT&lt;/code&gt;：大数据量 ID（如雪花 ID）&lt;/li&gt;
&lt;li&gt;字符串：&lt;code&gt;CHAR(n)&lt;/code&gt;：长度固定（如手机号、身份证），&lt;code&gt;VARCHAR(n)&lt;/code&gt;：长度可变（最常用），&lt;code&gt;TEXT&lt;/code&gt;：大文本（不建议频繁索引）&lt;/li&gt;
&lt;li&gt;价格：不要用 FLOAT / DOUBLE（会有精度问题）推荐：&lt;code&gt;DECIMAL(m,n)&lt;/code&gt;，m：总位数 n：小数位数&lt;/li&gt;
&lt;li&gt;时间：用于时间记录（创建时间、更新时间等）&lt;code&gt;DATE&lt;/code&gt;：日期（2026-04-19），&lt;code&gt;DATETIME&lt;/code&gt;：日期+时间（推荐），&lt;code&gt;TIMESTAMP&lt;/code&gt;：时间戳（带时区转换）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="b-tree-和-btree-的区别"&gt;B-Tree 和 B+Tree 的区别
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;B-Tree：所有节点（非叶子 + 叶子）都存储数据，每个节点既存 key 也存 data。&lt;/li&gt;
&lt;li&gt;B+Tree: 只有叶子节点存数据，非叶子节点只存索引（key）。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="btree-的优点"&gt;B+Tree 的优点
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;B+Tree 数据全部存储在叶子节点，非叶子节点只存索引，因此单个节点可以容纳更多的索引项，从而降低树的高度，减少磁盘 IO 次数，提升查询效率。&lt;/li&gt;
&lt;li&gt;B+Tree 叶子节点之间通过双向指针相连，可以非常高效地进行&lt;strong&gt;范围查询和顺序遍历&lt;/strong&gt;，可以直接在叶子层顺序向前或向后扫描，从而显著减少磁盘 IO，提高查询性能。同时双向结构还支持反向遍历，进一步增强查询灵活性。&lt;/li&gt;
&lt;li&gt;B+Tree 查询路径固定，每次查询都必须从根节点一路访问到叶子节点，每一层只进行一次节点匹配，因此整体查询次数是稳定且可预测的。&lt;/li&gt;
&lt;li&gt;B+Tree 通常在 3 层结构下就可以存储约 2000 万级别的数据。&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote class="alert alert-note"&gt;
 &lt;div class="alert-header"&gt;
 &lt;span class="alert-icon"&gt;📝&lt;/span&gt;
 &lt;span class="alert-title"&gt;备注&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="alert-body"&gt;
 &lt;p&gt;InnoDB 一个页（page）默认大小：&lt;strong&gt;16KB = 16384 bytes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;非叶子节点存只存索引 key（BIGINT = 8 bytes）和指针（通常 6-8 bytes）&lt;/p&gt;
&lt;p&gt;每个节点能存多少“分支”：16384 / 16 ≈ 1000 个指针&lt;/p&gt;
&lt;p&gt;三层 B+Tree 推导：1000 × 1000 × 16（ 一行 ≈ 1KB）≈ 2000 万&lt;/p&gt;
 &lt;/div&gt;
 &lt;/blockquote&gt;
&lt;h3 id="什么是回表"&gt;什么是回表
&lt;/h3&gt;&lt;p&gt;通过二级索引（非聚簇索引）找到主键后，还需要再回到主键索引（聚簇索引）中查询完整数据行的过程。&lt;/p&gt;
&lt;h3 id="select--查询一定会回表吗"&gt;Select * 查询一定会回表吗？
&lt;/h3&gt;&lt;p&gt;不一定会回表，如果查询条件是主键索引（聚簇索引），例如 &lt;code&gt;where id = ?&lt;/code&gt;，MySQL 会直接在聚簇索引中找到整行数据，因此不会发生回表；只有在使用二级索引查询且无法覆盖所有字段时，才会发生回表。&lt;/p&gt;
&lt;h3 id="mysql-深分页超大分页问题如何优化"&gt;MySQL 深分页（超大分页）问题如何优化？
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;游标分页：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;last_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;LIMIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;通过记录上一页最后一条数据的主键（如 &lt;code&gt;last_id&lt;/code&gt;），作为下一页查询的起点，利用索引有序性进行范围查询。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;延迟关联（子查询优化）&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIMIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;先通过子查询在索引中只查询主键（小结果集），再通过主键与原表关联回表获取完整数据，从而减少大范围扫描带来的性能损耗。&lt;/p&gt;
&lt;h3 id="什么是索引下推原理"&gt;什么是索引下推，原理？
&lt;/h3&gt;&lt;p&gt;索引下推是 MySQL（InnoDB）的一种优化机制，核心思想是：在存储引擎层就先用索引过滤数据，减少回表次数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;A%&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;先用索引（如 name）定位数据范围&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在&lt;strong&gt;索引层同时判断 age = 20&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;只把满足条件的记录回表查询完整数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;减少无效回表次数，提高性能&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="innodb-和-myisam-的区别"&gt;InnoDB 和 MyISAM 的区别
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;对比项&lt;/th&gt;
 &lt;th&gt;InnoDB&lt;/th&gt;
 &lt;th&gt;MyISAM&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;事务&lt;/td&gt;
 &lt;td&gt;✔ 支持（ACID）&lt;/td&gt;
 &lt;td&gt;❌ 不支持&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;锁机制&lt;/td&gt;
 &lt;td&gt;行级锁&lt;/td&gt;
 &lt;td&gt;表级锁&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;外键&lt;/td&gt;
 &lt;td&gt;✔ 支持&lt;/td&gt;
 &lt;td&gt;❌ 不支持&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;崩溃恢复&lt;/td&gt;
 &lt;td&gt;✔ 支持（redo log）&lt;/td&gt;
 &lt;td&gt;❌ 不支持&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;索引结构&lt;/td&gt;
 &lt;td&gt;聚簇索引&lt;/td&gt;
 &lt;td&gt;非聚簇索引&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;查询性能&lt;/td&gt;
 &lt;td&gt;稍慢（但稳定）&lt;/td&gt;
 &lt;td&gt;快（读多场景）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="数据库三大范式"&gt;数据库三大范式
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;第一范式（1NF）：字段必须是&lt;strong&gt;不可再分的原子值&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;第二范式（2NF）：每个非主键字段必须&lt;strong&gt;完全依赖主键&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;第三范式（3NF）：非主键字段之间不能传递依赖&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="事务特性acid"&gt;事务特性（ACID）
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;A - Atomicity（原子性）：事务中的操作要么全部执行成功，要么全部失败回滚，通过 &lt;code&gt;undo log&lt;/code&gt; 保证回滚能力。&lt;/li&gt;
&lt;li&gt;C - Consistency（一致性）：事务执行前后，数据必须从一个合法状态转换到另一个合法状态，保证数据符合业务规则。&lt;/li&gt;
&lt;li&gt;I - Isolation（隔离性）：多个事务并发执行时互不干扰，通过 &lt;code&gt;锁机制（排他锁等）&lt;/code&gt; 和 &lt;code&gt;MVCC&lt;/code&gt; 保证并发隔离。&lt;/li&gt;
&lt;li&gt;D - Durability（持久性）：事务一旦提交，数据就会永久保存，即使系统崩溃也不会丢失，通过 &lt;code&gt;redo log&lt;/code&gt; 保证。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="事务隔离级别和解决的问题"&gt;事务隔离级别和解决的问题
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;读未提交（Read Uncommitted）&lt;/strong&gt;：不解决任何并发问题，可能出现脏读、不可重复读、幻读。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;读已提交（Read Committed）&lt;/strong&gt;：（Oracle 默认）解决脏读，但仍可能出现不可重复读和幻读，适合银行业务对资金实时业务的要求。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;可重复读（Repeatable Read）&lt;/strong&gt;（MySQL 默认）：解决脏读和不可重复读，通过 MVCC + 间隙锁在一定程度上避免幻读，适合互联网电商业务“强一致读场景”。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;串行化（Serializable）&lt;/strong&gt;：完全解决脏读、不可重复读和幻读，通过强制事务串行执行实现最高隔离级别，但并发性能最差。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="分布式事务"&gt;分布式事务
&lt;/h3&gt;&lt;p&gt;分布式事务是指跨多个服务或数据库的事务一致性问题，无法依赖本地事务实现，常见解决方案是基于最终一致性的方案，如消息队列和 Seata。&lt;/p&gt;
&lt;h3 id="长事务问题"&gt;长事务问题
&lt;/h3&gt;&lt;p&gt;事务执行时间过长，持有锁或版本过久未释放的情况&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;占用数据库连接资源&lt;/li&gt;
&lt;li&gt;锁持有时间长，导致阻塞和死锁概率增加&lt;/li&gt;
&lt;li&gt;undo log / MVCC 版本堆积，影响性能&lt;/li&gt;
&lt;li&gt;可能导致数据库性能整体下降&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;优化思路：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;拆分大事务（拆成多个小事务）&lt;/li&gt;
&lt;li&gt;避免事务中包含远程调用&lt;/li&gt;
&lt;li&gt;减少锁持有时间&lt;/li&gt;
&lt;li&gt;异步化处理非核心逻辑&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="mysql-的-mvcc-会导致表膨胀吗"&gt;MySQL 的 MVCC 会导致表膨胀吗？
&lt;/h3&gt;&lt;p&gt;MySQL 的 MVCC 通过 undo log 记录数据的历史版本，并结合 Read View 判断可见性，同时依赖 purge 线程在没有活跃事务引用旧版本时清理 undo log，从而避免历史版本无限增长导致的空间膨胀。&lt;/p&gt;
&lt;p&gt;此外，对于&lt;strong&gt;删除操作&lt;/strong&gt;，InnoDB 并不会立即物理删除数据，而是先做“标记删除”，旧版本仍通过 undo log 保留；当 purge 线程确认没有事务再引用该版本后，才会真正物理删除该记录，并将这块空间&lt;strong&gt;标记为可复用（供后续插入使用）&lt;/strong&gt;，从而避免空间浪费。&lt;/p&gt;
&lt;p&gt;但如果存在长事务，会导致旧版本无法被清理，进而造成 undo log 堆积和空间占用增加。&lt;/p&gt;
&lt;h3 id="mysql-中的锁"&gt;MySQL 中的锁
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;锁性质&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;悲观锁：假设会发生冲突，先加锁再操作，通过数据库锁机制实现（如 &lt;code&gt;SELECT ... FOR UPDATE&lt;/code&gt;），适用于写多、冲突概率高的场景。&lt;/li&gt;
&lt;li&gt;乐观锁：假设不会冲突，提交时再检查，通常通过版本号（version）或 CAS 实现，适用于读多写少的场景。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;
&lt;p&gt;锁粒度&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;表级锁：锁整张表，开销小，实现简单，但并发性能低，常见于 MyISAM 引擎。&lt;/li&gt;
&lt;li&gt;行级锁：锁具体某一行数据，并发能力强，粒度最小，InnoDB 默认使用（提升并发性能）。&lt;/li&gt;
&lt;li&gt;意向锁（InnoDB 特有）：是一种“表级的标记锁”，用于表示某个事务&lt;strong&gt;即将对某些行加锁&lt;/strong&gt;，不直接锁数据，只是“声明意图”，避免表锁与行锁冲突，提高加锁效率。
&lt;ol&gt;
&lt;li&gt;意向共享锁（IS）：表示“事务准备在某些行上加共享锁”，读操作前会加。&lt;/li&gt;
&lt;li&gt;意向排他锁（IX）：表示“事务准备在某些行上加排他锁”，写操作前会加。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;锁类型&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;共享锁（S 锁）：读锁，多个事务可以同时持有，读读不冲突，但读写冲突。&lt;/li&gt;
&lt;li&gt;排他锁（X 锁）：写锁，同一时间只能一个事务持有，写写、读写都会冲突。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="如何进行数据库数据迁移"&gt;如何进行数据库数据迁移？
&lt;/h3&gt;&lt;h4 id="迁移方案"&gt;迁移方案
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;停机一次性迁移：停止业务写入，进行全量数据导出（mysqldump / pg_dump），导入新库后切换应用连接，适用于小数据量或可接受停机的场景。&lt;/li&gt;
&lt;li&gt;在线分批次迁移：采用“全量 + 增量”方式，先迁移历史数据，再通过 binlog/CDC（如 Canal）同步增量数据，最后灰度切换流量，适用于大规模或不能停机的系统。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="迁移过程可能导致的问题"&gt;迁移过程可能导致的问题
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;数据一致性问题：迁移期间仍有写入，导致新旧库数据不一致或延迟同步问题。&lt;/li&gt;
&lt;li&gt;应用兼容性问题：新旧库表结构或 SQL 语法不一致，导致接口报错或查询异常。&lt;/li&gt;
&lt;li&gt;性能抖动问题：全量导入或 binlog 同步造成数据库 IO 和网络压力上升，影响线上业务。&lt;/li&gt;
&lt;li&gt;回滚困难问题：若未保留旧库或未做双写，切换后出现问题难以快速回退。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="如何减少迁移过程对用户体验的影响"&gt;如何减少迁移过程对用户体验的影响
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;兼容性测试：在迁移前进行 SQL 兼容性、表结构、接口回归测试，确保新旧库在读写行为上一致。&lt;/li&gt;
&lt;li&gt;采用“全量+增量“的同步方案：先进行历史数据全量迁移，再通过 binlog / CDC（如 Canal）同步增量数据，保证业务不中断。&lt;/li&gt;
&lt;li&gt;设计灰度切换：通过按用户比例或业务模块逐步切换流量到新库，降低整体切换风险。&lt;/li&gt;
&lt;li&gt;监控与回滚预案：全程监控延迟、错误率、数据一致性等指标，一旦异常可快速切回旧库，保证业务可恢复性。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一般会做全量迁移，再做增量同步，分阶段灰度切换流量，监控数据一致性和业务指标，遇到异常可快速回滚，尽量把对用户的影响降至最低。&lt;/p&gt;
&lt;h3 id="业务每天新增-1000-万笔订单某天需要导出应该如何做"&gt;业务每天新增 1000 万笔订单，某天需要导出应该如何做？
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;按条件分批导出：按 &lt;strong&gt;时间 / ID / 分片键&lt;/strong&gt; 将数据拆分成多个区间分批查询导出，避免一次性全表扫描导致数据库压力过大。&lt;/li&gt;
&lt;li&gt;分布式并行导出：将导出任务拆分为多个子任务，通过多线程或分布式任务执行（按 ID hash / 时间分片），提升导出效率。&lt;/li&gt;
&lt;li&gt;异步任务执行：将导出操作放入后台任务系统（如 MQ / XXL-Job），避免阻塞请求线程，提升系统可用性。&lt;/li&gt;
&lt;li&gt;分页批量拉取数据：采用 &lt;strong&gt;limit + 游标（last_id）&lt;/strong&gt; 或按范围分页方式逐批查询数据，避免 OFFSET 深分页性能问题。&lt;/li&gt;
&lt;li&gt;流式写文件：使用流式读取 + 流式写出（如 BufferedWriter / JDBC fetch size），边查询边写入文件，避免内存占用过高。&lt;/li&gt;
&lt;li&gt;上传 S3 对象存储：导出完成后将文件上传到对象存储（如 S3 / OSS），提供下载链接，避免本地磁盘压力并支持高并发下载。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;对于大订单导出，通常采用异步任务+分页批处理+流式写出+对象存储的组合，用户点击导出，只是在后端提交异步任务，后台消息队列异步消费，数据库分批拉取避免全表扫描，使用游标或 id 分页，分批流式写出文件，不放在内存中而是写到对象存储服务（OSS）中供用户下载。&lt;/p&gt;
&lt;p&gt;导入具体步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;将业务数据预处理为 &lt;strong&gt;CSV / TSV 等标准格式文件&lt;/strong&gt;，保证字段顺序与目标表结构一致。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过 SCP / FTP / OSS 下载等方式，将数据文件传输到数据库所在机器本地磁盘，提高导入性能。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在导入前暂时禁用二级索引或约束，减少索引维护开销，提高导入速度。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DISABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KEYS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="err"&gt;导入完成后再恢复：&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ENABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;KEYS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用 MySQL 高效导入命令进行快速加载：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;LOAD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;INFILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/path/file.csv&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;FIELDS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TERMINATED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;LINES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TERMINATED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;导入完成后重新创建索引（或恢复索引），并进行数据校验（行数对比 / checksum）确保数据一致性。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="redis"&gt;Redis
&lt;/h2&gt;&lt;h3 id="redis-中的基本类型及应用场景"&gt;Redis 中的基本类型及应用场景
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;数据类型&lt;/th&gt;
 &lt;th&gt;底层数据结构&lt;/th&gt;
 &lt;th&gt;特点&lt;/th&gt;
 &lt;th&gt;常见应用场景&lt;/th&gt;
 &lt;th&gt;示例&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;String&lt;/td&gt;
 &lt;td&gt;SDS（简单动态字符串）&lt;/td&gt;
 &lt;td&gt;O(1) 访问、可扩展、支持二进制安全&lt;/td&gt;
 &lt;td&gt;缓存、计数器、分布式锁、Token&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;SET user:1 &amp;quot;json&amp;quot;&lt;/code&gt; / &lt;code&gt;INCR pv&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Hash&lt;/td&gt;
 &lt;td&gt;ziplist / hashtable（小对象 ziplist，大对象 hashtable）&lt;/td&gt;
 &lt;td&gt;适合存对象，节省内存&lt;/td&gt;
 &lt;td&gt;用户信息、订单对象&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;HSET user:1 name Tom&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;List&lt;/td&gt;
 &lt;td&gt;quicklist（ziplist + linkedlist（双向链表））&lt;/td&gt;
 &lt;td&gt;双端队列结构，支持阻塞&lt;/td&gt;
 &lt;td&gt;消息队列、最新列表&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;LPUSH queue order1&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Set&lt;/td&gt;
 &lt;td&gt;hashtable（整数集合 intset / hashtable）&lt;/td&gt;
 &lt;td&gt;无序唯一、支持集合运算&lt;/td&gt;
 &lt;td&gt;去重、共同好友&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;SADD tags java redis&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;ZSet&lt;/td&gt;
 &lt;td&gt;skiplist（跳表） + hashtable&lt;/td&gt;
 &lt;td&gt;有序、支持范围查询和排序&lt;/td&gt;
 &lt;td&gt;排行榜、热度排序&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;ZADD rank 100 user1&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;BitMap&lt;/td&gt;
 &lt;td&gt;String（位操作，本质是 bit 数组）&lt;/td&gt;
 &lt;td&gt;极省内存，高效状态标记&lt;/td&gt;
 &lt;td&gt;签到、活跃用户统计&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;SETBIT sign 1 1&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Pub/Sub&lt;/td&gt;
 &lt;td&gt;事件驱动（channel + dict 结构）&lt;/td&gt;
 &lt;td&gt;消息广播，实时通知&lt;/td&gt;
 &lt;td&gt;聊天室、系统通知&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;PUBLISH msg &amp;quot;hi&amp;quot;&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="跳表skiplist的说明"&gt;跳表（SkipList）的说明
&lt;/h3&gt;&lt;p&gt;跳表（SkipList）是一种&lt;strong&gt;基于有序链表 + 多级索引&lt;/strong&gt;的数据结构，通过“空间换时间”来实现类似&lt;strong&gt;二分查找&lt;/strong&gt;的效率。&lt;/p&gt;
&lt;h4 id="为什么不用红黑树"&gt;为什么不用红黑树？
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;红黑树：中序遍历较复杂，跳表：链表天然顺序结构，范围查询非常快。&lt;/li&gt;
&lt;li&gt;不需要复杂旋转（红黑树需要旋转维护平衡），更容易维护和调试。&lt;/li&gt;
&lt;li&gt;局部修改，不需要大范围结构调整。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="redis-是单线程为什么会快呢"&gt;Redis 是单线程为什么会快呢？
&lt;/h3&gt;&lt;p&gt;Redis 只是命令处理模型是单线程的，避免了锁竞争和线程切换开销，同时基于 I/O 多路复用（epoll）实现高并发连接处理，所有数据在内存中操作，并配合高度优化的数据结构，使得单线程也能实现极高吞吐；在 Redis 6 之后引入 I/O 多线程用于提升网络读写性能，但核心命令执行仍然是单线程。&lt;/p&gt;
&lt;h3 id="谈谈你对-io-多路复用的理解"&gt;谈谈你对 I/O 多路复用的理解
&lt;/h3&gt;&lt;p&gt;I/O 多路复用是一种通过一个线程监听多个 socket 的机制，利用 epoll 等系统调用在内核层管理连接状态，只处理就绪的 I/O 事件，从而避免线程阻塞和频繁创建线程的问题，提高系统并发能力。&lt;/p&gt;
&lt;h3 id="io-多路复用实现的三种方式"&gt;I/O 多路复用实现的三种方式
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;select：最早的 I/O 多路复用实现，通过&lt;strong&gt;轮询所有 fd&lt;/strong&gt;检查状态（fd 数量有限（默认 1024））。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;轮询&lt;/li&gt;
&lt;li&gt;有 fd（文件描述符）大小限制&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;poll：是 select 的改进版，去掉了 fd 数量限制，同样需要&lt;strong&gt;遍历所有 fd&lt;/strong&gt;（仍然是 O(n) 轮询）。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;仍是轮询&lt;/li&gt;
&lt;li&gt;没有 fd 限制&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;epoll：事件驱动模型，注册 fd 到内核，等待事件发生，返回“就绪 fd 列表”。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;事件驱动&lt;/li&gt;
&lt;li&gt;高性能&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="操作系统用户态和内核态以及它们之间的切换"&gt;操作系统用户态和内核态以及它们之间的切换
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;用户态：调用系统 API（间接操作文件、网络等），运行普通应用程序，权限较低，不能直接访问硬件。&lt;/li&gt;
&lt;li&gt;内核态：操作系统内核运行状态，拥有最高权限，可以直接访问 CPU，内存，硬盘，网络设备等。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="用户态和内核态切换"&gt;用户态和内核态切换
&lt;/h4&gt;&lt;p&gt;用户程序通过系统调用进入内核执行，再返回用户态的过程&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TD
 A["用户程序调用 read()"] --&gt; B[触发系统调用 syscall]
 B --&gt; C[CPU 切换到内核态 Kernel Mode]
 C --&gt; D[执行内核逻辑\n读取磁盘 / 网络 I/O]
 D --&gt; E[内核准备返回数据]
 E --&gt; F[CPU 切换回用户态 User Mode]
 F --&gt; G[用户程序获得返回结果]&lt;/pre&gt;&lt;h2 id="redis-1"&gt;Redis
&lt;/h2&gt;&lt;h3 id="redis-大-key-解决方案"&gt;Redis 大 Key 解决方案
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;定期使用 &lt;code&gt;redis-cli --bigkeys&lt;/code&gt; 命令进行扫描，快速定位可能的大 Key（注意：该命令为抽样统计，不保证全量精确）&lt;/li&gt;
&lt;li&gt;对于 Big List 一般采用拆分策略，比如按 1000 个元素一组进行分片存储；如果只关心最新数据，可以结合 &lt;code&gt;LTRIM&lt;/code&gt; 定期修剪，避免 List 无限增长导致阻塞操作（如 &lt;code&gt;LRANGE&lt;/code&gt; / &lt;code&gt;LLEN&lt;/code&gt; 变慢）&lt;/li&gt;
&lt;li&gt;对于 Big Hash，同样需要拆分，可以根据字段名做 hash 取模，将数据分散到多个小 Hash 中；并且在所有代码中，避免对大 Hash 使用 &lt;code&gt;HGETALL&lt;/code&gt;，应强制使用 &lt;code&gt;HSCAN&lt;/code&gt; 进行增量遍历，避免一次性全量拉取导致阻塞 Redis 单线程&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="scan-命令"&gt;&lt;code&gt;SCAN&lt;/code&gt; 命令
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;分批次增量遍历整个 Redis，每次只返回一小部分 key（避免 &lt;code&gt;KEYS&lt;/code&gt; 命令造成阻塞）&lt;/li&gt;
&lt;li&gt;基于游标（cursor）的遍历方式，非阻塞性操作，每次 &lt;code&gt;SCAN&lt;/code&gt; 只消耗很短时间，不影响主线程正常执行其他命令&lt;/li&gt;
&lt;li&gt;牺牲强一致性（可能出现重复或遗漏），换取高可用性与低阻塞性，适用于在线环境的渐进式遍历&lt;/li&gt;
&lt;li&gt;通常需要配合 &lt;code&gt;MATCH&lt;/code&gt;（模式匹配）和 &lt;code&gt;COUNT&lt;/code&gt;（控制每次扫描数量）使用，以提高扫描效率&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SCAN&lt;/code&gt; 不保证一次遍历完整数据集，必须循环直到 cursor 回到 0 才算完成一次完整遍历&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="redis-内存淘汰策略"&gt;Redis 内存淘汰策略
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;noeviction（默认）&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;不删除任何数据&lt;/li&gt;
&lt;li&gt;内存满后写入直接报错（OOM）&lt;/li&gt;
&lt;li&gt;适合：严格不能丢数据的场景&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;allkeys-lru&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;在所有 key 中，删除“最近最少使用”的 key&lt;/li&gt;
&lt;li&gt;最常用的缓存策略（推荐）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;volatile-lru&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;只在设置了 TTL 的 key 中做 LRU 淘汰&lt;/li&gt;
&lt;li&gt;永不过期的 key 不参与&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;allkeys-lfu&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;在所有 key 中删除“访问频率最低”的 key&lt;/li&gt;
&lt;li&gt;比 LRU 更智能（更适合热点数据）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;volatile-lfu&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;只在带 TTL 的 key 中按访问频率淘汰&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;allkeys-random&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;随机删除 key（不看冷热）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;volatile-random&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;在设置 TTL 的 key 中随机删除&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="redis-过期删除策略"&gt;Redis 过期删除策略
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;惰性删除（Lazy Deletion）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问 key 时才检查是否过期&lt;/li&gt;
&lt;li&gt;如果过期才删除&lt;/li&gt;
&lt;li&gt;优点：不耗 CPU&lt;/li&gt;
&lt;li&gt;缺点：过期 key 可能长期占内存&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;定期删除（Periodic Deletion）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Redis 每隔一段时间随机抽查一批 key&lt;/li&gt;
&lt;li&gt;删除其中已过期的 key&lt;/li&gt;
&lt;li&gt;优点：平衡 CPU 和内存&lt;/li&gt;
&lt;li&gt;缺点：不是全量扫描&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;定期 + 惰性混合&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="redis-持久化策略"&gt;Redis 持久化策略
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;RDB（数据快照）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;优点：&lt;/strong&gt; 恢复速度快、对性能影响小、文件体积小。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缺点：&lt;/strong&gt; 可能丢失最近一次快照之后的数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;AOF（追加日志）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;优点：&lt;/strong&gt; 数据安全性高，最多只丢最后一小段写入数据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缺点：&lt;/strong&gt; 文件体积大，恢复速度较慢。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;RDB + AOF（混合模式）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;优点：&lt;/strong&gt; 兼顾恢复速度快和数据安全性高。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缺点：&lt;/strong&gt; 实现更复杂，占用资源略高。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="redis-集群模式"&gt;Redis 集群模式
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;主从复制：一主多从结构，主负责写、从负责读，用于数据备份和读扩展，但不支持自动分片，主节点宕机需要手动处理或配合其他机制。&lt;/li&gt;
&lt;li&gt;哨兵模式：在主从基础上增加监控和自动故障转移，主节点挂了可以自动选新主，但仍然是单主架构，容量扩展能力有限。&lt;/li&gt;
&lt;li&gt;Cluster 集群模式：官方分布式方案，通过分片（slot）把数据分散到多个主节点，实现水平扩展和自动故障转移，是生产环境大规模使用的方案，但配置和使用复杂度更高。&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>在 Spring Boot 中配置 ShardingSphere 实现分库分表与读写分离</title><link>https://blog.evorsio.com/p/shardingsphere-spring-boot/</link><pubDate>Sat, 18 Apr 2026 01:24:00 +1200</pubDate><guid>https://blog.evorsio.com/p/shardingsphere-spring-boot/</guid><description>&lt;h1 id="在-spring-boot-中配置-shardingsphere-实现分库分表与读写分离"&gt;在 Spring Boot 中配置 ShardingSphere 实现分库分表与读写分离
&lt;/h1&gt;&lt;p&gt;随着业务数据量和访问压力的增长，单体数据库架构逐渐面临性能瓶颈与扩展性问题。为了应对这一挑战，常见的解决方案包括&lt;strong&gt;读写分离&lt;/strong&gt;与&lt;strong&gt;分库分表&lt;/strong&gt;：前者用于缓解读写压力不均，后者用于降低单表数据规模，提高整体查询与写入性能。&lt;/p&gt;
&lt;p&gt;在实际开发中，如果直接在业务代码中实现路由逻辑，会显著增加系统复杂度。因此，通常会引入 &lt;strong&gt;ShardingSphere&lt;/strong&gt; 这类数据库中间件，在不改动业务代码的前提下完成 SQL 路由与数据拆分。&lt;/p&gt;
&lt;p&gt;本文将基于 Spring Boot，逐步实现 ShardingSphere 的读写分离与分库分表配置，并通过示例验证其运行效果。&lt;/p&gt;
&lt;h2 id="先决条件"&gt;先决条件
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;配置好 MySQL 主从，参考 &lt;a class="link" href="https://blog.evorsio.com/p/mysql-gtid-replication/" &gt;MySQL 主从复制&lt;/a&gt; 一文中配置 MySQL 主从复制，主机用来写，从机用来读。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据库中有测试用表:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;create&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;auto_increment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;comment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;用户ID&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;primary&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;comment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;用户邮箱&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nickname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;comment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;用户昵称&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;password_hash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;comment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;用户密码&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;constraint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uk_email&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;unique&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;comment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;用户表&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用 MybatisPlus 3 操作数据库 (可以通过插件例如 MybatisX 一键生成 mapper 和 domain 等)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="读写分离"&gt;读写分离
&lt;/h2&gt;&lt;p&gt;在 Spring Boot 项目中的 &lt;code&gt;application.yaml&lt;/code&gt; 中配置数据库驱动和 jdbc url&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;spring&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;datasource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;driver-class-name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;org.apache.shardingsphere.driver.ShardingSphereDriver&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;jdbc:shardingsphere:classpath:sharding.yaml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;在与 &lt;code&gt;application.yaml&lt;/code&gt; 同目录下创建 &lt;code&gt;sharding.yaml&lt;/code&gt; 文件写入如下:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;dataSources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;master&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dataSourceClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;com.zaxxer.hikari.HikariDataSource&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;driverClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;com.mysql.cj.jdbc.Driver&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;jdbcUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;jdbc:mysql://localhost:3306/db?useSSL=false&amp;amp;serverTimezone=UTC&amp;amp;allowPublicKeyRetrieval=true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;user&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pass&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;slave&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dataSourceClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;com.zaxxer.hikari.HikariDataSource&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;driverClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;com.mysql.cj.jdbc.Driver&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;jdbcUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;jdbc:mysql://localhost:3307/db?useSSL=false&amp;amp;serverTimezone=UTC&amp;amp;allowPublicKeyRetrieval=true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;user&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pass&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- !&lt;span class="l"&gt;SINGLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;tables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;*.*&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# ← 加载所有库的所有表，不分片的表都走这里&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- !&lt;span class="l"&gt;READWRITE_SPLITTING&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dataSourceGroups&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;readwrite_ds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;writeDataSourceName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;master&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;readDataSourceNames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;slave&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;transactionalReadQueryStrategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;loadBalancerName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;random&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;loadBalancers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;random&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;RANDOM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;sql-show&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;配置成功后启动 Spring Boot 项目检查无误后进行测试 Sharding jdbc 读写分离是否正常运行，创建 Spring Boot 测试类：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;span class="lnt"&gt;52
&lt;/span&gt;&lt;span class="lnt"&gt;53
&lt;/span&gt;&lt;span class="lnt"&gt;54
&lt;/span&gt;&lt;span class="lnt"&gt;55
&lt;/span&gt;&lt;span class="lnt"&gt;56
&lt;/span&gt;&lt;span class="lnt"&gt;57
&lt;/span&gt;&lt;span class="lnt"&gt;58
&lt;/span&gt;&lt;span class="lnt"&gt;59
&lt;/span&gt;&lt;span class="lnt"&gt;60
&lt;/span&gt;&lt;span class="lnt"&gt;61
&lt;/span&gt;&lt;span class="lnt"&gt;62
&lt;/span&gt;&lt;span class="lnt"&gt;63
&lt;/span&gt;&lt;span class="lnt"&gt;64
&lt;/span&gt;&lt;span class="lnt"&gt;65
&lt;/span&gt;&lt;span class="lnt"&gt;66
&lt;/span&gt;&lt;span class="lnt"&gt;67
&lt;/span&gt;&lt;span class="lnt"&gt;68
&lt;/span&gt;&lt;span class="lnt"&gt;69
&lt;/span&gt;&lt;span class="lnt"&gt;70
&lt;/span&gt;&lt;span class="lnt"&gt;71
&lt;/span&gt;&lt;span class="lnt"&gt;72
&lt;/span&gt;&lt;span class="lnt"&gt;73
&lt;/span&gt;&lt;span class="lnt"&gt;74
&lt;/span&gt;&lt;span class="lnt"&gt;75
&lt;/span&gt;&lt;span class="lnt"&gt;76
&lt;/span&gt;&lt;span class="lnt"&gt;77
&lt;/span&gt;&lt;span class="lnt"&gt;78
&lt;/span&gt;&lt;span class="lnt"&gt;79
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.example.demo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.example.demo.domain.User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.example.demo.mapper.UserMapper&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;lombok.extern.slf4j.Slf4j&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.apache.shardingsphere.infra.hint.HintManager&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.junit.jupiter.api.Test&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.springframework.beans.factory.annotation.Autowired&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.springframework.boot.test.context.SpringBootTest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;org.springframework.transaction.annotation.Transactional&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * @author Evorsio
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * @since 2026/4/17
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@Slf4j&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@SpringBootTest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShardingTests&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Autowired&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UserMapper&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userMapper&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * 测试写操作 → 路由到 master
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;testInsert&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;test@example.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setNickname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;测试用户&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPasswordHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;123456&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userMapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;插入成功，id={}&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 观察日志：Actual SQL: master ::: INSERT ...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * 测试读操作 → 路由到 slave
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;testSelect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userMapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;selectList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;查询到 {} 条记录&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 观察日志：Actual SQL: slave ::: SELECT ...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * 测试事务内读 → 走 master（避免主从延迟）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Transactional&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;testTransactionalRead&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;transaction@example.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setNickname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;事务用户&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPasswordHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;123456&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userMapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 事务内立即读 → 走 master，能读到刚写入的数据&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userMapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;selectById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;事务内查询结果：{}&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 观察日志：Actual SQL: master ::: SELECT ...（不走 slave）&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * 测试 HintManager 强制走 master
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;testForceMaster&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HintManager&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hintManager&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HintManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hintManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setWriteRouteOnly&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 强制走主库&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userMapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;selectList&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;强制主库查询到 {} 条记录&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 观察日志：Actual SQL: master ::: SELECT ...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;分别测试每个方法，正确输出如下:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;testInsert()&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-17T21:32:06.277+12:00 INFO &lt;span class="m"&gt;27064&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-17T21:32:06.277+12:00 INFO &lt;span class="m"&gt;27064&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master ::: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;test@example.com, 测试用户, 123456&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-17T21:32:06.330+12:00 INFO &lt;span class="m"&gt;27064&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; com.example.demo.ShardingTests : 插入成功，id&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;testSelect()&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-17T21:34:34.371+12:00 INFO &lt;span class="m"&gt;27216&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: SELECT id,email,nickname,password_hash FROM users
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-17T21:34:34.371+12:00 INFO &lt;span class="m"&gt;27216&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: slave ::: SELECT id,email,nickname,password_hash FROM users
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-17T21:34:34.428+12:00 INFO &lt;span class="m"&gt;27216&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; com.example.demo.ShardingTests : 查询到 &lt;span class="m"&gt;2&lt;/span&gt; 条记录
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;testTransactionalRead()&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-17T21:35:06.995+12:00 INFO &lt;span class="m"&gt;4324&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-17T21:35:06.995+12:00 INFO &lt;span class="m"&gt;4324&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master ::: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;transaction@example.com, 事务用户, 123456&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-17T21:35:07.167+12:00 INFO &lt;span class="m"&gt;4324&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: SELECT id,email,nickname,password_hash FROM users WHERE &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;?
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-17T21:35:07.168+12:00 INFO &lt;span class="m"&gt;4324&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master ::: SELECT id,email,nickname,password_hash FROM users WHERE &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;? ::: &lt;span class="o"&gt;[&lt;/span&gt;3&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-17T21:35:07.211+12:00 INFO &lt;span class="m"&gt;4324&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; com.example.demo.ShardingTests : 事务内查询结果：User&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3, &lt;span class="nv"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;transaction@example.com, &lt;span class="nv"&gt;nickname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;事务用户, &lt;span class="nv"&gt;passwordHash&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;123456&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;testForceMaster()&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-17T21:35:33.391+12:00 INFO &lt;span class="m"&gt;10264&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: SELECT id,email,nickname,password_hash FROM users
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-17T21:35:33.392+12:00 INFO &lt;span class="m"&gt;10264&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master ::: SELECT id,email,nickname,password_hash FROM users
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-17T21:35:33.451+12:00 INFO &lt;span class="m"&gt;10264&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; com.example.demo.ShardingTests : 强制主库查询到 &lt;span class="m"&gt;2&lt;/span&gt; 条记录
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;全部测试通过，读写分离配置完成&lt;/p&gt;
&lt;h2 id="分库分表"&gt;分库分表
&lt;/h2&gt;&lt;p&gt;首先配置 mysql 主从复制和测试用数据库&lt;/p&gt;
&lt;p&gt;创建三个文件&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;master-init.sql&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;span class="lnt"&gt;52
&lt;/span&gt;&lt;span class="lnt"&gt;53
&lt;/span&gt;&lt;span class="lnt"&gt;54
&lt;/span&gt;&lt;span class="lnt"&gt;55
&lt;/span&gt;&lt;span class="lnt"&gt;56
&lt;/span&gt;&lt;span class="lnt"&gt;57
&lt;/span&gt;&lt;span class="lnt"&gt;58
&lt;/span&gt;&lt;span class="lnt"&gt;59
&lt;/span&gt;&lt;span class="lnt"&gt;60
&lt;/span&gt;&lt;span class="lnt"&gt;61
&lt;/span&gt;&lt;span class="lnt"&gt;62
&lt;/span&gt;&lt;span class="lnt"&gt;63
&lt;/span&gt;&lt;span class="lnt"&gt;64
&lt;/span&gt;&lt;span class="lnt"&gt;65
&lt;/span&gt;&lt;span class="lnt"&gt;66
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- ===== 建库授权 =====
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db_0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db_1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GRANT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIVILEGES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GRANT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIVILEGES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db_0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GRANT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIVILEGES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- 创建主从复制专用账号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;replicator&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IDENTIFIED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;replicator123&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GRANT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;REPLICATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SLAVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;replicator&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;FLUSH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIVILEGES&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- ===== db：非分片表 =====
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;roles&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user_profile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;avatar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bio&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gender&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tinyint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DEFAULT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;birthday&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user_role&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;role_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;role_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;outbox&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tinyint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DEFAULT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;roles&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;admin&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- ===== db_0：users 分片表 =====
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db_0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;users_0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nickname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;password_hash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;users_1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;users_0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- ===== db_1：users 分片表 =====
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db_1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;users_0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;bigint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nickname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;password_hash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;users_1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;users_0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;slave-init.sh&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;等待 master 就绪...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;until&lt;/span&gt; mysql -h mysql-master -P &lt;span class="m"&gt;3306&lt;/span&gt; -u replicator -preplicator123 -e &lt;span class="s2"&gt;&amp;#34;SELECT 1&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&amp;gt;/dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;重试中...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sleep &lt;span class="m"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql -uroot -p&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;&amp;lt;EOF
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;STOP REPLICA;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;CHANGE REPLICATION SOURCE TO
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; SOURCE_HOST=&amp;#39;mysql-master&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; SOURCE_PORT=3306,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; SOURCE_USER=&amp;#39;replicator&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; SOURCE_PASSWORD=&amp;#39;replicator123&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; SOURCE_AUTO_POSITION=1,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; GET_SOURCE_PUBLIC_KEY=1;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;START REPLICA;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;主从复制配置完成&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;docker-compose.yaml&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mysql-master&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;mysql:8.0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;mysql-master&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;db&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;user&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pass&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;root&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; --server-id=1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; --log-bin=mysql-bin
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; --binlog-format=ROW
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; --gtid-mode=ON
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; --enforce-gtid-consistency=ON
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; --log-slave-updates=ON&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;3306:3306&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;mysql_master_data:/var/lib/mysql&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./master-init.sql:/docker-entrypoint-initdb.d/init.sql&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# ← 新增&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mysql-slave&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;mysql:8.0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;mysql-slave&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;always&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;3307:3306&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;root&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; --server-id=2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; --relay-log=mysql-relay-bin
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; --gtid-mode=ON
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; --enforce-gtid-consistency=ON
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; --log-slave-updates=ON
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; --read-only=ON&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;mysql_slave_data:/var/lib/mysql&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./slave-init.sh:/docker-entrypoint-initdb.d/init.sh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# ← 新增&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mysql_master_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mysql_slave_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;使用 &lt;code&gt;docker compose up -d&lt;/code&gt; 启动，并进入 mysql-slave 从机中查看状态 &lt;code&gt;docker exec -it mysql-slave mysql -uroot -proot&lt;/code&gt;，&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;show&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;replica&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="k"&gt;G&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;输出:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;span class="lnt"&gt;52
&lt;/span&gt;&lt;span class="lnt"&gt;53
&lt;/span&gt;&lt;span class="lnt"&gt;54
&lt;/span&gt;&lt;span class="lnt"&gt;55
&lt;/span&gt;&lt;span class="lnt"&gt;56
&lt;/span&gt;&lt;span class="lnt"&gt;57
&lt;/span&gt;&lt;span class="lnt"&gt;58
&lt;/span&gt;&lt;span class="lnt"&gt;59
&lt;/span&gt;&lt;span class="lnt"&gt;60
&lt;/span&gt;&lt;span class="lnt"&gt;61
&lt;/span&gt;&lt;span class="lnt"&gt;62
&lt;/span&gt;&lt;span class="lnt"&gt;63
&lt;/span&gt;&lt;span class="lnt"&gt;64
&lt;/span&gt;&lt;span class="lnt"&gt;65
&lt;/span&gt;&lt;span class="lnt"&gt;66
&lt;/span&gt;&lt;span class="lnt"&gt;67
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&amp;gt; show replica status&lt;span class="se"&gt;\G&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;*************************** 1. row ***************************
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Replica_IO_State: Waiting &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; to send event
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Source_Host: mysql-master
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Source_User: replicator
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Source_Port: &lt;span class="m"&gt;3306&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Connect_Retry: &lt;span class="m"&gt;60&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Source_Log_File: mysql-bin.000003
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Read_Source_Log_Pos: &lt;span class="m"&gt;197&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Relay_Log_File: mysql-relay-bin.000005
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Relay_Log_Pos: &lt;span class="m"&gt;413&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Relay_Source_Log_File: mysql-bin.000003
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Replica_IO_Running: Yes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Replica_SQL_Running: Yes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Replicate_Do_DB:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Replicate_Ignore_DB:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Replicate_Do_Table:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Replicate_Ignore_Table:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Replicate_Wild_Do_Table:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Replicate_Wild_Ignore_Table:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Last_Errno: &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Last_Error:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Skip_Counter: &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Exec_Source_Log_Pos: &lt;span class="m"&gt;197&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Relay_Log_Space: &lt;span class="m"&gt;3004361&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Until_Condition: None
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Until_Log_File:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Until_Log_Pos: &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Source_SSL_Allowed: No
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Source_SSL_CA_File:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Source_SSL_CA_Path:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Source_SSL_Cert:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Source_SSL_Cipher:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Source_SSL_Key:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Seconds_Behind_Source: &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Source_SSL_Verify_Server_Cert: No
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Last_IO_Errno: &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Last_IO_Error:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Last_SQL_Errno: &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Last_SQL_Error:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Replicate_Ignore_Server_Ids:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Source_Server_Id: &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Source_UUID: 3b2fadb5-3a53-11f1-999c-b2404a28de3c
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Source_Info_File: mysql.slave_master_info
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; SQL_Delay: &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; SQL_Remaining_Delay: NULL
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Replica_SQL_Running_State: Replica has &lt;span class="nb"&gt;read&lt;/span&gt; all relay log&lt;span class="p"&gt;;&lt;/span&gt; waiting &lt;span class="k"&gt;for&lt;/span&gt; more updates
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Source_Retry_Count: &lt;span class="m"&gt;86400&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Source_Bind:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Last_IO_Error_Timestamp:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Last_SQL_Error_Timestamp:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Source_SSL_Crl:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Source_SSL_Crlpath:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Retrieved_Gtid_Set: 3b2fadb5-3a53-11f1-999c-b2404a28de3c:1-25
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Executed_Gtid_Set: 3b1bf78c-3a53-11f1-923f-e21ea55938fa:1-5,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3b2fadb5-3a53-11f1-999c-b2404a28de3c:1-25
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Auto_Position: &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Replicate_Rewrite_DB:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Channel_Name:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Source_TLS_Version:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Source_public_key_path:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Get_Source_public_key: &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Network_Namespace:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="m"&gt;1&lt;/span&gt; row in &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0.00 sec&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ERROR:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;No query specified
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;状态正常，可以进行 sharding sphere 分库分表配置，修改 &lt;code&gt;sharding.yaml&lt;/code&gt;,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;span class="lnt"&gt;52
&lt;/span&gt;&lt;span class="lnt"&gt;53
&lt;/span&gt;&lt;span class="lnt"&gt;54
&lt;/span&gt;&lt;span class="lnt"&gt;55
&lt;/span&gt;&lt;span class="lnt"&gt;56
&lt;/span&gt;&lt;span class="lnt"&gt;57
&lt;/span&gt;&lt;span class="lnt"&gt;58
&lt;/span&gt;&lt;span class="lnt"&gt;59
&lt;/span&gt;&lt;span class="lnt"&gt;60
&lt;/span&gt;&lt;span class="lnt"&gt;61
&lt;/span&gt;&lt;span class="lnt"&gt;62
&lt;/span&gt;&lt;span class="lnt"&gt;63
&lt;/span&gt;&lt;span class="lnt"&gt;64
&lt;/span&gt;&lt;span class="lnt"&gt;65
&lt;/span&gt;&lt;span class="lnt"&gt;66
&lt;/span&gt;&lt;span class="lnt"&gt;67
&lt;/span&gt;&lt;span class="lnt"&gt;68
&lt;/span&gt;&lt;span class="lnt"&gt;69
&lt;/span&gt;&lt;span class="lnt"&gt;70
&lt;/span&gt;&lt;span class="lnt"&gt;71
&lt;/span&gt;&lt;span class="lnt"&gt;72
&lt;/span&gt;&lt;span class="lnt"&gt;73
&lt;/span&gt;&lt;span class="lnt"&gt;74
&lt;/span&gt;&lt;span class="lnt"&gt;75
&lt;/span&gt;&lt;span class="lnt"&gt;76
&lt;/span&gt;&lt;span class="lnt"&gt;77
&lt;/span&gt;&lt;span class="lnt"&gt;78
&lt;/span&gt;&lt;span class="lnt"&gt;79
&lt;/span&gt;&lt;span class="lnt"&gt;80
&lt;/span&gt;&lt;span class="lnt"&gt;81
&lt;/span&gt;&lt;span class="lnt"&gt;82
&lt;/span&gt;&lt;span class="lnt"&gt;83
&lt;/span&gt;&lt;span class="lnt"&gt;84
&lt;/span&gt;&lt;span class="lnt"&gt;85
&lt;/span&gt;&lt;span class="lnt"&gt;86
&lt;/span&gt;&lt;span class="lnt"&gt;87
&lt;/span&gt;&lt;span class="lnt"&gt;88
&lt;/span&gt;&lt;span class="lnt"&gt;89
&lt;/span&gt;&lt;span class="lnt"&gt;90
&lt;/span&gt;&lt;span class="lnt"&gt;91
&lt;/span&gt;&lt;span class="lnt"&gt;92
&lt;/span&gt;&lt;span class="lnt"&gt;93
&lt;/span&gt;&lt;span class="lnt"&gt;94
&lt;/span&gt;&lt;span class="lnt"&gt;95
&lt;/span&gt;&lt;span class="lnt"&gt;96
&lt;/span&gt;&lt;span class="lnt"&gt;97
&lt;/span&gt;&lt;span class="lnt"&gt;98
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;dataSources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;master&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# db 库（非分片表）&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dataSourceClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;com.zaxxer.hikari.HikariDataSource&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;driverClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;com.mysql.cj.jdbc.Driver&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;jdbcUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;jdbc:mysql://localhost:3306/db?useSSL=false&amp;amp;serverTimezone=UTC&amp;amp;allowPublicKeyRetrieval=true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;user&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pass&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;master_0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# db_0 库&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dataSourceClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;com.zaxxer.hikari.HikariDataSource&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;driverClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;com.mysql.cj.jdbc.Driver&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;jdbcUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;jdbc:mysql://localhost:3306/db_0?useSSL=false&amp;amp;serverTimezone=UTC&amp;amp;allowPublicKeyRetrieval=true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;user&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pass&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;master_1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# db_1 库&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dataSourceClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;com.zaxxer.hikari.HikariDataSource&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;driverClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;com.mysql.cj.jdbc.Driver&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;jdbcUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;jdbc:mysql://localhost:3306/db_1?useSSL=false&amp;amp;serverTimezone=UTC&amp;amp;allowPublicKeyRetrieval=true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;user&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pass&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;slave&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# slave db 库&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dataSourceClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;com.zaxxer.hikari.HikariDataSource&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;driverClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;com.mysql.cj.jdbc.Driver&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;jdbcUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;jdbc:mysql://localhost:3307/db?useSSL=false&amp;amp;serverTimezone=UTC&amp;amp;allowPublicKeyRetrieval=true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;user&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pass&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;slave_0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dataSourceClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;com.zaxxer.hikari.HikariDataSource&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;driverClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;com.mysql.cj.jdbc.Driver&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;jdbcUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;jdbc:mysql://localhost:3307/db_0?useSSL=false&amp;amp;serverTimezone=UTC&amp;amp;allowPublicKeyRetrieval=true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;user&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pass&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;slave_1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dataSourceClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;com.zaxxer.hikari.HikariDataSource&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;driverClassName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;com.mysql.cj.jdbc.Driver&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;jdbcUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;jdbc:mysql://localhost:3307/db_1?useSSL=false&amp;amp;serverTimezone=UTC&amp;amp;allowPublicKeyRetrieval=true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;user&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pass&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- !&lt;span class="l"&gt;READWRITE_SPLITTING&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;dataSourceGroups&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;rw_ds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 非分片表用这个&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;writeDataSourceName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;master&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;readDataSourceNames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;slave&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;transactionalReadQueryStrategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;loadBalancerName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;random&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;rw_ds_0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;writeDataSourceName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;master_0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;readDataSourceNames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;slave_0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;transactionalReadQueryStrategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;loadBalancerName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;random&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;rw_ds_1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;writeDataSourceName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;master_1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;readDataSourceNames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;slave_1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;transactionalReadQueryStrategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;loadBalancerName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;random&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;loadBalancers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;random&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;RANDOM&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- !&lt;span class="l"&gt;SHARDING&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;tables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;actualDataNodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;rw_ds_${0..1}.users_${0..1}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;databaseStrategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;standard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;shardingColumn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;shardingAlgorithmName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;db_inline&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;tableStrategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;standard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;shardingColumn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;shardingAlgorithmName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;tbl_inline&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;shardingAlgorithms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;db_inline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;INLINE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;algorithm-expression&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;rw_ds_${id % 2}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;tbl_inline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;INLINE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;algorithm-expression&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;users_${(id.intdiv(2)) % 2}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- !&lt;span class="l"&gt;SINGLE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;tables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s2"&gt;&amp;#34;*.*&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;defaultDataSource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;rw_ds&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 非分片表走 db 库&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;sql-show&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;配置完后运行测试，&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * 测试批量写操作 → 分库分表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;testBatchInsertSharding&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;1L&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;user_&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;@test.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setNickname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;user&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPasswordHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;pwd_&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;userMapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;控制台输出：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.626+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.626+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master_1 ::: INSERT INTO users_0 &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt;?, ?, ?, ?&lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;1, user_0@test.com, user0, pwd_0&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.653+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.653+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master_0 ::: INSERT INTO users_1 &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt;?, ?, ?, ?&lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;2, user_1@test.com, user1, pwd_1&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.666+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.666+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master_1 ::: INSERT INTO users_1 &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt;?, ?, ?, ?&lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;3, user_2@test.com, user2, pwd_2&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.676+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.676+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master_0 ::: INSERT INTO users_0 &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt;?, ?, ?, ?&lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;4, user_3@test.com, user3, pwd_3&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.685+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.685+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master_1 ::: INSERT INTO users_0 &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt;?, ?, ?, ?&lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;5, user_4@test.com, user4, pwd_4&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.692+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.692+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master_0 ::: INSERT INTO users_1 &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt;?, ?, ?, ?&lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;6, user_5@test.com, user5, pwd_5&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.702+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.702+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master_1 ::: INSERT INTO users_1 &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt;?, ?, ?, ?&lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;7, user_6@test.com, user6, pwd_6&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.709+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.709+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master_0 ::: INSERT INTO users_0 &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt;?, ?, ?, ?&lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;8, user_7@test.com, user7, pwd_7&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.716+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.716+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master_1 ::: INSERT INTO users_0 &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt;?, ?, ?, ?&lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;9, user_8@test.com, user8, pwd_8&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.724+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.724+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master_0 ::: INSERT INTO users_1 &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt;?, ?, ?, ?&lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;10, user_9@test.com, user9, pwd_9&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.731+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.731+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master_1 ::: INSERT INTO users_1 &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt;?, ?, ?, ?&lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;11, user_10@test.com, user10, pwd_10&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.739+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.740+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master_0 ::: INSERT INTO users_0 &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt;?, ?, ?, ?&lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;12, user_11@test.com, user11, pwd_11&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.746+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.746+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master_1 ::: INSERT INTO users_0 &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt;?, ?, ?, ?&lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;13, user_12@test.com, user12, pwd_12&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.751+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.752+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master_0 ::: INSERT INTO users_1 &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt;?, ?, ?, ?&lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;14, user_13@test.com, user13, pwd_13&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.759+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.759+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master_1 ::: INSERT INTO users_1 &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt;?, ?, ?, ?&lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;15, user_14@test.com, user14, pwd_14&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.766+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.766+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master_0 ::: INSERT INTO users_0 &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt;?, ?, ?, ?&lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;16, user_15@test.com, user15, pwd_15&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.772+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.772+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master_1 ::: INSERT INTO users_0 &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt;?, ?, ?, ?&lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;17, user_16@test.com, user16, pwd_16&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.777+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.777+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master_0 ::: INSERT INTO users_1 &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt;?, ?, ?, ?&lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;18, user_17@test.com, user17, pwd_17&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.781+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.781+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master_1 ::: INSERT INTO users_1 &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt;?, ?, ?, ?&lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;19, user_18@test.com, user18, pwd_18&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.785+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Logic SQL: INSERT INTO users &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt; ?, ?, ?, ? &lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2026-04-18T01:12:41.786+12:00 INFO &lt;span class="m"&gt;16080&lt;/span&gt; --- &lt;span class="o"&gt;[&lt;/span&gt;demo&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; main&lt;span class="o"&gt;]&lt;/span&gt; ShardingSphere-SQL : Actual SQL: master_0 ::: INSERT INTO users_0 &lt;span class="o"&gt;(&lt;/span&gt; id, email, nickname, password_hash &lt;span class="o"&gt;)&lt;/span&gt; VALUES &lt;span class="o"&gt;(&lt;/span&gt;?, ?, ?, ?&lt;span class="o"&gt;)&lt;/span&gt; ::: &lt;span class="o"&gt;[&lt;/span&gt;20, user_19@test.com, user19, pwd_19&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;20 条测试数据全部插入数据库成功，进入数据库查看&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id="db_0users_0"&gt;db_0.users_0
&lt;/h1&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;id&lt;/th&gt;
 &lt;th&gt;email&lt;/th&gt;
 &lt;th&gt;nickname&lt;/th&gt;
 &lt;th&gt;password&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="mailto:user_3@test.com" &gt;user_3@test.com&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;user3&lt;/td&gt;
 &lt;td&gt;pwd_3&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;8&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="mailto:user_7@test.com" &gt;user_7@test.com&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;user7&lt;/td&gt;
 &lt;td&gt;pwd_7&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;12&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="mailto:user_11@test.com" &gt;user_11@test.com&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;user11&lt;/td&gt;
 &lt;td&gt;pwd_11&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;16&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="mailto:user_15@test.com" &gt;user_15@test.com&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;user15&lt;/td&gt;
 &lt;td&gt;pwd_15&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;20&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="mailto:user_19@test.com" &gt;user_19@test.com&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;user19&lt;/td&gt;
 &lt;td&gt;pwd_19&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h1 id="db_0users_1"&gt;db_0.users_1
&lt;/h1&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;id&lt;/th&gt;
 &lt;th&gt;email&lt;/th&gt;
 &lt;th&gt;nickname&lt;/th&gt;
 &lt;th&gt;password&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="mailto:user_1@test.com" &gt;user_1@test.com&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;user1&lt;/td&gt;
 &lt;td&gt;pwd_1&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;6&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="mailto:user_5@test.com" &gt;user_5@test.com&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;user5&lt;/td&gt;
 &lt;td&gt;pwd_5&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;10&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="mailto:user_9@test.com" &gt;user_9@test.com&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;user9&lt;/td&gt;
 &lt;td&gt;pwd_9&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;14&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="mailto:user_13@test.com" &gt;user_13@test.com&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;user13&lt;/td&gt;
 &lt;td&gt;pwd_13&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;18&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="mailto:user_17@test.com" &gt;user_17@test.com&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;user17&lt;/td&gt;
 &lt;td&gt;pwd_17&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h1 id="db_1users_0"&gt;db_1.users_0
&lt;/h1&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;id&lt;/th&gt;
 &lt;th&gt;email&lt;/th&gt;
 &lt;th&gt;nickname&lt;/th&gt;
 &lt;th&gt;password&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="mailto:user_0@test.com" &gt;user_0@test.com&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;user0&lt;/td&gt;
 &lt;td&gt;pwd_0&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;5&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="mailto:user_4@test.com" &gt;user_4@test.com&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;user4&lt;/td&gt;
 &lt;td&gt;pwd_4&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;9&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="mailto:user_8@test.com" &gt;user_8@test.com&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;user8&lt;/td&gt;
 &lt;td&gt;pwd_8&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;13&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="mailto:user_12@test.com" &gt;user_12@test.com&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;user12&lt;/td&gt;
 &lt;td&gt;pwd_12&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;17&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="mailto:user_16@test.com" &gt;user_16@test.com&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;user16&lt;/td&gt;
 &lt;td&gt;pwd_16&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h1 id="db_1users_1"&gt;db_1.users_1
&lt;/h1&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;id&lt;/th&gt;
 &lt;th&gt;email&lt;/th&gt;
 &lt;th&gt;nickname&lt;/th&gt;
 &lt;th&gt;password&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="mailto:user_2@test.com" &gt;user_2@test.com&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;user2&lt;/td&gt;
 &lt;td&gt;pwd_2&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;7&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="mailto:user_6@test.com" &gt;user_6@test.com&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;user6&lt;/td&gt;
 &lt;td&gt;pwd_6&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;11&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="mailto:user_10@test.com" &gt;user_10@test.com&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;user10&lt;/td&gt;
 &lt;td&gt;pwd_10&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;15&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="mailto:user_14@test.com" &gt;user_14@test.com&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;user14&lt;/td&gt;
 &lt;td&gt;pwd_14&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;19&lt;/td&gt;
 &lt;td&gt;&lt;a class="link" href="mailto:user_18@test.com" &gt;user_18@test.com&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;user18&lt;/td&gt;
 &lt;td&gt;pwd_18&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;p&gt;如上可见 20 条 user 数据被正确分到了四张表中，分库分表配置成功。&lt;/p&gt;
&lt;p&gt;通过上述示例可以看到，数据在插入时已经按照分片规则被自动路由到不同的库和表中，实现了基础的分库分表效果。&lt;/p&gt;
&lt;p&gt;但需要注意的是，本文中的分片规则属于人为构造的简化模型，更多用于帮助理解数据路由过程。在真实生产环境中，ShardingSphere 还支持更复杂的分片策略（如哈希分片、范围分片、自定义算法等），同时也可以配合雪花算法等分布式 ID 生成方案，从而避免手动维护 ID 和路由规则的问题。&lt;/p&gt;</description></item></channel></rss>