<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>复习-JavaGuide-Database on 随记</title><link>https://blog.liuyi2026.asia/zh/tags/%E5%A4%8D%E4%B9%A0-javaGuide-database/</link><description>Recent content in 复习-JavaGuide-Database on 随记</description><generator>Hugo</generator><language>zh</language><lastBuildDate>Tue, 14 Mar 2023 22:34:52 +0000</lastBuildDate><atom:link href="https://blog.liuyi2026.asia/zh/tags/%E5%A4%8D%E4%B9%A0-javaGuide-database/index.xml" rel="self" type="application/rss+xml"/><item><title>mysql执行计划</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/MySQL/ly0606lymysql-query-execution-plan/</link><pubDate>Tue, 14 Mar 2023 22:34:52 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/MySQL/ly0606lymysql-query-execution-plan/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;blockquote class='book-hint '>
&lt;p>本文来自公号 MySQL 技术，JavaGuide 对其做了补充完善。原文地址：https://mp.weixin.qq.com/s/d5OowNLtXBGEAbT31sSH4g&lt;/p>&lt;/blockquote>&lt;p>优化 SQL 的第一步应该是读懂 SQL 的执行计划。本篇文章，我们一起来学习下 MySQL &lt;code>EXPLAIN&lt;/code> 执行计划相关知识。&lt;/p>
&lt;h2 id="什么是执行计划">什么是执行计划？&lt;a class="anchor" href="#%e4%bb%80%e4%b9%88%e6%98%af%e6%89%a7%e8%a1%8c%e8%ae%a1%e5%88%92">#&lt;/a>&lt;/h2>
&lt;p>&lt;strong>执行计划&lt;/strong> 是指一条 SQL 语句在经过 &lt;strong>MySQL 查询优化器&lt;/strong> 的优化会后，具体的执行方式。&lt;/p>
&lt;p>执行计划通常用于 &lt;strong>SQL 性能分析&lt;/strong>、&lt;strong>优化&lt;/strong>等场景。通过 &lt;code>EXPLAIN&lt;/code> 的结果，可以了解到如&lt;strong>数据表的查询顺序&lt;/strong>、数据查询操作的&lt;strong>操作类型&lt;/strong>、&lt;strong>哪些索引&lt;/strong>可以被命中、哪些索引&lt;strong>实际&lt;/strong>会命中、每个数据表有多少&lt;strong>行记录被查询&lt;/strong>等信息。&lt;/p>
&lt;h2 id="如何获取执行计划">如何获取执行计划？&lt;a class="anchor" href="#%e5%a6%82%e4%bd%95%e8%8e%b7%e5%8f%96%e6%89%a7%e8%a1%8c%e8%ae%a1%e5%88%92">#&lt;/a>&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-mysql" data-lang="mysql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- 提交准备数据
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">SET&lt;/span> NAMES utf8mb4;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">SET&lt;/span> FOREIGN_KEY_CHECKS &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- ----------------------------
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- Table structure for dept_emp
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- ----------------------------
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">DROP&lt;/span> &lt;span style="color:#66d9ef">TABLE&lt;/span> &lt;span style="color:#66d9ef">IF&lt;/span> &lt;span style="color:#66d9ef">EXISTS&lt;/span> &lt;span style="color:#f92672">`&lt;/span>dept_emp&lt;span style="color:#f92672">`&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">CREATE&lt;/span> &lt;span style="color:#66d9ef">TABLE&lt;/span> &lt;span style="color:#f92672">`&lt;/span>dept_emp&lt;span style="color:#f92672">`&lt;/span> (
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">`&lt;/span>id&lt;span style="color:#f92672">`&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span>(&lt;span style="color:#ae81ff">0&lt;/span>) &lt;span style="color:#66d9ef">NOT&lt;/span> &lt;span style="color:#66d9ef">NULL&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">`&lt;/span>emp_no&lt;span style="color:#f92672">`&lt;/span> &lt;span style="color:#66d9ef">varchar&lt;/span>(&lt;span style="color:#ae81ff">128&lt;/span>) &lt;span style="color:#66d9ef">CHARACTER&lt;/span> &lt;span style="color:#66d9ef">SET&lt;/span> utf8mb4 &lt;span style="color:#66d9ef">COLLATE&lt;/span> utf8mb4_0900_ai_ci &lt;span style="color:#66d9ef">NULL&lt;/span> &lt;span style="color:#66d9ef">DEFAULT&lt;/span> &lt;span style="color:#66d9ef">NULL&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">`&lt;/span>other1&lt;span style="color:#f92672">`&lt;/span> &lt;span style="color:#66d9ef">varchar&lt;/span>(&lt;span style="color:#ae81ff">255&lt;/span>) &lt;span style="color:#66d9ef">CHARACTER&lt;/span> &lt;span style="color:#66d9ef">SET&lt;/span> utf8mb4 &lt;span style="color:#66d9ef">COLLATE&lt;/span> utf8mb4_0900_ai_ci &lt;span style="color:#66d9ef">NULL&lt;/span> &lt;span style="color:#66d9ef">DEFAULT&lt;/span> &lt;span style="color:#66d9ef">NULL&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">`&lt;/span>other2&lt;span style="color:#f92672">`&lt;/span> &lt;span style="color:#66d9ef">varchar&lt;/span>(&lt;span style="color:#ae81ff">255&lt;/span>) &lt;span style="color:#66d9ef">CHARACTER&lt;/span> &lt;span style="color:#66d9ef">SET&lt;/span> utf8mb4 &lt;span style="color:#66d9ef">COLLATE&lt;/span> utf8mb4_0900_ai_ci &lt;span style="color:#66d9ef">NULL&lt;/span> &lt;span style="color:#66d9ef">DEFAULT&lt;/span> &lt;span style="color:#66d9ef">NULL&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">PRIMARY&lt;/span> &lt;span style="color:#66d9ef">KEY&lt;/span> (&lt;span style="color:#f92672">`&lt;/span>id&lt;span style="color:#f92672">`&lt;/span>) &lt;span style="color:#66d9ef">USING&lt;/span> BTREE,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">INDEX&lt;/span> &lt;span style="color:#f92672">`&lt;/span>index_emp_no&lt;span style="color:#f92672">`&lt;/span>(&lt;span style="color:#f92672">`&lt;/span>emp_no&lt;span style="color:#f92672">`&lt;/span>) &lt;span style="color:#66d9ef">USING&lt;/span> BTREE
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>) &lt;span style="color:#66d9ef">ENGINE&lt;/span> &lt;span style="color:#f92672">=&lt;/span> InnoDB &lt;span style="color:#66d9ef">CHARACTER&lt;/span> &lt;span style="color:#66d9ef">SET&lt;/span> &lt;span style="color:#f92672">=&lt;/span> utf8mb4 &lt;span style="color:#66d9ef">COLLATE&lt;/span> &lt;span style="color:#f92672">=&lt;/span> utf8mb4_0900_ai_ci ROW_FORMAT &lt;span style="color:#f92672">=&lt;/span> Dynamic;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- ----------------------------
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- Records of dept_emp
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- ----------------------------
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">INSERT&lt;/span> &lt;span style="color:#66d9ef">INTO&lt;/span> &lt;span style="color:#f92672">`&lt;/span>dept_emp&lt;span style="color:#f92672">`&lt;/span> &lt;span style="color:#66d9ef">VALUES&lt;/span> (&lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;a1&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;o11&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;012&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">INSERT&lt;/span> &lt;span style="color:#66d9ef">INTO&lt;/span> &lt;span style="color:#f92672">`&lt;/span>dept_emp&lt;span style="color:#f92672">`&lt;/span> &lt;span style="color:#66d9ef">VALUES&lt;/span> (&lt;span style="color:#ae81ff">2&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;a2&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;o21&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;o22&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">INSERT&lt;/span> &lt;span style="color:#66d9ef">INTO&lt;/span> &lt;span style="color:#f92672">`&lt;/span>dept_emp&lt;span style="color:#f92672">`&lt;/span> &lt;span style="color:#66d9ef">VALUES&lt;/span> (&lt;span style="color:#ae81ff">3&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;a3&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;o31&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;o32&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">INSERT&lt;/span> &lt;span style="color:#66d9ef">INTO&lt;/span> &lt;span style="color:#f92672">`&lt;/span>dept_emp&lt;span style="color:#f92672">`&lt;/span> &lt;span style="color:#66d9ef">VALUES&lt;/span> (&lt;span style="color:#ae81ff">4&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;a4&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;o41&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;o42&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">INSERT&lt;/span> &lt;span style="color:#66d9ef">INTO&lt;/span> &lt;span style="color:#f92672">`&lt;/span>dept_emp&lt;span style="color:#f92672">`&lt;/span> &lt;span style="color:#66d9ef">VALUES&lt;/span> (&lt;span style="color:#ae81ff">5&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;a5&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;o51&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;o52&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">SET&lt;/span> FOREIGN_KEY_CHECKS &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>;&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>MySQL 为我们提供了 &lt;code>EXPLAIN&lt;/code> 命令，来获取执行计划的相关信息。&lt;/p></description></item><item><title>sql常见面试题总结01</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/ly0503lysql-question-01/</link><pubDate>Sun, 12 Mar 2023 17:53:18 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/ly0503lysql-question-01/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;blockquote class='book-hint '>
&lt;p>题目来源于：
&lt;a target="_blank" href="https://www.nowcoder.com/exam/oj?page=1&amp;amp;tab=SQL%e7%af%87&amp;amp;topicId=298">牛客题霸 - SQL 必知必会&lt;/a>&lt;/p>&lt;/blockquote>&lt;h2 id="检索数据">检索数据&lt;a class="anchor" href="#%e6%a3%80%e7%b4%a2%e6%95%b0%e6%8d%ae">#&lt;/a>&lt;/h2>
&lt;p>&lt;code>select&lt;/code> 用于从数据库中查询数据。&lt;/p>
&lt;h3 id="从-customers-表中检索所有的-id">从 Customers 表中检索所有的 ID&lt;a class="anchor" href="#%e4%bb%8e-customers-%e8%a1%a8%e4%b8%ad%e6%a3%80%e7%b4%a2%e6%89%80%e6%9c%89%e7%9a%84-id">#&lt;/a>&lt;/h3>
&lt;p>现有表 &lt;code>Customers&lt;/code> 如下：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>cust_id&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>A&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>B&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>C&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>编写 SQL 语句，从 &lt;code>Customers&lt;/code> 表中检索所有的 &lt;code>cust_id&lt;/code>。&lt;/p>
&lt;p>答案：&lt;/p>
&lt;pre tabindex="0">&lt;code>select cust_id
from Customers;&lt;/code>&lt;/pre>&lt;h3 id="检索并列出已订购产品的清单">检索并列出已订购产品的清单&lt;a class="anchor" href="#%e6%a3%80%e7%b4%a2%e5%b9%b6%e5%88%97%e5%87%ba%e5%b7%b2%e8%ae%a2%e8%b4%ad%e4%ba%a7%e5%93%81%e7%9a%84%e6%b8%85%e5%8d%95">#&lt;/a>&lt;/h3>
&lt;p>表 &lt;code>OrderItems&lt;/code> 含有非空的列 &lt;code>prod_id&lt;/code> 代表商品 id，包含了所有已订购的商品（有些已被订购多次）。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>prod_id&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>a1&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>a2&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>a3&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>a4&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>a5&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>a6&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>a7&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>编写 SQL 语句，检索并列出所有已订购商品（&lt;code>prod_id&lt;/code>）的去重后的清单。&lt;/p>
&lt;p>答案：&lt;/p>
&lt;pre tabindex="0">&lt;code>select distinct prod_id
from OrderItems;&lt;/code>&lt;/pre>&lt;p>知识点：&lt;code>distinct&lt;/code> 用于返回列中的唯一不同值。&lt;/p>
&lt;h3 id="检索所有列">检索所有列&lt;a class="anchor" href="#%e6%a3%80%e7%b4%a2%e6%89%80%e6%9c%89%e5%88%97">#&lt;/a>&lt;/h3>
&lt;p>现在有 &lt;code>Customers&lt;/code> 表（表中含有列 &lt;code>cust_id&lt;/code> 代表客户 id，&lt;code>cust_name&lt;/code> 代表客户姓名）&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>cust_id&lt;/th>
 &lt;th>cust_name&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>a1&lt;/td>
 &lt;td>andy&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>a2&lt;/td>
 &lt;td>ben&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>a3&lt;/td>
 &lt;td>tony&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>a4&lt;/td>
 &lt;td>tom&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>a5&lt;/td>
 &lt;td>an&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>a6&lt;/td>
 &lt;td>lee&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>a7&lt;/td>
 &lt;td>hex&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>需要编写 SQL 语句，检索所有列。&lt;/p></description></item><item><title>sql语法基础知识总结</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/ly0504lysql-syntax-summary/</link><pubDate>Sun, 12 Mar 2023 17:52:48 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/ly0504lysql-syntax-summary/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;blockquote class='book-hint '>
&lt;p>本文整理完善自下面这两份资料：&lt;/p>
&lt;ul>
&lt;li>
&lt;a target="_blank" href="https://juejin.cn/post/6844903790571700231">SQL 语法速成手册&lt;/a>&lt;/li>
&lt;li>
&lt;a target="_blank" href="https://www.begtut.com/mysql/mysql-tutorial.html">MySQL 超全教程&lt;/a>&lt;/li>
&lt;/ul>&lt;/blockquote>&lt;h2 id="基本概念">基本概念&lt;a class="anchor" href="#%e5%9f%ba%e6%9c%ac%e6%a6%82%e5%bf%b5">#&lt;/a>&lt;/h2>
&lt;h3 id="数据库术语">数据库术语&lt;a class="anchor" href="#%e6%95%b0%e6%8d%ae%e5%ba%93%e6%9c%af%e8%af%ad">#&lt;/a>&lt;/h3>
&lt;ul>
&lt;li>&lt;code>数据库（database）&lt;/code> - 保存有组织的数据的容器（通常是一个文件或一组文件）。&lt;/li>
&lt;li>&lt;code>数据表（table）&lt;/code> - 某种特定类型数据的结构化清单。&lt;/li>
&lt;li>&lt;code>模式（schema）&lt;/code> - 关于数据库和表的布局及特性的信息。模式定义了数据在表中如何存储，包含存储什么样的数据，数据如何分解，各部分信息如何命名等信息。数据库和表都有模式。&lt;/li>
&lt;li>&lt;code>列（column）&lt;/code> - 表中的一个字段。所有表都是由一个或多个列组成的。&lt;/li>
&lt;li>&lt;code>行（row）&lt;/code> - 表中的一个记录。&lt;/li>
&lt;li>&lt;code>主键（primary key）&lt;/code> - 一列（或一组列），其值能够唯一标识表中每一行。&lt;/li>
&lt;/ul>
&lt;h3 id="sql-语法">SQL 语法&lt;a class="anchor" href="#sql-%e8%af%ad%e6%b3%95">#&lt;/a>&lt;/h3>
&lt;p>SQL（Structured Query Language)，标准 SQL 由 ANSI 标准委员会管理，从而称为 ANSI SQL。各个 DBMS 都有自己的实现，如 PL/SQL、Transact-SQL 等。&lt;/p>
&lt;h4 id="sql-语法结构">SQL 语法结构&lt;a class="anchor" href="#sql-%e8%af%ad%e6%b3%95%e7%bb%93%e6%9e%84">#&lt;/a>&lt;/h4>
&lt;p>&lt;img src="img/ly-20241212141857484.jpg" alt="img" />&lt;/p>
&lt;p>SQL 语法结构包括：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;code>子句&lt;/code>&lt;/strong> - 是语句和查询的组成成分。（在某些情况下，这些都是可选的。）&lt;/li>
&lt;li>&lt;strong>&lt;code>表达式&lt;/code>&lt;/strong> - 可以产生任何标量值，或由列和行的数据库表&lt;/li>
&lt;li>&lt;strong>&lt;code>谓词&lt;/code>&lt;/strong> - 给需要评估的 SQL 三值逻辑（3VL）（true/false/unknown）或布尔真值指定条件，并限制语句和查询的效果，或改变程序流程。&lt;/li>
&lt;li>&lt;strong>&lt;code>查询&lt;/code>&lt;/strong> - 基于特定条件检索数据。这是 SQL 的一个重要组成部分。&lt;/li>
&lt;li>&lt;strong>&lt;code>语句&lt;/code>&lt;/strong> - 可以持久地影响纲要和数据，也可以控制数据库事务、程序流程、连接、会话或诊断。&lt;/li>
&lt;/ul>
&lt;h4 id="sql-语法要点">SQL 语法要点&lt;a class="anchor" href="#sql-%e8%af%ad%e6%b3%95%e8%a6%81%e7%82%b9">#&lt;/a>&lt;/h4>
&lt;ul>
&lt;li>&lt;strong>SQL 语句不区分大小写&lt;/strong>，但是数据库表名、列名和值是否区分，依赖于具体的 DBMS 以及配置。例如：&lt;code>SELECT&lt;/code> 与 &lt;code>select&lt;/code> 、&lt;code>Select&lt;/code> 是相同的。&lt;/li>
&lt;li>&lt;strong>多条 SQL 语句必须以分号（&lt;code>;&lt;/code>）分隔&lt;/strong>。&lt;/li>
&lt;li>处理 SQL 语句时，&lt;strong>所有空格都被忽略&lt;/strong>。&lt;/li>
&lt;/ul>
&lt;p>SQL 语句可以写成一行，也可以分写为多行。&lt;/p></description></item><item><title>3种常用的缓存读写策略详解</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/Redis/ly0703ly3-commonly-used-cache-read-and-write-strategies/</link><pubDate>Fri, 24 Feb 2023 09:31:52 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/Redis/ly0703ly3-commonly-used-cache-read-and-write-strategies/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;p>看到很多小伙伴简历上写了“&lt;strong>熟练使用缓存&lt;/strong>”，但是被我问到“&lt;strong>缓存常用的3种读写策略&lt;/strong>”的时候却一脸懵逼。&lt;/p>
&lt;p>在我看来，造成这个问题的原因是我们在学习 Redis 的时候，可能只是简单了写一些 Demo，并没有去关注缓存的读写策略，或者说压根不知道这回事。&lt;/p>
&lt;p>但是，搞懂3种常见的缓存读写策略对于实际工作中使用缓存以及面试中被问到缓存都是非常有帮助的！&lt;/p>
&lt;p>&lt;strong>下面介绍到的三种模式各有优劣，不存在最佳模式，根据具体的业务场景选择适合自己的缓存读写模式。&lt;/strong>&lt;/p>
&lt;h3 id="cache-aside-pattern旁路缓存模式">Cache Aside Pattern（旁路缓存模式）&lt;a class="anchor" href="#cache-aside-pattern%e6%97%81%e8%b7%af%e7%bc%93%e5%ad%98%e6%a8%a1%e5%bc%8f">#&lt;/a>&lt;/h3>
&lt;p>&lt;strong>Cache Aside Pattern 是我们平时使用比较多的一个缓存读写模式，比较适合读请求比较多的场景。&lt;/strong>&lt;/p>
&lt;p>Cache Aside Pattern 中服务端需要同时维系 db 和 cache，并且是&lt;strong>以 db 的结果为准&lt;/strong>。&lt;/p>
&lt;p>下面我们来看一下这个策略模式下的缓存读写步骤。&lt;/p>
&lt;p>&lt;strong>写&lt;/strong> ：&lt;/p>
&lt;ul>
&lt;li>先更新 db&lt;/li>
&lt;li>然后直接删除 cache 。&lt;/li>
&lt;/ul>
&lt;p>简单画了一张图帮助大家理解写的步骤。&lt;/p>
&lt;p>&lt;img src="img/ly-20241212141916648.jpg" alt="img" />&lt;/p>
&lt;p>&lt;strong>读&lt;/strong> :&lt;/p>
&lt;ul>
&lt;li>从 cache 中读取数据，读取到就直接返回&lt;/li>
&lt;li>cache 中读取不到的话，就从 db 中读取数据返回&lt;/li>
&lt;li>再把数据放到 cache 中。&lt;/li>
&lt;/ul>
&lt;p>简单画了一张图帮助大家理解读的步骤。&lt;/p>
&lt;p>&lt;img src="img/ly-20241212141916935.png" alt="ly-20241212141916935" />&lt;/p>
&lt;p>你仅仅了解了上面这些内容的话是远远不够的，我们还要搞懂其中的原理。&lt;/p>
&lt;p>比如说面试官很可能会追问：“&lt;strong>在写数据的过程中，可以先删除 cache ，后更新 db 么？&lt;/strong>”&lt;/p>
&lt;p>&lt;strong>答案：&lt;/strong> 那肯定是不行的！因为这样可能会造成 &lt;strong>数据库（db）和缓存（Cache）数据不一致&lt;/strong>的问题。&lt;/p>
&lt;p>举例：请求 1 先写数据 A，请求 2 随后读数据 A 的话，就很有可能产生数据不一致性的问题。&lt;/p>
&lt;p>这个过程可以简单描述为：&lt;/p>
&lt;blockquote class='book-hint '>
&lt;p>请求 1 先把 cache 中的 A 数据删除 -&amp;gt; 请求 2 从 db 中读取数据【&lt;strong>此时请求2把脏数据(对于请求1来说是)更新到缓存去了&lt;/strong>】-&amp;gt;请求 1 再把 db 中的 A 数据更新，即请求1的操作非原子&lt;/p></description></item><item><title>redis内存碎片</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/Redis/ly0704lyredis-memory-fragmentation/</link><pubDate>Fri, 24 Feb 2023 09:26:00 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/Redis/ly0704lyredis-memory-fragmentation/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;h2 id="什么是内存碎片">什么是内存碎片?&lt;a class="anchor" href="#%e4%bb%80%e4%b9%88%e6%98%af%e5%86%85%e5%ad%98%e7%a2%8e%e7%89%87">#&lt;/a>&lt;/h2>
&lt;p>你可以将内存碎片简单地理解为那些&lt;strong>不可用的空闲内存&lt;/strong>。&lt;/p>
&lt;p>举个例子：操作系统为你分配了 32 字节的连续内存空间，而你存储数据实际只需要使用 24 字节内存空间，那这多余出来的 8 字节内存空间如果后续没办法再被分配存储其他数据的话，就可以被称为内存碎片。&lt;/p>
&lt;p>&lt;img src="img/ly-20241212141917438.png" alt="ly-20241212141917438" />&lt;/p>
&lt;p>Redis 内存碎片虽然不会影响 Redis 性能，但是会&lt;strong>增加内存消耗&lt;/strong>。&lt;/p>
&lt;h2 id="为什么会有-redis-内存碎片">为什么会有 Redis 内存碎片?&lt;a class="anchor" href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e4%bc%9a%e6%9c%89-redis-%e5%86%85%e5%ad%98%e7%a2%8e%e7%89%87">#&lt;/a>&lt;/h2>
&lt;p>Redis 内存碎片产生比较常见的 2 个原因：&lt;/p>
&lt;p>&lt;strong>1、Redis 存储存储数据的时候向操作系统申请的内存空间可能会大于数据实际需要的存储空间。&lt;/strong>&lt;/p>
&lt;p>以下是这段 Redis 官方的原话：&lt;/p>
&lt;blockquote class='book-hint '>
&lt;p>To store user keys, Redis allocates at most as much memory as the &lt;code>maxmemory&lt;/code> setting enables (however there are small extra allocations possible).&lt;/p>&lt;/blockquote>&lt;p>Redis 使用 &lt;code>zmalloc&lt;/code> 方法(Redis 自己实现的内存分配方法)进行内存分配的时候，除了要分配 &lt;code>size&lt;/code> 大小的内存之外，还会多分配 &lt;code>PREFIX_SIZE&lt;/code> 大小的内存。&lt;/p>
&lt;p>&lt;code>zmalloc&lt;/code> 方法源码如下（源码地址：https://github.com/antirez/redis-tools/blob/master/zmalloc.c）：&lt;/p>
&lt;pre tabindex="0">&lt;code>void *zmalloc(size_t size) {
 // 分配指定大小的内存
 void *ptr = malloc(size+PREFIX_SIZE);
 if (!ptr) zmalloc_oom_handler(size);
#ifdef HAVE_MALLOC_SIZE
 update_zmalloc_stat_alloc(zmalloc_size(ptr));
 return ptr;
#else
 *((size_t*)ptr) = size;
 update_zmalloc_stat_alloc(size+PREFIX_SIZE);
 return (char*)ptr+PREFIX_SIZE;
#endif
}&lt;/code>&lt;/pre>&lt;p>另外，Redis 可以使用&lt;strong>多种内存分配器&lt;/strong>来分配内存（ &lt;strong>libc&lt;/strong>、&lt;strong>jemalloc&lt;/strong>、&lt;strong>tcmalloc&lt;/strong>），默认使用 
&lt;a target="_blank" href="https://github.com/jemalloc/jemalloc">jemalloc&lt;/a>，而 jemalloc 按照一系列固定的大小（8 字节、16 字节、32 字节&amp;hellip;&amp;hellip;）来分配内存的。jemalloc 划分的内存单元如下图所示：&lt;/p></description></item><item><title>redis特殊数据结构</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/Redis/ly0702lyredis-spec-data-structure/</link><pubDate>Thu, 23 Feb 2023 23:02:58 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/Redis/ly0702lyredis-spec-data-structure/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;p>除了 5 种基本的数据结构之外，Redis 还支持 3 种特殊的数据结构 ：&lt;strong>Bitmap&lt;/strong>、&lt;strong>HyperLogLog&lt;/strong>、&lt;strong>GEO&lt;/strong>。&lt;/p>
&lt;h2 id="bitmap">Bitmap&lt;a class="anchor" href="#bitmap">#&lt;/a>&lt;/h2>
&lt;h3 id="介绍">介绍&lt;a class="anchor" href="#%e4%bb%8b%e7%bb%8d">#&lt;/a>&lt;/h3>
&lt;p>Bitmap 存储的是连续的二进制数字（0 和 1），通过 Bitmap, &lt;strong>只需要一个 bit 位来表示某个元素对应的值&lt;/strong>或者&lt;strong>状态&lt;/strong>，key 就是对应元素本身 。我们知道 8 个 bit 可以组成一个 byte，所以 Bitmap 本身会极大的节省储存空间。&lt;/p>
&lt;p>你可以将 Bitmap 看作是一个&lt;strong>存储二进制数字（0 和 1）的数组&lt;/strong>，数组中每个元素的下标叫做 offset（偏移量）。&lt;/p>
&lt;p>
&lt;a target="_blank" href="https://camo.githubusercontent.com/1c1ce8351556fe9727cadfd385fdbd6f449d92a174bbd65db5383791fec05a13/68747470733a2f2f67756964652d626c6f672d696d616765732e6f73732d636e2d7368656e7a68656e2e616c6979756e63732e636f6d2f6769746875622f6a61766167756964652f64617461626173652f72656469732f696d6167652d32303232303732303139343135343133332e706e67">&lt;img src="https://camo.githubusercontent.com/1c1ce8351556fe9727cadfd385fdbd6f449d92a174bbd65db5383791fec05a13/68747470733a2f2f67756964652d626c6f672d696d616765732e6f73732d636e2d7368656e7a68656e2e616c6979756e63732e636f6d2f6769746875622f6a61766167756964652f64617461626173652f72656469732f696d6167652d32303232303732303139343135343133332e706e67" alt="img" />&lt;/a>&lt;/p>
&lt;h3 id="常用命令">常用命令&lt;a class="anchor" href="#%e5%b8%b8%e7%94%a8%e5%91%bd%e4%bb%a4">#&lt;/a>&lt;/h3>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>命令&lt;/th>
 &lt;th>介绍&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>SETBIT key offset value&lt;/td>
 &lt;td>设置指定 offset 位置的值&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>GETBIT key offset&lt;/td>
 &lt;td>获取指定 offset 位置的值&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>BITCOUNT key start end&lt;/td>
 &lt;td>获取 start 和 end 之前值为 1 的元素个数&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>BITOP operation destkey key1 key2 &amp;hellip;&lt;/td>
 &lt;td>对一个或多个 Bitmap 进行运算，可用运算符有 AND, OR, XOR 以及 NOT&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>Bitmap 基本操作演示&lt;/strong> ：&lt;/p></description></item><item><title>redis基本数据结构</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/Redis/ly0701lyredis-base-data-structures/</link><pubDate>Thu, 23 Feb 2023 14:22:58 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/Redis/ly0701lyredis-base-data-structures/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;p>Redis 共有 5 种基本数据结构：&lt;strong>String&lt;/strong>（字符串）、&lt;strong>List&lt;/strong>（列表）、&lt;strong>Set&lt;/strong>（集合）、&lt;strong>Hash&lt;/strong>（散列）、&lt;strong>Zset&lt;/strong>（有序集合）。&lt;/p>
&lt;p>这 5 种数据结构是直接提供给用户使用的，是数据的保存形式，其底层实现主要依赖这 8 种数据结构：简单动态字符串（&lt;strong>SDS&lt;/strong>）、&lt;strong>LinkedList&lt;/strong>（双向链表）、&lt;strong>Hash Table&lt;/strong>（哈希表）、&lt;strong>SkipList&lt;/strong>（跳跃表）、&lt;strong>Intset&lt;/strong>（整数集合）、&lt;strong>ZipList&lt;/strong>（压缩列表）、&lt;strong>QuickList&lt;/strong>（快速列表）。&lt;/p>
&lt;p>Redis 基本数据结构的底层数据结构实现如下：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>String&lt;/th>
 &lt;th>List&lt;/th>
 &lt;th>Hash&lt;/th>
 &lt;th>Set&lt;/th>
 &lt;th>Zset&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>SDS&lt;/td>
 &lt;td>LinkedList/ZipList/QuickList&lt;/td>
 &lt;td>Hash Table、ZipList&lt;/td>
 &lt;td>ZipList、Intset&lt;/td>
 &lt;td>ZipList、SkipList&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>Redis 3.2 之前，List 底层实现是 LinkedList 或者 ZipList。 Redis 3.2 之后，引入了 LinkedList 和 ZipList 的结合 QuickList，List 的底层实现变为 QuickList。&lt;/p>
&lt;p>你可以在 Redis 官网上找到 Redis 数据结构非常详细的介绍：&lt;/p>
&lt;ul>
&lt;li>
&lt;a target="_blank" href="https://redis.com/redis-enterprise/data-structures/">Redis Data Structures&lt;/a>&lt;/li>
&lt;li>
&lt;a target="_blank" href="https://redis.io/docs/manual/data-types/data-types-tutorial/">Redis Data types tutorial&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>未来随着 Redis 新版本的发布，可能会有新的数据结构出现，通过查阅 Redis 官网对应的介绍，你总能获取到最靠谱的信息。&lt;/p>
&lt;p>&lt;img src="img/ly-20241212141914862.png" alt="ly-20241212141914862" />&lt;/p>
&lt;h2 id="string字符串">String（字符串）&lt;a class="anchor" href="#string%e5%ad%97%e7%ac%a6%e4%b8%b2">#&lt;/a>&lt;/h2>
&lt;h3 id="介绍">介绍&lt;a class="anchor" href="#%e4%bb%8b%e7%bb%8d">#&lt;/a>&lt;/h3>
&lt;p>String 是 Redis 中最简单同时也是最常用的一个数据结构。&lt;/p>
&lt;p>String 是一种&lt;strong>二进制安全&lt;/strong>的数据结构，可以用来&lt;strong>存储任何类型的数据&lt;/strong>比如&lt;strong>字符串&lt;/strong>、&lt;strong>整数&lt;/strong>、&lt;strong>浮点数&lt;/strong>、&lt;strong>图片&lt;/strong>（图片的 base64 编码或者解码或者图片的路径）、&lt;strong>序列化后的对象&lt;/strong>。&lt;/p>
&lt;p>&lt;img src="img/ly-20241212141915150.png" alt="ly-20241212141915150" />&lt;/p></description></item><item><title>redis面试题02</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/Redis/ly0706lyredis-questions-02/</link><pubDate>Thu, 23 Feb 2023 11:16:04 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/Redis/ly0706lyredis-questions-02/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;h2 id="redis-事务">Redis 事务&lt;a class="anchor" href="#redis-%e4%ba%8b%e5%8a%a1">#&lt;/a>&lt;/h2>
&lt;h3 id="如何使用-redis-事务">如何使用 Redis 事务？&lt;a class="anchor" href="#%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8-redis-%e4%ba%8b%e5%8a%a1">#&lt;/a>&lt;/h3>
&lt;p>Redis 可以通过 &lt;strong>&lt;code>MULTI&lt;/code>，&lt;code>EXEC&lt;/code>，&lt;code>DISCARD&lt;/code> 和 &lt;code>WATCH&lt;/code>&lt;/strong> 等命令来实现事务(transaction)功能。&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;gt; MULTI
OK
&amp;gt; SET PROJECT &amp;#34;JavaGuide&amp;#34;
QUEUED
&amp;gt; GET PROJECT
QUEUED
&amp;gt; EXEC
1) OK
2) &amp;#34;JavaGuide&amp;#34;&lt;/code>&lt;/pre>&lt;p>
&lt;a target="_blank" href="https://redis.io/commands/multi">&lt;code>MULTI&lt;/code>&lt;/a> 命令后可以输入多个命令，Redis 不会立即执行这些命令，而是将它们放到队列，当调用了 
&lt;a target="_blank" href="https://redis.io/commands/exec">&lt;code>EXEC&lt;/code>&lt;/a> 命令后，再执行所有的命令。&lt;/p>
&lt;p>这个过程是这样的：&lt;/p>
&lt;ol>
&lt;li>开始事务（&lt;code>MULTI&lt;/code>）；&lt;/li>
&lt;li>命令入队(批量操作 Redis 的命令，先进先出（FIFO）的顺序执行)；&lt;/li>
&lt;li>执行事务(&lt;code>EXEC&lt;/code>)。&lt;/li>
&lt;/ol>
&lt;p>你也可以通过 
&lt;a target="_blank" href="https://redis.io/commands/discard">&lt;code>DISCARD&lt;/code>&lt;/a> 命令取消一个事务，它会清空事务队列中保存的所有命令。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>&amp;gt; MULTI
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>OK
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;gt; SET PROJECT &lt;span style="color:#e6db74">&amp;#34;JavaGuide&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>QUEUED
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;gt; GET PROJECT
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>QUEUED
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;gt; DISCARD
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>OK&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>你可以通过
&lt;a target="_blank" href="https://redis.io/commands/watch">&lt;code>WATCH&lt;/code>&lt;/a> 命令监听指定的 Key，当调用 &lt;code>EXEC&lt;/code> 命令执行事务时，如果一个被 &lt;code>WATCH&lt;/code> 命令监视的 Key 被 &lt;strong>其他客户端/Session&lt;/strong> 修改的话，整个事务都不会被执行。&lt;/p>
&lt;pre tabindex="0">&lt;code># 客户端 1
&amp;gt; SET PROJECT &amp;#34;RustGuide&amp;#34;
OK
&amp;gt; WATCH PROJECT
OK
&amp;gt; MULTI
OK
&amp;gt; SET PROJECT &amp;#34;JavaGuide&amp;#34;
QUEUED

# 客户端 2
# 在客户端 1 执行 EXEC 命令提交事务之前修改 PROJECT 的值
&amp;gt; SET PROJECT &amp;#34;GoGuide&amp;#34;

# 客户端 1
# 修改失败，因为 PROJECT 的值被客户端2修改了
&amp;gt; EXEC
(nil)
&amp;gt; GET PROJECT
&amp;#34;GoGuide&amp;#34;&lt;/code>&lt;/pre>&lt;p>不过，如果 &lt;strong>WATCH&lt;/strong> 与 &lt;strong>事务&lt;/strong> 在同一个 Session 里，并且被 &lt;strong>WATCH&lt;/strong> 监视的 Key 被修改的操作发生在事务内部，这个事务是可以被执行成功的（相关 issue ：
&lt;a target="_blank" href="https://github.com/Snailclimb/JavaGuide/issues/1714">WATCH 命令碰到 MULTI 命令时的不同效果&lt;/a>）。&lt;/p></description></item><item><title>redis面试题01</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/Redis/ly0705lyredis-questions-01/</link><pubDate>Wed, 22 Feb 2023 11:31:11 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/Redis/ly0705lyredis-questions-01/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;h2 id="redis-基础">Redis 基础&lt;a class="anchor" href="#redis-%e5%9f%ba%e7%a1%80">#&lt;/a>&lt;/h2>
&lt;h3 id="什么是-redis">什么是 Redis？&lt;a class="anchor" href="#%e4%bb%80%e4%b9%88%e6%98%af-redis">#&lt;/a>&lt;/h3>
&lt;p>
&lt;a target="_blank" href="https://redis.io/">Redis&lt;/a> 是一个基于 C 语言开发的开源数据库（BSD 许可），与传统数据库不同的是 Redis 的数据是存在&lt;strong>内存&lt;/strong>中的（内存数据库），&lt;strong>读写&lt;/strong>速度非常&lt;strong>快&lt;/strong>，被广泛应用于&lt;strong>缓存方向&lt;/strong>。并且，Redis 存储的是 &lt;strong>KV 键值对&lt;/strong>数据。&lt;/p>
&lt;p>为了满足不同的业务场景，Redis 内置了多种数据类型实现（比如 &lt;strong>String&lt;/strong>、&lt;strong>Hash&lt;/strong>、【&lt;strong>List&lt;/strong>、&lt;strong>Set&lt;/strong>、】&lt;strong>Sorted Set&lt;/strong>、&lt;strong>Bitmap&lt;/strong>）。并且，Redis 还支持&lt;strong>事务&lt;/strong> 、&lt;strong>持久化&lt;/strong>、&lt;strong>Lua 脚本&lt;/strong>、多种开箱即用的&lt;strong>集群&lt;/strong>方案（&lt;strong>Redis Sentinel&lt;/strong>、&lt;strong>Redis Cluster&lt;/strong>）。&lt;/p>
&lt;p>Redis 没有外部依赖，Linux 和 OS X 是 Redis 开发和测试最多的两个操作系统，官方推荐生产环境使用 Linux 部署 Redis。&lt;/p>
&lt;p>个人学习的话，你可以自己本机安装 Redis 或者通过 Redis 官网提供的
&lt;a target="_blank" href="https://try.redis.io/">在线 Redis 环境&lt;/a>来实际体验 Redis。&lt;/p>
&lt;p>&lt;img src="img/ly-20241212141918257.png" alt="ly-20241212141918257" />&lt;/p>
&lt;p>全世界有非常多的网站使用到了 Redis ，
&lt;a target="_blank" href="https://techstacks.io/">techstacks.io&lt;/a> 专门维护了一个
&lt;a target="_blank" href="https://techstacks.io/tech/redis">使用 Redis 的热门站点列表&lt;/a> ，感兴趣的话可以看看。&lt;/p>
&lt;h3 id="redis-为什么这么快">Redis 为什么这么快？&lt;a class="anchor" href="#redis-%e4%b8%ba%e4%bb%80%e4%b9%88%e8%bf%99%e4%b9%88%e5%bf%ab">#&lt;/a>&lt;/h3>
&lt;p>Redis 内部做了非常多的性能优化，比较重要的主要有下面 3 点：&lt;/p>
&lt;ul>
&lt;li>Redis 基于&lt;strong>内存&lt;/strong>，内存的访问速度是磁盘的上千倍；&lt;/li>
&lt;li>Redis &lt;strong>基于 Reactor 模式&lt;/strong>设计开发了一套&lt;strong>高效的事件处理模型&lt;/strong>，主要是&lt;strong>单线程事件循环&lt;/strong>和 &lt;strong>IO 多路复用&lt;/strong>（Redis 线程模式后面会详细介绍到）；&lt;/li>
&lt;li>Redis 内置了多种&lt;strong>优化过后的数据结构&lt;/strong>实现，性能非常高。&lt;/li>
&lt;/ul>
&lt;p>下面这张图片总结的挺不错的，分享一下，出自 
&lt;a target="_blank" href="https://twitter.com/alexxubyte/status/1498703822528544770">Why is Redis so fast?&lt;/a> 。&lt;/p></description></item><item><title>git</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/lyaly_dev_tools/git/</link><pubDate>Tue, 07 Feb 2023 16:14:19 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/lyaly_dev_tools/git/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;h2 id="版本控制">版本控制&lt;a class="anchor" href="#%e7%89%88%e6%9c%ac%e6%8e%a7%e5%88%b6">#&lt;/a>&lt;/h2>
&lt;h3 id="什么是版本控制">什么是版本控制&lt;a class="anchor" href="#%e4%bb%80%e4%b9%88%e6%98%af%e7%89%88%e6%9c%ac%e6%8e%a7%e5%88%b6">#&lt;/a>&lt;/h3>
&lt;p>&lt;strong>版本控制&lt;/strong>是一种&lt;strong>记录一个&lt;/strong>或&lt;strong>若干文件内容变化&lt;/strong>，以便&lt;strong>将来查阅特定版本修订情况&lt;/strong>的系统。 除了&lt;strong>项目源代码&lt;/strong>，你还可以对&lt;strong>任何类型的文件&lt;/strong>进行版本控制。&lt;/p>
&lt;h3 id="为什么要版本控制">为什么要版本控制&lt;a class="anchor" href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e8%a6%81%e7%89%88%e6%9c%ac%e6%8e%a7%e5%88%b6">#&lt;/a>&lt;/h3>
&lt;p>有了它你就可以将某个文件&lt;strong>回溯到之前的状态&lt;/strong>，甚至将&lt;strong>整个项目都回退到过去某个时间点&lt;/strong>的状态，你可以&lt;strong>比较&lt;/strong>文件的变化细节，&lt;strong>查出最后&lt;/strong>是谁修改了哪个地方，从而&lt;strong>找出导致怪异问题&lt;/strong>出现的原因，又是&lt;strong>谁在何时报告了&lt;/strong>某个功能缺陷等等。&lt;/p>
&lt;h3 id="本地版本控制系统">本地版本控制系统&lt;a class="anchor" href="#%e6%9c%ac%e5%9c%b0%e7%89%88%e6%9c%ac%e6%8e%a7%e5%88%b6%e7%b3%bb%e7%bb%9f">#&lt;/a>&lt;/h3>
&lt;p>许多人习惯用&lt;strong>复制整个项目&lt;/strong>目录的方式来&lt;strong>保存不同的版本&lt;/strong>，或许还会&lt;strong>改名加上备份时间&lt;/strong>以示区别。 这么做唯一的好处就是&lt;strong>简单&lt;/strong>，但是特别容&lt;strong>易犯错&lt;/strong>。 有时候会&lt;strong>混淆&lt;/strong>所在的工作目录，一不小心会&lt;strong>写错&lt;/strong>文件或者&lt;strong>覆盖&lt;/strong>意想外的文件。&lt;/p>
&lt;p>为了解决这个问题，人们很久以前就开发了许多种&lt;strong>本地版本控制&lt;/strong>系统，大多都是采用某种&lt;strong>简单的数据库&lt;/strong>来&lt;strong>记录文件的历次更新&lt;/strong>差异。&lt;/p>
&lt;p>&lt;img src="img/ly-20241212142006392.png" alt="image.png" />&lt;/p>
&lt;h3 id="集中化的版本控制系统">集中化的版本控制系统&lt;a class="anchor" href="#%e9%9b%86%e4%b8%ad%e5%8c%96%e7%9a%84%e7%89%88%e6%9c%ac%e6%8e%a7%e5%88%b6%e7%b3%bb%e7%bb%9f">#&lt;/a>&lt;/h3>
&lt;p>接下来人们又遇到一个问题，如何让在&lt;strong>不同系统上的开发者协同&lt;/strong>工作？ 于是，&lt;strong>集中化的版本控制&lt;/strong>系统（&lt;strong>Centralized Version Control Systems&lt;/strong>，简称 &lt;strong>CVCS&lt;/strong>）应运而生。&lt;/p>
&lt;p>集中化的版本控制系统都有一个&lt;strong>单一的集中管理的服务器&lt;/strong>，&lt;strong>保存所有文件的修订版本&lt;/strong>，而协同工作的人们都通过客户端&lt;strong>连到这台服务器&lt;/strong>，取出&lt;strong>最新&lt;/strong>的文件或者&lt;strong>提交更新&lt;/strong>。&lt;/p>
&lt;p>&lt;img src="img/ly-20241212142006663.png" alt="image.png" />&lt;/p>
&lt;p>这么做虽然解决了本地版本控制系统无法让在不同系统上的开发者协同工作的诟病，但也还是存在下面的问题：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>单点故障：&lt;/strong> &lt;strong>中央服务器宕机&lt;/strong>，则其他人无法使用；如果中心数据库磁盘损坏又没有进行备份，你将丢失所有数据。本地版本控制系统也存在类似问题，只要整个项目的历史记录被&lt;strong>保存在单一&lt;/strong>位置，就有&lt;strong>丢失所有历史更新记录&lt;/strong>的风险。&lt;/li>
&lt;li>&lt;strong>必须联网才能工作：&lt;/strong> &lt;strong>受网络&lt;/strong>状况、带宽影响。&lt;/li>
&lt;/ul>
&lt;h3 id="分布式版本控制系统">分布式版本控制系统&lt;a class="anchor" href="#%e5%88%86%e5%b8%83%e5%bc%8f%e7%89%88%e6%9c%ac%e6%8e%a7%e5%88%b6%e7%b3%bb%e7%bb%9f">#&lt;/a>&lt;/h3>
&lt;p>于是分布式版本控制系统（&lt;strong>Distributed Version Control System&lt;/strong>，简称 &lt;strong>DVCS&lt;/strong>）面世了。 Git 就是一个典型的分布式版本控制系统。&lt;/p>
&lt;p>这类系统，客户端并&lt;strong>不只提取最新版本的文件快照&lt;/strong>，而是把&lt;strong>代码仓库完整地镜像&lt;/strong>下来。 这么一来，任何一处协同工作用的服务器发生故障，事后都可以用&lt;strong>任何一个镜像出来的本地仓库&lt;/strong>恢复。 因为每一次的克隆操作，实际上都是一次对&lt;strong>代码仓库的完整备份&lt;/strong>。&lt;/p>
&lt;p>&lt;img src="img/ly-20241212142006803.png" alt="image.png" />&lt;/p>
&lt;p>分布式版本控制系统可以&lt;strong>不用联网就可以工作&lt;/strong>，因为每个人的电脑上都是完整的版本库，当你修改了某个文件后，你只需要&lt;strong>将自己的修改推送给别人&lt;/strong>就可以了。但是，在实际使用分布式版本控制系统的时候，很少会&lt;strong>直接进行推送&lt;/strong>修改，而是&lt;strong>使用一台充当“中央服务器”&lt;strong>的东西。这个服务器的作用仅仅是用来&lt;/strong>方便“交换”大家的修改&lt;/strong>，没有它大家也一样干活，只是交换修改不方便而已。&lt;/p>
&lt;p>分布式版本控制系统的优势不单是不必联网这么简单，后面我们还会看到 Git 极其&lt;strong>强大的分支管理&lt;/strong>等功能。&lt;/p>
&lt;h2 id="认识-git">认识 Git&lt;a class="anchor" href="#%e8%ae%a4%e8%af%86-git">#&lt;/a>&lt;/h2>
&lt;h3 id="git-简史">Git 简史&lt;a class="anchor" href="#git-%e7%ae%80%e5%8f%b2">#&lt;/a>&lt;/h3>
&lt;p>Linux 内核项目组当时使用分布式版本控制系统 &lt;strong>BitKeeper&lt;/strong> 来管理和维护代码。但是，后来开发 BitKeeper 的商业公司同 Linux 内核开源社区的合作关系结束，他们收回了 Linux 内核社区免费使用 BitKeeper 的权力。 Linux 开源社区（特别是 Linux 的缔造者 &lt;strong>Linus Torvalds&lt;/strong>）基于使用 BitKeeper 时的经验教训，开发出自己的版本系统，而且对新的版本控制系统做了很多改进。&lt;/p></description></item><item><title>MySQL高性能优化规范建议总结</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/MySQL/ly0611lymysql-high-performance-optimization-specification-recommendations/</link><pubDate>Fri, 20 Jan 2023 11:36:34 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/MySQL/ly0611lymysql-high-performance-optimization-specification-recommendations/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;blockquote class='book-hint '>
&lt;p>索引优化相关&lt;/p>
&lt;ol>
&lt;li>in 代替 or&lt;/li>
&lt;li>not exist 代替 not in&lt;/li>
&lt;/ol>&lt;/blockquote>&lt;h1 id="数据库命名规范">数据库命名规范&lt;a class="anchor" href="#%e6%95%b0%e6%8d%ae%e5%ba%93%e5%91%bd%e5%90%8d%e8%a7%84%e8%8c%83">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>所有&lt;strong>数据库对象&lt;/strong>名称必须使用&lt;strong>小写字母&lt;/strong>并用&lt;strong>下划线分割&lt;/strong>&lt;/li>
&lt;li>所有数据库对象名称&lt;strong>禁止使用 MySQL 保留关键字&lt;/strong>（如果表名中包含关键字查询时，需要将其用单引号括起来）&lt;/li>
&lt;li>数据库对象的命名要能做到&lt;strong>见名识意&lt;/strong>，并且最好&lt;strong>不要超过 32 个&lt;/strong>字符&lt;/li>
&lt;li>&lt;strong>临时库表&lt;/strong>必须&lt;strong>以 &lt;code>tmp_&lt;/code> 为前缀&lt;/strong>并以日期为后缀，&lt;strong>备份表&lt;/strong>必须&lt;strong>以 &lt;code>bak_&lt;/code> 为前缀&lt;/strong>并&lt;strong>以日期 (时间戳) 为后缀&lt;/strong>&lt;/li>
&lt;li>所有&lt;strong>存储相同数据的列名和列类型&lt;/strong>必须一致（&lt;strong>一般作为关联列&lt;/strong>，如果查询时关联列&lt;strong>类型不一致会自动进行数据类型隐式转换&lt;/strong>，会&lt;strong>造成列上的索引失效&lt;/strong>，导致查询效率降低）&lt;/li>
&lt;/ul>
&lt;h1 id="数据库基本设计规范">数据库基本设计规范&lt;a class="anchor" href="#%e6%95%b0%e6%8d%ae%e5%ba%93%e5%9f%ba%e6%9c%ac%e8%ae%be%e8%ae%a1%e8%a7%84%e8%8c%83">#&lt;/a>&lt;/h1>
&lt;h2 id="所有表必须使用innodb存储引擎">所有表必须使用InnoDB存储引擎&lt;a class="anchor" href="#%e6%89%80%e6%9c%89%e8%a1%a8%e5%bf%85%e9%a1%bb%e4%bd%bf%e7%94%a8innodb%e5%ad%98%e5%82%a8%e5%bc%95%e6%93%8e">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>没有特殊要求（即 InnoDB 无法满足的功能如：列存储，存储空间数据等）的情况下，所有表必须使用 InnoDB 存储引擎（MySQL5.5 之前默认使用 Myisam，5.6 以后默认的为 InnoDB）。&lt;/li>
&lt;li>InnoDB 支持&lt;strong>事务&lt;/strong>，支持&lt;strong>行级锁&lt;/strong>，更好的&lt;strong>恢复性&lt;/strong>，&lt;strong>高并发&lt;/strong>下性能更好&lt;/li>
&lt;/ul>
&lt;h2 id="数据库和表的字符集统一使用utf-8">数据库和表的字符集统一使用UTF-8&lt;a class="anchor" href="#%e6%95%b0%e6%8d%ae%e5%ba%93%e5%92%8c%e8%a1%a8%e7%9a%84%e5%ad%97%e7%ac%a6%e9%9b%86%e7%bb%9f%e4%b8%80%e4%bd%bf%e7%94%a8utf-8">#&lt;/a>&lt;/h2>
&lt;p>&lt;strong>兼容性&lt;/strong>更好，&lt;strong>统一字符集&lt;/strong>可以避免由于字符集转换产生的&lt;strong>乱码&lt;/strong>，不同的字符集进行比较前需要进行转换会造成&lt;strong>索引失效&lt;/strong>，如果数据库中有&lt;strong>存储 emoji 表情&lt;/strong>的需要，字符集需要采用 &lt;strong>utf8mb4&lt;/strong> 字符集。&lt;/p>
&lt;p>参考文章：&lt;/p>
&lt;ul>
&lt;li>
&lt;a target="_blank" href="https://blog.csdn.net/horses/article/details/107243447">MySQL 字符集不一致导致索引失效的一个真实案例open in new window&lt;/a>&lt;/li>
&lt;li>[MySQL 字符集详解&lt;/li>
&lt;/ul>
&lt;h2 id="所有表和字段都需要添加注释">所有表和字段都需要添加注释&lt;a class="anchor" href="#%e6%89%80%e6%9c%89%e8%a1%a8%e5%92%8c%e5%ad%97%e6%ae%b5%e9%83%bd%e9%9c%80%e8%a6%81%e6%b7%bb%e5%8a%a0%e6%b3%a8%e9%87%8a">#&lt;/a>&lt;/h2>
&lt;p>使用 &lt;strong>comment 从句添加表&lt;/strong>和&lt;strong>列的备注&lt;/strong>，从一开始就进行数据字典的维护&lt;/p>
&lt;h2 id="尽量控制单表数据量的大小建议控制在500万以内">尽量控制单表数据量的大小，建议控制在500万以内&lt;a class="anchor" href="#%e5%b0%bd%e9%87%8f%e6%8e%a7%e5%88%b6%e5%8d%95%e8%a1%a8%e6%95%b0%e6%8d%ae%e9%87%8f%e7%9a%84%e5%a4%a7%e5%b0%8f%e5%bb%ba%e8%ae%ae%e6%8e%a7%e5%88%b6%e5%9c%a8500%e4%b8%87%e4%bb%a5%e5%86%85">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>500 万并不是 MySQL 数据库的限制，&lt;strong>过大会造成修改表结构&lt;/strong>，&lt;strong>备份&lt;/strong>，&lt;strong>恢复&lt;/strong>都会有很大的问题。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>可以用&lt;strong>历史数据归档（应用于日志数据）&lt;/strong>，**分库分表（应用于业务数据）**等手段来控制数据量大小&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="谨慎使用mysql分区表">谨慎使用MySQL分区表&lt;a class="anchor" href="#%e8%b0%a8%e6%85%8e%e4%bd%bf%e7%94%a8mysql%e5%88%86%e5%8c%ba%e8%a1%a8">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>分区表在&lt;strong>物理上表现为多个文件&lt;/strong>，在&lt;strong>逻辑上表现为一个表&lt;/strong>；&lt;/p>
&lt;/li>
&lt;li>
&lt;p>谨慎选择分区键，&lt;strong>跨分区查询效率可能更低&lt;/strong>；&lt;/p>
&lt;/li>
&lt;li>
&lt;p>建议采用&lt;strong>物理分表的方式管理大数据&lt;/strong>。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="经常一起使用的列放到一个表中">经常一起使用的列放到一个表中&lt;a class="anchor" href="#%e7%bb%8f%e5%b8%b8%e4%b8%80%e8%b5%b7%e4%bd%bf%e7%94%a8%e7%9a%84%e5%88%97%e6%94%be%e5%88%b0%e4%b8%80%e4%b8%aa%e8%a1%a8%e4%b8%ad">#&lt;/a>&lt;/h2>
&lt;p>避免更多的关联操作。&lt;/p></description></item><item><title>MySQL常见面试题总结</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/MySQL/ly0610lymysql-questions-01/</link><pubDate>Fri, 20 Jan 2023 11:36:06 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/MySQL/ly0610lymysql-questions-01/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!====&lt;/p>&lt;/blockquote>&lt;h1 id="mysql基础">MySQL基础&lt;a class="anchor" href="#mysql%e5%9f%ba%e7%a1%80">#&lt;/a>&lt;/h1>
&lt;h2 id="关系型数据库介绍">关系型数据库介绍&lt;a class="anchor" href="#%e5%85%b3%e7%b3%bb%e5%9e%8b%e6%95%b0%e6%8d%ae%e5%ba%93%e4%bb%8b%e7%bb%8d">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>关系型数据库&lt;/strong>，建立在&lt;strong>关系模型&lt;/strong>的基础上的数据库。表明数据库中所&lt;strong>存储&lt;/strong>的数据之间的&lt;strong>联系&lt;/strong>（一对一、一对多、多对多）&lt;/li>
&lt;li>关系型数据库中，我们的数据都被&lt;strong>存放在各种表&lt;/strong>中（比如用户表），表中的&lt;strong>每一行&lt;/strong>存放着&lt;strong>一条数据（比如一个用户的信息）&lt;/strong>
&lt;img src="img/ly-20241212141910786.png" alt="关系型数据库表关系" />&lt;/li>
&lt;li>大部分关系型数据库都使用&lt;strong>SQL&lt;/strong>来操作数据库中的数据，并且大部分&lt;strong>关系型数据库&lt;/strong>都支持&lt;strong>事务&lt;/strong>的&lt;strong>四大特性（ACID）&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>常见的关系型数据库&lt;/strong>&lt;br>
&lt;strong>MySQL&lt;/strong>、&lt;strong>PostgreSQL&lt;/strong>、&lt;strong>Oracle&lt;/strong>、&lt;strong>SQL Server&lt;/strong>、&lt;strong>SQLite&lt;/strong>（&lt;strong>微信本地的聊天记录&lt;/strong>的存储就是用的 SQLite） &amp;hellip;&amp;hellip;&lt;/p>
&lt;h2 id="mysql介绍">MySQL介绍&lt;a class="anchor" href="#mysql%e4%bb%8b%e7%bb%8d">#&lt;/a>&lt;/h2>
&lt;p>&lt;img src="img/ly-20241212141911084.png" alt="img" />&lt;/p>
&lt;ul>
&lt;li>
&lt;p>MySQL是一种&lt;strong>关系型数据库&lt;/strong>，主要用于&lt;strong>持久化存储&lt;/strong>我们系统中的一些数据比如&lt;strong>用户信息&lt;/strong>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>由于 MySQL 是&lt;strong>开源&lt;/strong>免费并且比较&lt;strong>成熟&lt;/strong>的数据库，因此，MySQL 被大量使用在各种系统中。任何人都可以在 &lt;strong>GPL(General Public License 通用性公开许可证)&lt;/strong> 的许可下下载并根据&lt;strong>个性化的需要&lt;/strong>对其进行&lt;strong>修改&lt;/strong>。MySQL 的默认端口号是&lt;strong>3306&lt;/strong>。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h1 id="mysql基础架构">MySQL基础架构&lt;a class="anchor" href="#mysql%e5%9f%ba%e7%a1%80%e6%9e%b6%e6%9e%84">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>MySQL的一个&lt;strong>简要机构图&lt;/strong>，客户端的一条&lt;strong>SQL语句&lt;/strong>在MySQL内部如何执行
&lt;img src="img/ly-20241212141911246.png" alt="ly-20241212141911246" />&lt;/li>
&lt;li>MySQL主要由几部分构成
&lt;ol>
&lt;li>&lt;strong>连接器&lt;/strong>：&lt;strong>身份认证&lt;/strong>和&lt;strong>权限相关&lt;/strong>（登录MySQL的时候）&lt;/li>
&lt;li>&lt;strong>查询缓存&lt;/strong>：执行&lt;strong>查询&lt;/strong>语句的时候，会先&lt;strong>查询缓存&lt;/strong>（MySQL8.0版本后&lt;strong>移除&lt;/strong>，因为这个功能不太实用）&lt;/li>
&lt;li>&lt;strong>分析器&lt;/strong>：&lt;strong>没有命中缓存&lt;/strong>的话，SQL语句就会经过分析器，分析器说白了就是要先看你的SQL语句&lt;strong>要干嘛&lt;/strong>，再检查你的&lt;strong>SQL语句语法&lt;/strong>是否正确&lt;/li>
&lt;li>&lt;strong>优化器&lt;/strong>：按照&lt;strong>MySQL认为最优的方案&lt;/strong>去执行&lt;/li>
&lt;li>&lt;strong>执行器&lt;/strong>：&lt;strong>执行&lt;/strong>语句，然后从&lt;strong>存储引擎返回&lt;/strong>数据。执行语句之前会&lt;strong>先判断是否有权限&lt;/strong>，如果没有权限，就会报错&lt;/li>
&lt;li>&lt;strong>插件式存储引擎&lt;/strong>：主要负责&lt;strong>数据&lt;/strong>的&lt;strong>存储&lt;/strong>和&lt;strong>读取&lt;/strong>，采用的是&lt;strong>插件式架构&lt;/strong>，支持&lt;strong>InnoDB&lt;/strong>、&lt;strong>MyISAM&lt;/strong>、&lt;strong>Memory&lt;/strong>等多种存储引擎&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ul>
&lt;h1 id="mysql存储引擎">MySQL存储引擎&lt;a class="anchor" href="#mysql%e5%ad%98%e5%82%a8%e5%bc%95%e6%93%8e">#&lt;/a>&lt;/h1>
&lt;p>MySQL&lt;strong>核心&lt;/strong>在于&lt;strong>存储引擎&lt;/strong>&lt;/p>
&lt;h2 id="mysql支持哪些存储引擎默认使用哪个">MySQL支持哪些存储引擎？默认使用哪个？&lt;a class="anchor" href="#mysql%e6%94%af%e6%8c%81%e5%93%aa%e4%ba%9b%e5%ad%98%e5%82%a8%e5%bc%95%e6%93%8e%e9%bb%98%e8%ae%a4%e4%bd%bf%e7%94%a8%e5%93%aa%e4%b8%aa">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>MySQL支持&lt;strong>多种存储引擎&lt;/strong>，可以通过&lt;code>show engines&lt;/code>命令来&lt;strong>查看MySQL支持的所有存储引擎&lt;/strong>
&lt;img src="img/ly-20241212141911409.png" alt="查看 MySQL 提供的所有存储引擎" />&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>默认&lt;/strong>存储引擎为InnoDB，并且，所有存储引擎中&lt;strong>只有InnoDB是事务性存储引擎&lt;/strong>，也就是说&lt;strong>只有InnoDB支持事务&lt;/strong>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>这里使用MySQL 8.x&lt;/strong>
MySQL 5.5.5之前，MyISAM是MySQL的默认存储引擎；5.5.5之后，InnoDB是MySQL的默认存储引擎，可以通过&lt;code>select version()&lt;/code>命令查看你的MySQL版本&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-mysql" data-lang="mysql">&lt;span style="display:flex;">&lt;span>mysql&lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#66d9ef">select&lt;/span> &lt;span style="color:#a6e22e">version&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">+-----------+&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#a6e22e">version&lt;/span>() &lt;span style="color:#f92672">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">+-----------+&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">|&lt;/span> &lt;span style="color:#ae81ff">8&lt;/span>.&lt;span style="color:#ae81ff">0&lt;/span>.&lt;span style="color:#ae81ff">27&lt;/span> &lt;span style="color:#f92672">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">+-----------+&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">1&lt;/span> row &lt;span style="color:#66d9ef">in&lt;/span> &lt;span style="color:#66d9ef">set&lt;/span> (&lt;span style="color:#ae81ff">0&lt;/span>.&lt;span style="color:#ae81ff">00&lt;/span> sec) &lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>使用&lt;code>show variables like %storage_engine%&lt;/code>命令直接查看MySQL&lt;strong>当前默认的存储引擎&lt;/strong> &lt;br>
&lt;img src="img/ly-20241212141911580.png" alt="查看 MySQL 当前默认的存储引擎" />&lt;/p>
&lt;p>如果只想&lt;strong>查看数据库中某个表使用的存储引擎&lt;/strong>的话，可以使用&lt;code>show table status from db_name where name = 'table_name'&lt;/code>命令&lt;br>
&lt;img src="img/ly-20241212141911743.png" alt="查看表的存储引擎" />&lt;/p></description></item><item><title>MySQL中的隐式转换造成的索引失效</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/MySQL/ly0609lyindex-invalidation-caused-by-implicit-conversion/</link><pubDate>Thu, 19 Jan 2023 17:10:48 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/MySQL/ly0609lyindex-invalidation-caused-by-implicit-conversion/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>
&lt;p>本篇文章基于MySQL 5.7.26，原文：https://www.guitu18.com/post/2019/11/24/61.html&lt;/p>&lt;/blockquote>&lt;h1 id="前言">前言&lt;a class="anchor" href="#%e5%89%8d%e8%a8%80">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>关于&lt;strong>数据库优化&lt;/strong>，最常见的莫过于&lt;strong>索引失效&lt;/strong>，数据量多的时候比较明显，处理不及时会造成&lt;strong>雪球效应&lt;/strong>，最终导致&lt;strong>数据库卡死甚至瘫痪&lt;/strong>。&lt;/li>
&lt;li>这里说的是&lt;strong>隐式转换造成的索引失效&lt;/strong>&lt;/li>
&lt;/ul>
&lt;h1 id="数据准备">数据准备&lt;a class="anchor" href="#%e6%95%b0%e6%8d%ae%e5%87%86%e5%a4%87">#&lt;/a>&lt;/h1>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-mysql" data-lang="mysql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- 创建测试数据表
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">DROP&lt;/span> &lt;span style="color:#66d9ef">TABLE&lt;/span> &lt;span style="color:#66d9ef">IF&lt;/span> &lt;span style="color:#66d9ef">EXISTS&lt;/span> test1;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">CREATE&lt;/span> &lt;span style="color:#66d9ef">TABLE&lt;/span> &lt;span style="color:#f92672">`&lt;/span>test1&lt;span style="color:#f92672">`&lt;/span> (
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">`&lt;/span>id&lt;span style="color:#f92672">`&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span>(&lt;span style="color:#ae81ff">11&lt;/span>) &lt;span style="color:#66d9ef">NOT&lt;/span> &lt;span style="color:#66d9ef">NULL&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">`&lt;/span>num1&lt;span style="color:#f92672">`&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span>(&lt;span style="color:#ae81ff">11&lt;/span>) &lt;span style="color:#66d9ef">NOT&lt;/span> &lt;span style="color:#66d9ef">NULL&lt;/span> &lt;span style="color:#66d9ef">DEFAULT&lt;/span> &lt;span style="color:#e6db74">&amp;#39;0&amp;#39;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">`&lt;/span>num2&lt;span style="color:#f92672">`&lt;/span> &lt;span style="color:#66d9ef">varchar&lt;/span>(&lt;span style="color:#ae81ff">11&lt;/span>) &lt;span style="color:#66d9ef">NOT&lt;/span> &lt;span style="color:#66d9ef">NULL&lt;/span> &lt;span style="color:#66d9ef">DEFAULT&lt;/span> &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">`&lt;/span>type1&lt;span style="color:#f92672">`&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span>(&lt;span style="color:#ae81ff">4&lt;/span>) &lt;span style="color:#66d9ef">NOT&lt;/span> &lt;span style="color:#66d9ef">NULL&lt;/span> &lt;span style="color:#66d9ef">DEFAULT&lt;/span> &lt;span style="color:#e6db74">&amp;#39;0&amp;#39;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">`&lt;/span>type2&lt;span style="color:#f92672">`&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span>(&lt;span style="color:#ae81ff">4&lt;/span>) &lt;span style="color:#66d9ef">NOT&lt;/span> &lt;span style="color:#66d9ef">NULL&lt;/span> &lt;span style="color:#66d9ef">DEFAULT&lt;/span> &lt;span style="color:#e6db74">&amp;#39;0&amp;#39;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">`&lt;/span>str1&lt;span style="color:#f92672">`&lt;/span> &lt;span style="color:#66d9ef">varchar&lt;/span>(&lt;span style="color:#ae81ff">100&lt;/span>) &lt;span style="color:#66d9ef">NOT&lt;/span> &lt;span style="color:#66d9ef">NULL&lt;/span> &lt;span style="color:#66d9ef">DEFAULT&lt;/span> &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">`&lt;/span>str2&lt;span style="color:#f92672">`&lt;/span> &lt;span style="color:#66d9ef">varchar&lt;/span>(&lt;span style="color:#ae81ff">100&lt;/span>) &lt;span style="color:#66d9ef">DEFAULT&lt;/span> &lt;span style="color:#66d9ef">NULL&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">PRIMARY&lt;/span> &lt;span style="color:#66d9ef">KEY&lt;/span> (&lt;span style="color:#f92672">`&lt;/span>id&lt;span style="color:#f92672">`&lt;/span>),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">KEY&lt;/span> &lt;span style="color:#f92672">`&lt;/span>num1&lt;span style="color:#f92672">`&lt;/span> (&lt;span style="color:#f92672">`&lt;/span>num1&lt;span style="color:#f92672">`&lt;/span>),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">KEY&lt;/span> &lt;span style="color:#f92672">`&lt;/span>num2&lt;span style="color:#f92672">`&lt;/span> (&lt;span style="color:#f92672">`&lt;/span>num2&lt;span style="color:#f92672">`&lt;/span>),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">KEY&lt;/span> &lt;span style="color:#f92672">`&lt;/span>type1&lt;span style="color:#f92672">`&lt;/span> (&lt;span style="color:#f92672">`&lt;/span>type1&lt;span style="color:#f92672">`&lt;/span>),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">KEY&lt;/span> &lt;span style="color:#f92672">`&lt;/span>str1&lt;span style="color:#f92672">`&lt;/span> (&lt;span style="color:#f92672">`&lt;/span>str1&lt;span style="color:#f92672">`&lt;/span>),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">KEY&lt;/span> &lt;span style="color:#f92672">`&lt;/span>str2&lt;span style="color:#f92672">`&lt;/span> (&lt;span style="color:#f92672">`&lt;/span>str2&lt;span style="color:#f92672">`&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>) &lt;span style="color:#66d9ef">ENGINE&lt;/span>&lt;span style="color:#f92672">=&lt;/span>InnoDB &lt;span style="color:#66d9ef">DEFAULT&lt;/span> &lt;span style="color:#66d9ef">CHARSET&lt;/span>&lt;span style="color:#f92672">=&lt;/span>utf8;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- 创建存储过程
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">DROP&lt;/span> &lt;span style="color:#66d9ef">PROCEDURE&lt;/span> &lt;span style="color:#66d9ef">IF&lt;/span> &lt;span style="color:#66d9ef">EXISTS&lt;/span> pre_test1;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>DELIMITER &lt;span style="color:#f92672">//&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">CREATE&lt;/span> &lt;span style="color:#66d9ef">PROCEDURE&lt;/span> &lt;span style="color:#f92672">`&lt;/span>pre_test1&lt;span style="color:#f92672">`&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>BEGIN
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">DECLARE&lt;/span> i &lt;span style="color:#66d9ef">INT&lt;/span> &lt;span style="color:#66d9ef">DEFAULT&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">SET&lt;/span> autocommit &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">WHILE&lt;/span> i &lt;span style="color:#f92672">&amp;lt;&lt;/span> &lt;span style="color:#ae81ff">10000000&lt;/span> DO
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">SET&lt;/span> i &lt;span style="color:#f92672">=&lt;/span> i &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">SET&lt;/span> &lt;span style="color:#f92672">@&lt;/span>str1 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">SUBSTRING&lt;/span>(&lt;span style="color:#a6e22e">MD5&lt;/span>(&lt;span style="color:#a6e22e">RAND&lt;/span>()),&lt;span style="color:#ae81ff">1&lt;/span>,&lt;span style="color:#ae81ff">20&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">-- 每100条数据str2产生一个null值
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">IF&lt;/span> i &lt;span style="color:#f92672">%&lt;/span> &lt;span style="color:#ae81ff">100&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#66d9ef">THEN&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">SET&lt;/span> &lt;span style="color:#f92672">@&lt;/span>str2 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">NULL&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">ELSE&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">SET&lt;/span> &lt;span style="color:#f92672">@&lt;/span>str2 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#f92672">@&lt;/span>str1;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> END &lt;span style="color:#66d9ef">IF&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">INSERT&lt;/span> &lt;span style="color:#66d9ef">INTO&lt;/span> &lt;span style="color:#a6e22e">test1&lt;/span> (&lt;span style="color:#f92672">`&lt;/span>id&lt;span style="color:#f92672">`&lt;/span>, &lt;span style="color:#f92672">`&lt;/span>num1&lt;span style="color:#f92672">`&lt;/span>, &lt;span style="color:#f92672">`&lt;/span>num2&lt;span style="color:#f92672">`&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">`&lt;/span>type1&lt;span style="color:#f92672">`&lt;/span>, &lt;span style="color:#f92672">`&lt;/span>type2&lt;span style="color:#f92672">`&lt;/span>, &lt;span style="color:#f92672">`&lt;/span>str1&lt;span style="color:#f92672">`&lt;/span>, &lt;span style="color:#f92672">`&lt;/span>str2&lt;span style="color:#f92672">`&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">VALUES&lt;/span> (&lt;span style="color:#a6e22e">CONCAT&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>, i), &lt;span style="color:#a6e22e">CONCAT&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>, i),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">CONCAT&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>, i), i&lt;span style="color:#f92672">%&lt;/span>&lt;span style="color:#ae81ff">5&lt;/span>, i&lt;span style="color:#f92672">%&lt;/span>&lt;span style="color:#ae81ff">5&lt;/span>, &lt;span style="color:#f92672">@&lt;/span>str1, &lt;span style="color:#f92672">@&lt;/span>str2);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">-- 事务优化，每一万条数据提交一次事务
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">IF&lt;/span> i &lt;span style="color:#f92672">%&lt;/span> &lt;span style="color:#ae81ff">10000&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#66d9ef">THEN&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> COMMIT;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> END &lt;span style="color:#66d9ef">IF&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> END &lt;span style="color:#66d9ef">WHILE&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>END;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">//&lt;/span> DELIMITER ;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- 执行存储过程
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">CALL&lt;/span> &lt;span style="color:#a6e22e">pre_test1&lt;/span>(); &lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>其中，七个字段，首先使用存储过程生成 1000 万条测试数据， 测试表一共建立了 7 个字段（包括主键），&lt;strong>&lt;code>num1&lt;/code>&lt;strong>和&lt;/strong>&lt;code>num2&lt;/code>&lt;strong>保存的是和&lt;code>ID&lt;/code>一样的顺序数字，其中&lt;/strong>&lt;code>num2&lt;/code>是字符串类型&lt;/strong>。 &lt;strong>&lt;code>type1&lt;/code>&lt;strong>和&lt;/strong>&lt;code>type2&lt;/code>&lt;strong>保存的都是主键对 5 的取模，目的是模拟实际应用中常用&lt;/strong>类似 type 类型&lt;/strong>的数据，但是**&lt;code>type2&lt;/code>是没有建立索引&lt;strong>的。 &lt;code>str1&lt;/code>和&lt;code>str2&lt;/code>都是保存了一个 &lt;strong>20 位长度的随机字符串&lt;/strong>，&lt;/strong>&lt;code>str1&lt;/code>不能为&lt;code>NULL&lt;/code>，&lt;code>str2&lt;/code>允许为&lt;code>NULL&lt;/code>&lt;strong>，相应的生成测试数据的时候我也会&lt;/strong>在&lt;code>str2&lt;/code>字段生产少量&lt;code>NULL&lt;/code>值**（每 100 条数据产生一个&lt;code>NULL&lt;/code>值）。&lt;/p></description></item><item><title>MySQL数据库时间类型数据存储建议</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/MySQL/ly0608lysome-thoughts-on-database-storage-time/</link><pubDate>Thu, 19 Jan 2023 17:10:06 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/MySQL/ly0608lysome-thoughts-on-database-storage-time/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;h1 id="不要用字符串存储日期">不要用字符串存储日期&lt;a class="anchor" href="#%e4%b8%8d%e8%a6%81%e7%94%a8%e5%ad%97%e7%ac%a6%e4%b8%b2%e5%ad%98%e5%82%a8%e6%97%a5%e6%9c%9f">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>优点：简单直白&lt;/li>
&lt;li>缺点
&lt;ol>
&lt;li>字符串&lt;strong>占有的空间更大&lt;/strong>&lt;/li>
&lt;li>字符串存储的日期&lt;strong>效率比较低&lt;/strong>（逐个字符进行比较），&lt;strong>无法用日期相关的API&lt;/strong>进行计算和比较&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ul>
&lt;h1 id="datetime和timestamp之间抉择">Datetime和Timestamp之间抉择&lt;a class="anchor" href="#datetime%e5%92%8ctimestamp%e4%b9%8b%e9%97%b4%e6%8a%89%e6%8b%a9">#&lt;/a>&lt;/h1>
&lt;p>Datetime 和 Timestamp 是 MySQL 提供的两种&lt;strong>比较相似&lt;/strong>的保存时间的数据类型。他们两者究竟该如何选择呢？&lt;/p>
&lt;p>&lt;strong>通常我们都会首选 Timestamp&lt;/strong>&lt;/p>
&lt;h2 id="datetime类型没有时区信息">Datetime类型没有时区信息&lt;a class="anchor" href="#datetime%e7%b1%bb%e5%9e%8b%e6%b2%a1%e6%9c%89%e6%97%b6%e5%8c%ba%e4%bf%a1%e6%81%af">#&lt;/a>&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>DateTime 类型是没有时区信息的（时区无关）&lt;/strong> ，DateTime 类型保存的时间都是&lt;strong>当前会话所设置的时区&lt;/strong>对应的时间。这样就会有什么问题呢？当你的时区更换之后，比如你的服务器更换地址或者更换客户端连接时区设置的话，就会导致你从数据库中读出的时间错误。不要小看这个问题，很多系统就是因为这个问题闹出了很多笑话。&lt;/li>
&lt;li>&lt;strong>Timestamp 和时区有关&lt;/strong>。Timestamp 类型字段的值会随着服务器时区的变化而变化，自动换算成相应的时间，说简单点就是&lt;strong>在不同时区&lt;/strong>，&lt;strong>查询到同一个条记录此字段的值会不一样&lt;/strong>&lt;/li>
&lt;/ol>
&lt;p>案例&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-mysql" data-lang="mysql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- 建表
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">CREATE&lt;/span> &lt;span style="color:#66d9ef">TABLE&lt;/span> &lt;span style="color:#f92672">`&lt;/span>time_zone_test&lt;span style="color:#f92672">`&lt;/span> (
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">`&lt;/span>id&lt;span style="color:#f92672">`&lt;/span> &lt;span style="color:#66d9ef">bigint&lt;/span>(&lt;span style="color:#ae81ff">20&lt;/span>) &lt;span style="color:#66d9ef">NOT&lt;/span> &lt;span style="color:#66d9ef">NULL&lt;/span> &lt;span style="color:#66d9ef">AUTO_INCREMENT&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">`&lt;/span>date_time&lt;span style="color:#f92672">`&lt;/span> &lt;span style="color:#66d9ef">datetime&lt;/span> &lt;span style="color:#66d9ef">DEFAULT&lt;/span> &lt;span style="color:#66d9ef">NULL&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">`&lt;/span>time_stamp&lt;span style="color:#f92672">`&lt;/span> &lt;span style="color:#66d9ef">timestamp&lt;/span> &lt;span style="color:#66d9ef">NOT&lt;/span> &lt;span style="color:#66d9ef">NULL&lt;/span> &lt;span style="color:#66d9ef">DEFAULT&lt;/span> &lt;span style="color:#66d9ef">CURRENT_TIMESTAMP&lt;/span> &lt;span style="color:#66d9ef">ON&lt;/span> &lt;span style="color:#66d9ef">UPDATE&lt;/span> &lt;span style="color:#66d9ef">CURRENT_TIMESTAMP&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">PRIMARY&lt;/span> &lt;span style="color:#66d9ef">KEY&lt;/span> (&lt;span style="color:#f92672">`&lt;/span>id&lt;span style="color:#f92672">`&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>) &lt;span style="color:#66d9ef">ENGINE&lt;/span>&lt;span style="color:#f92672">=&lt;/span>InnoDB &lt;span style="color:#66d9ef">DEFAULT&lt;/span> &lt;span style="color:#66d9ef">CHARSET&lt;/span>&lt;span style="color:#f92672">=&lt;/span>utf8; 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- 插入数据
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">INSERT&lt;/span> &lt;span style="color:#66d9ef">INTO&lt;/span> &lt;span style="color:#a6e22e">time_zone_test&lt;/span>(date_time,time_stamp) &lt;span style="color:#66d9ef">VALUES&lt;/span>(&lt;span style="color:#a6e22e">NOW&lt;/span>(),&lt;span style="color:#a6e22e">NOW&lt;/span>());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- 查看数据
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">select&lt;/span> date_time,time_stamp &lt;span style="color:#66d9ef">from&lt;/span> time_zone_test;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- 结果
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#75715e">/*
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> +---------------------+---------------------+
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">| date_time | time_stamp |
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">+---------------------+---------------------+
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">| 2020-01-11 09:53:32 | 2020-01-11 09:53:32 |
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">+---------------------+---------------------+
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">------ 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">*/&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>修改时区并查看数据&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-mysql" data-lang="mysql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">set&lt;/span> time_zone&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;+8:00&amp;#39;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">/*
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">+---------------------+---------------------+
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">| date_time | time_stamp |
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">+---------------------+---------------------+
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">| 2020-01-11 09:53:32 | 2020-01-11 17:53:32 |
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">+---------------------+---------------------+
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">------ 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">*/&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>关于MySQL时区设置的一个&lt;strong>常用sql命令&lt;/strong>&lt;/p></description></item><item><title>SQL语句在MySQL中的执行过程</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/MySQL/ly0605lyhow-sql-executed-in-mysql/</link><pubDate>Thu, 19 Jan 2023 10:20:57 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/MySQL/ly0605lyhow-sql-executed-in-mysql/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>
&lt;p>原文 
&lt;a target="_blank" href="https://github.com/kinglaw1204">https://github.com/kinglaw1204&lt;/a> 感谢作者&lt;/p>&lt;/blockquote>&lt;ul>
&lt;li>本篇文章会分析&lt;strong>一个SQL语句&lt;/strong>在MySQL的&lt;strong>执行流程&lt;/strong>，包括&lt;strong>SQL的查询&lt;/strong>在MySQL内部会怎么&lt;strong>流转&lt;/strong>，&lt;strong>SQL语句的更新&lt;/strong>是怎么完成的&lt;/li>
&lt;li>分析之前先看看&lt;strong>MySQL的基础架构&lt;/strong>，知道了MySQL由&lt;strong>哪些组件&lt;/strong>组成以及&lt;strong>这些组件的作用&lt;/strong>是什么，可以帮助我们&lt;strong>理解&lt;/strong>和&lt;strong>解决&lt;/strong>这些问题&lt;/li>
&lt;/ul>
&lt;h1 id="mysql基础架构分析">MySQL基础架构分析&lt;a class="anchor" href="#mysql%e5%9f%ba%e7%a1%80%e6%9e%b6%e6%9e%84%e5%88%86%e6%9e%90">#&lt;/a>&lt;/h1>
&lt;p>&lt;img src="img/ly-20241212141908611.png" alt="ly-20241212141908611" />&lt;/p>
&lt;h2 id="mysql基本架构概览">MySQL基本架构概览&lt;a class="anchor" href="#mysql%e5%9f%ba%e6%9c%ac%e6%9e%b6%e6%9e%84%e6%a6%82%e8%a7%88">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>下图是MySQL的简要架构图，从下图可以看到&lt;strong>用户的SQL语句&lt;/strong>在MySQL内部是&lt;strong>如何执行的&lt;/strong>&lt;/li>
&lt;li>先简单介绍一个下图涉及的一些组件的基本作用
&lt;img src="img/ly-20241212141908907.png" alt="ly-20241212141908907" />
&lt;ol>
&lt;li>&lt;strong>连接器&lt;/strong>： &lt;strong>身份认证&lt;/strong>和&lt;strong>权限相关&lt;/strong>（登录MySQL的时候）&lt;/li>
&lt;li>&lt;strong>查询缓存&lt;/strong>：执行查询语句的时候，会&lt;strong>先查询缓存&lt;/strong>（MySQL8.0版本后移除，因为这个功能不太实用）&lt;/li>
&lt;li>&lt;strong>分析器&lt;/strong>：&lt;strong>没有命中&lt;/strong>缓存的话，SQL语句就会经过分析器，分析器说白了就是要&lt;strong>先看&lt;/strong>你的SQL语句干嘛，再&lt;strong>检查&lt;/strong>你的SQL语句&lt;strong>语法&lt;/strong>是否正确&lt;/li>
&lt;li>&lt;strong>优化器&lt;/strong>：按照&lt;strong>MySQL认为最优的方案&lt;/strong>去执行&lt;/li>
&lt;li>&lt;strong>执行器&lt;/strong>：&lt;strong>执行语句&lt;/strong>，然后从&lt;strong>存储引擎&lt;/strong>返回数据&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>简单来说 MySQL 主要分为 Server 层和存储引擎层：
&lt;ul>
&lt;li>&lt;strong>Server 层&lt;/strong>：主要包括&lt;strong>连接器&lt;/strong>、&lt;strong>查询缓存&lt;/strong>、&lt;strong>分析器&lt;/strong>、&lt;strong>优化器&lt;/strong>、&lt;strong>执行器&lt;/strong>等，所有&lt;strong>跨存储引擎&lt;/strong>的功能都在这一层实现，比如&lt;strong>存储过程&lt;/strong>、&lt;strong>触发器&lt;/strong>、&lt;strong>视图&lt;/strong>，&lt;strong>函数&lt;/strong>等，还有一个&lt;strong>通用的日志模块 binlog 日志模块&lt;/strong>。&lt;/li>
&lt;li>&lt;strong>存储引擎&lt;/strong>： 主要负责数据的&lt;strong>存储&lt;/strong>和&lt;strong>读取&lt;/strong>，采用&lt;strong>可以替换的插件式架构&lt;/strong>，支持 InnoDB、MyISAM、Memory 等多个存储引擎，其中 InnoDB 引擎有自有的日志模块 &lt;strong>redolog 模块&lt;/strong>。&lt;strong>现在最常用的存储引擎是 InnoDB，它从 MySQL 5.5 版本开始就被当做默认存储引擎了&lt;/strong>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="server层基本组件介绍">Server层基本组件介绍&lt;a class="anchor" href="#server%e5%b1%82%e5%9f%ba%e6%9c%ac%e7%bb%84%e4%bb%b6%e4%bb%8b%e7%bb%8d">#&lt;/a>&lt;/h2>
&lt;p>&lt;img src="img/ly-20241212141909073.png" alt="ly-20241212141909073" />&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>连接器&lt;/strong>
连接器主要和&lt;strong>身份认证&lt;/strong>和&lt;strong>权限相关&lt;/strong>的功能相关，就好比一个级别很高的门卫一样&lt;/p>
&lt;blockquote class='book-hint '>
&lt;p>主要负责用户登录数据库，进行用户的身份认证，包括校验账户密码，权限等操作，如果用户&lt;strong>账户密码&lt;/strong>已通过，连接器会到&lt;strong>权限表&lt;/strong>中查询&lt;strong>该用户的所有权限&lt;/strong>，之后在这个连接里的权限逻辑判断都是会依赖&lt;strong>此时读取到的权限数据&lt;/strong>，也就是说，&lt;strong>后续只要这个连接不断开&lt;/strong>，&lt;strong>即使&lt;/strong>管理员&lt;strong>修改&lt;/strong>了该用户的权限，该用户也是不受影响的。&lt;/p>&lt;/blockquote>&lt;/li>
&lt;li>
&lt;p>&lt;strong>查询缓存（MySQL8.0 版本后移除）&lt;/strong>&lt;br>
查询缓存&lt;strong>主要用来缓存&lt;/strong>我们所执行的 &lt;strong>SELECT 语句&lt;/strong>以及该&lt;strong>语句的结果集&lt;/strong>。&lt;/p>
&lt;blockquote class='book-hint '>
&lt;ul>
&lt;li>
&lt;p>连接建立后，执行查询语句的时候，会先查询缓存，MySQL 会先校验这个 SQL 是否执行过，以 &lt;strong>Key-Value&lt;/strong> 的形式缓存在内存中，Key 是查询预计，Value 是结果集。如果缓存 key 被命中，就会直接返回给客户端，如果没有命中，就会执行后续的操作，完成后也会把结果缓存起来，方便下一次调用。当然在真正执行缓存查询的时候还是会校验用户的权限，是否有该表的查询条件。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>MySQL 查询不建议使用缓存，因为查询缓存失效在实际业务场景中可能会非常频繁，假如&lt;strong>你对一个表更新&lt;/strong>的话，&lt;strong>这个表上的所有的查询缓存都会被清空&lt;/strong>。对于&lt;strong>不经常更新的数据&lt;/strong>来说，&lt;strong>使用缓存还是可以&lt;/strong>的。所以，一般在大多数情况下我们都是不推荐去使用查询缓存的。&lt;/p>
&lt;/li>
&lt;/ul>&lt;/blockquote>&lt;p>MySQL &lt;strong>8.0 版本后删除了缓存&lt;/strong>的功能，官方也是认为该功能在实际的应用场景比较少，所以干脆直接删掉了&lt;/p></description></item><item><title>innodb引擎对MVCC的实现</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/MySQL/ly0604lyinnodb-implementation-of-mvcc/</link><pubDate>Mon, 16 Jan 2023 19:23:55 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/MySQL/ly0604lyinnodb-implementation-of-mvcc/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;h1 id="一致性非锁定读和锁定读">一致性非锁定读和锁定读&lt;a class="anchor" href="#%e4%b8%80%e8%87%b4%e6%80%a7%e9%9d%9e%e9%94%81%e5%ae%9a%e8%af%bb%e5%92%8c%e9%94%81%e5%ae%9a%e8%af%bb">#&lt;/a>&lt;/h1>
&lt;h2 id="一致性非锁定读">一致性非锁定读&lt;a class="anchor" href="#%e4%b8%80%e8%87%b4%e6%80%a7%e9%9d%9e%e9%94%81%e5%ae%9a%e8%af%bb">#&lt;/a>&lt;/h2>
&lt;p>★★非锁定★★&lt;/p>
&lt;ul>
&lt;li>对于&lt;strong>一致性非锁定读（Consistent Nonlocking Reads）&lt;strong>的实现，通常做法是&lt;/strong>加一个版本号&lt;/strong>或者&lt;strong>时间戳&lt;/strong>字段，在更新数据的同时&lt;strong>版本号+1&lt;/strong>或者&lt;strong>更新时间戳&lt;/strong>。查询时，将&lt;strong>当前可见的版本号&lt;/strong>与&lt;strong>对应记录的版本号&lt;/strong>进行比对，如果&lt;strong>记录的版本&lt;/strong>小于&lt;strong>可见版本&lt;/strong>，则表示&lt;strong>该记录可见&lt;/strong>&lt;/li>
&lt;li>&lt;strong>InnoDB&lt;/strong>存储引擎中，&lt;strong>多版本控制（multi versioning）&lt;strong>即是非锁定读的实现。如果读取的行&lt;/strong>正在执行DELETE&lt;/strong>或&lt;strong>UPDATE&lt;/strong>操作，这时读取操作&lt;strong>不会去等待行上&lt;/strong> &lt;strong>锁的释放&lt;/strong>.相反地，Inn哦DB存储引擎会去读取&lt;strong>行的一个快照数据&lt;/strong>，对于这种&lt;strong>读取历史数据&lt;/strong>的方式，我们叫它&lt;strong>快照读（snapshot read）&lt;/strong>。&lt;/li>
&lt;li>在 &lt;strong>&lt;code>Repeatable Read&lt;/code>&lt;/strong> 和 &lt;strong>&lt;code>Read Committed&lt;/code>&lt;/strong> 两个隔离级别下，如果是执行普通的 &lt;code>select&lt;/code> 语句（&lt;strong>不包括 &lt;code>select ... lock in share mode&lt;/code> ,&lt;code>select ... for update&lt;/code>&lt;/strong>）则会使用 &lt;strong>&lt;code>一致性非锁定读（MVCC）&lt;/code>&lt;/strong>。并且在 &lt;strong>&lt;code>Repeatable Read&lt;/code> 下 &lt;code>MVCC&lt;/code> 实现了可重复读和防止部分幻读&lt;/strong>&lt;/li>
&lt;/ul>
&lt;h2 id="锁定读">锁定读&lt;a class="anchor" href="#%e9%94%81%e5%ae%9a%e8%af%bb">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>如果执行的是下列语句，就是&lt;strong>锁定读（Locking Reads）&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;code>select ... lock in share&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>select ... for update&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>insert &lt;/code>、&lt;code>upate&lt;/code>、&lt;code>delete&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>锁定读下，读取的是数据的最新版本，这种读也被称为&lt;strong>当前读current read&lt;/strong>。&lt;strong>锁定读&lt;/strong>会对读取到的记录加锁&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>select ... lock in share mode &lt;/code>：对(读取到的)记录加&lt;strong>S锁&lt;/strong>，其他事务也可以加S锁，如果加X锁则会被阻塞&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>select ... for update&lt;/code>、&lt;code>insert&lt;/code>、&lt;code>update&lt;/code>、&lt;code>delete&lt;/code>：对记录加&lt;strong>X锁&lt;/strong>，且其他事务不能加任何锁&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;p>在一致性非锁定读下，即使读取的记录&lt;strong>已被其他事务加上X锁&lt;/strong>，这时记录也是可以被读取的，即读取的&lt;strong>快照数据&lt;/strong>。&lt;/p>
&lt;ol>
&lt;li>在&lt;strong>RepeatableRead&lt;/strong>下MVCC&lt;strong>防止了部分幻读&lt;/strong>，这边的“&lt;strong>部分”&lt;strong>是指在&lt;/strong>一致性非锁定读&lt;/strong>情况下，只能读取到第一次查询之前所插入的数据（&lt;strong>根据ReadView判断数据可见性，ReadView在第一次查询时生成&lt;/strong>），但如果是&lt;strong>当前读&lt;/strong>，每次读取的都是&lt;strong>最新数据&lt;/strong>，这时如果两次查询中间有其他事务插入数据，就会&lt;strong>产生幻读&lt;/strong>&lt;/li>
&lt;li>所以，InnoDB在实现RepeatableRead时，如果执行的是&lt;strong>当前读&lt;/strong>，则会对读取的记录使用&lt;strong>Next-key Lock&lt;/strong>，来防止其他事务在&lt;strong>间隙间插入数据&lt;/strong>。&lt;/li>
&lt;/ol>
&lt;blockquote class='book-hint '>
&lt;p>&lt;strong>RR产生幻读的另一个场景&lt;/strong>&lt;/p></description></item><item><title>MySQL事务隔离级别详解</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/MySQL/ly0603lytransaction-isolation-level/</link><pubDate>Mon, 16 Jan 2023 01:00:44 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/MySQL/ly0603lytransaction-isolation-level/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;h1 id="事务隔离级别总结">事务隔离级别总结&lt;a class="anchor" href="#%e4%ba%8b%e5%8a%a1%e9%9a%94%e7%a6%bb%e7%ba%a7%e5%88%ab%e6%80%bb%e7%bb%93">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>
&lt;p>SQL标准定义了&lt;strong>四个隔离级别&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>&lt;strong>READ-UNCOMMITTED(读取未提交)&lt;/strong>：&lt;strong>最低&lt;/strong>的隔离级别，允许读取&lt;strong>尚未提交的数据&lt;/strong>变更，可能会导致&lt;strong>脏读、幻读或不可重复读&lt;/strong>&lt;/li>
&lt;li>&lt;strong>READ-COMMITED(读取已提交)&lt;/strong>：允许读取&lt;strong>并发事务&lt;/strong> &lt;strong>已经提交&lt;/strong>的数据，可以阻止&lt;strong>脏读&lt;/strong>，但是&lt;strong>幻读&lt;/strong>或&lt;strong>不可重复读&lt;/strong>仍有可能发生&lt;/li>
&lt;li>&lt;strong>REPEATABLE-READ(可重复读)&lt;/strong>：对&lt;strong>同一字段的多次读取&lt;/strong>结果都是一致的，除非数据是被&lt;strong>本身事务自己&lt;/strong>所修改，可以&lt;strong>阻止脏读&lt;/strong>和&lt;strong>不可重复读&lt;/strong>，但&lt;strong>幻读&lt;/strong>仍有可能发生&lt;/li>
&lt;li>&lt;strong>SERIALIZABLE(可串行化)&lt;/strong>：&lt;strong>最高&lt;/strong>的隔离级别，&lt;strong>完全服从ACID&lt;/strong>的隔离级别。所有的&lt;strong>事务依次逐个&lt;/strong>执行，这样事务之间就&lt;strong>完全不可能产生干扰&lt;/strong>，也就是说，该级别可以防止&lt;strong>脏读&lt;/strong>、&lt;strong>不可重复读&lt;/strong>以及&lt;strong>幻读&lt;/strong>。&lt;/li>
&lt;/ol>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th style="text-align: center">隔离级别&lt;/th>
 &lt;th style="text-align: center">脏读&lt;/th>
 &lt;th style="text-align: center">不可重复读&lt;/th>
 &lt;th style="text-align: center">幻读&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td style="text-align: center">READ-UNCOMMITTED&lt;/td>
 &lt;td style="text-align: center">√&lt;/td>
 &lt;td style="text-align: center">√&lt;/td>
 &lt;td style="text-align: center">√&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: center">READ-COMMITTED&lt;/td>
 &lt;td style="text-align: center">×&lt;/td>
 &lt;td style="text-align: center">√&lt;/td>
 &lt;td style="text-align: center">√&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: center">REPEATABLE-READ&lt;/td>
 &lt;td style="text-align: center">×&lt;/td>
 &lt;td style="text-align: center">×&lt;/td>
 &lt;td style="text-align: center">√&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td style="text-align: center">SERIALIZABLE&lt;/td>
 &lt;td style="text-align: center">×&lt;/td>
 &lt;td style="text-align: center">×&lt;/td>
 &lt;td style="text-align: center">×&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;/li>
&lt;li>
&lt;p>MySQL InnoDB 存储引擎的默认支持的隔离级别是 &lt;strong>REPEATABLE-READ（可重读）&lt;/strong>&lt;/p>
&lt;blockquote class='book-hint '>
&lt;p>使用命令查看，通过&lt;code>SELECT @@tx_isolation;&lt;/code>。&lt;br>
MySQL 8.0 该命令改为&lt;code>SELECT @@transaction_isolation;&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>MySQL&amp;gt; SELECT @@tx_isolation;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>+-----------------+
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>| @@tx_isolation |
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>+-----------------+
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>| REPEATABLE-READ |
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>+-----------------+ &lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/blockquote>&lt;/li>
&lt;li>
&lt;p>从上面对SQL标准定义了&lt;strong>四个隔离级别&lt;/strong>的介绍可以看出，标准的SQL隔离级别里，&lt;strong>REPEATABLE-READ(可重复读)&lt;strong>是不可以防止幻读的。但是，&lt;strong>InnoDB实现的REPEATABLE-READ&lt;/strong> 隔离级别其实是可以&lt;/strong>解决幻读&lt;/strong>问题发生的，分两种情况&lt;/p>
&lt;ol>
&lt;li>&lt;strong>快照读&lt;/strong>：由&lt;strong>MVCC&lt;/strong>机制来保证不出现幻读&lt;/li>
&lt;li>&lt;strong>当前读&lt;/strong>：使用&lt;strong>Next-Key Lock&lt;/strong>进行&lt;strong>加锁&lt;/strong>来保证不出现幻读，Next-Key Lock是&lt;strong>行锁（Record Lock ）和间隙锁（Gap Lock）的结合&lt;/strong>，行锁只能锁住已经存在的行，为了避免插入新行，需要依赖&lt;strong>间隙锁&lt;/strong> (&lt;strong>只用间隙锁不行，因为间隙锁是 &amp;gt; 或 &amp;lt; ，不包括等于，所以再可重复读下原记录可能会被删掉&lt;/strong>)&lt;/li>
&lt;/ol>
&lt;p>因为&lt;strong>隔离级别越低，事务请求的锁越少&lt;/strong>，所以大部分数据库系统的隔离级别都是 &lt;strong>READ-COMMITTED&lt;/strong> ，但是你要知道的是 InnoDB 存储引擎默认使用 &lt;strong>REPEATABLE-READ&lt;/strong> 并不会有任何性能损失。&lt;/p></description></item><item><title>日志</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/MySQL/ly0602lymysql-logs/</link><pubDate>Sat, 14 Jan 2023 17:31:53 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/MySQL/ly0602lymysql-logs/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;h1 id="前言">前言&lt;a class="anchor" href="#%e5%89%8d%e8%a8%80">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>
&lt;p>首先要了解一个东西 ：WAL，全称 Write-Ahead Logging&lt;code>，它的关键点就是&lt;/code>先写日志，再写磁盘&lt;/p>
&lt;blockquote class='book-hint '>
&lt;p>在概念上，innodb通过***force log at commit***机制实现事务的持久性，即在事务提交的时候，必须先将该事务的所有事务日志写入到磁盘上的redo log file和undo log file中进行持久化&lt;/p>&lt;/blockquote>&lt;blockquote class='book-hint '>
&lt;ol>
&lt;li>
&lt;p>WAL 机制的原理也很简单：&lt;strong>修改并不直接写入到数据库文件中，而是写入到另外一个称为 WAL 的文件中；如果事务失败，WAL 中的记录会被忽略，撤销修改；如果事务成功，它将在随后的某个时间被写回到数据库文件中，提交修改&lt;/strong>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>使用 WAL 的数据库系统不会再每新增一条 WAL 日志就将其刷入数据库文件中，一般&lt;strong>积累一定的量然后批量写入，通常使用页为单位，这是磁盘的写入单位&lt;/strong>。 同步 &lt;strong>WAL 文件和数据库文件的行为被称为 checkpoint（检查点）&lt;/strong>，一般在 WAL 文件积累到一定页数修改的时候；当然，有些系统也可以手动执行 checkpoint。执行 checkpoint 之后，WAL 文件可以被清空，这样可以保证 WAL 文件不会因为太大而性能下降。&lt;/p>
&lt;p>有些数据库系统读取请求也可以使用 WAL，通过读取 WAL 最新日志就可以获取到数据的最新状态&lt;/p>
&lt;blockquote class='book-hint '>
&lt;p>关于checkpoint：https://www.cnblogs.com/chenpingzhao/p/5107480.html&lt;strong>思考一下这个场景&lt;/strong>：如果重做日志可以无限地增大，同时缓冲池也足够大 ，那么是不需要将缓冲池中页的新版本刷新回磁盘。因为当发生宕机时，完全可以通过重做日志来恢复整个数据库系统中的数据到宕机发生的时刻。但是这需要两个前提条件：1、缓冲池可以缓存数据库中所有的数据；2、重做日志可以无限增大&lt;/p>
&lt;p>因此Checkpoint（检查点）技术就诞生了，目的是解决以下几个问题：1、&lt;strong>缩短数据库的恢复时间&lt;/strong>；2、&lt;strong>缓冲池不够用时，将脏页刷新到磁盘&lt;/strong>；3、&lt;strong>重做日志不可用时，刷新脏页&lt;/strong>。&lt;/p>
&lt;ul>
&lt;li>当数据库发生宕机时，数据库&lt;strong>不需要重做所有的日志，因为Checkpoint之前的页都已经刷新回磁盘&lt;/strong>。数据库只需对Checkpoint后的重做日志进行恢复，这样就大大缩短了恢复的时间。&lt;/li>
&lt;li>当缓冲池不够用时，根据LRU算法会溢出最近最少使用的页，若此页为脏页，那么需要强制执行Checkpoint，将脏页也就是页的新版本刷回磁盘。&lt;/li>
&lt;li>当重做日志出现不可用时，因为当前事务数据库系统对重做日志的设计都是循环使用的，并不是让其无限增大的，重做日志可以被重用的部分是指这些重做日志已经不再需要，当数据库发生宕机时，数据库恢复操作不需要这部分的重做日志，因此这部分就可以被覆盖重用。如果重做日志还需要使用，那么必须强制Checkpoint，将缓冲池中的页至少刷新到当前重做日志的位置。&lt;/li>
&lt;/ul>&lt;/blockquote>&lt;/li>
&lt;li>
&lt;p>mysql 的 WAL，大家可能都比较熟悉。mysql 通过 redo、undo 日志实现 WAL。redo log 称为重做日志，每当有操作时，在&lt;strong>数据变更之前将操作写入 redo log&lt;/strong>，这样当发生掉电之类的情况时系统可以在重启后继续操作。undo log 称为撤销日志，当一些变更执行到一半无法完成时，可以根据撤销日志恢复到变更之间的状态。mysql 中用 redo log 来在系统 Crash 重启之类的情况时修复数据（事务的持久性），而 undo log 来保证事务的原子性。&lt;/p></description></item><item><title>索引</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/MySQL/ly0601lymysql-index/</link><pubDate>Tue, 10 Jan 2023 22:09:25 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/MySQL/ly0601lymysql-index/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;h1 id="补充索引基础知识引自b站sgg视频">补充索引基础知识(引自b站sgg视频)&lt;a class="anchor" href="#%e8%a1%a5%e5%85%85%e7%b4%a2%e5%bc%95%e5%9f%ba%e7%a1%80%e7%9f%a5%e8%af%86%e5%bc%95%e8%87%aab%e7%ab%99sgg%e8%a7%86%e9%a2%91">#&lt;/a>&lt;/h1>
&lt;ol>
&lt;li>存储引擎，数据的基本单位是&lt;strong>页&lt;/strong>，如果数据很少，只有一页，那就简单，是直接二分查找(不涉及磁盘IO)；如果数据很多，有好几个页，那么需要对页建立一种数据结构，能够最快定位到哪一页，然后减少磁盘IO&lt;/li>
&lt;/ol>
&lt;h1 id="索引介绍">索引介绍&lt;a class="anchor" href="#%e7%b4%a2%e5%bc%95%e4%bb%8b%e7%bb%8d">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>
&lt;p>索引是一种用于&lt;strong>快速查询&lt;/strong>和&lt;strong>检索数据&lt;/strong>的数据结构，其本质可以看成是一种&lt;strong>排序好&lt;/strong>的数据结构&lt;/p>
&lt;blockquote class='book-hint '>
&lt;p>索引的作用就相当于书的目录。打个比方: 我们在查字典的时候，如果没有目录，那我们就只能一页一页的去找我们需要查的那个字，速度很慢。如果有目录了，我们只需要先去目录里查找字的位置，然后直接翻到那一页就行了&lt;/p>&lt;/blockquote>&lt;/li>
&lt;li>
&lt;p>索引底层数据结构存在很多种类型，常见的索引结构有：&lt;strong>B树&lt;/strong>，&lt;strong>B+树&lt;/strong>和&lt;strong>Hash&lt;/strong>、&lt;strong>红黑树&lt;/strong>。在MySQL中，无论是Innodb还是MyIsam，都使用了B+树作为索引结构&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h1 id="索引的优缺点">索引的优缺点&lt;a class="anchor" href="#%e7%b4%a2%e5%bc%95%e7%9a%84%e4%bc%98%e7%bc%ba%e7%82%b9">#&lt;/a>&lt;/h1>
&lt;p>&lt;strong>优点：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>使用索引可以大大&lt;strong>加快&lt;/strong> 数据的检索速度（大大&lt;strong>减少检索的数据量&lt;/strong>）, 这也是创建索引的最主要的原因。&lt;/li>
&lt;li>通过创建&lt;strong>唯一性索引&lt;/strong>，可以保证数据库表中&lt;strong>每一行数据的唯一性&lt;/strong>。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>缺点：&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>创建索引&lt;/strong>和&lt;strong>维护索引&lt;/strong>需要&lt;strong>耗费许多&lt;/strong>时间。当对表中的数据进行&lt;strong>增删改&lt;/strong>的时候，如果数据有索引，那么&lt;strong>索引也需要动态的修改&lt;/strong>，会&lt;strong>降低 SQL 执行效率&lt;/strong>。&lt;/li>
&lt;li>索引需要使用&lt;strong>物理文件存储&lt;/strong>，也会&lt;strong>耗费一定空间&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>索引一定会提高查询性能吗&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>多数情况下，&lt;strong>索引查询&lt;/strong>都是比&lt;strong>全表扫描&lt;/strong>要快的。但是如果数据库的&lt;strong>数据量不大&lt;/strong>，那么使用&lt;strong>索引也不一定能够带来很大提升&lt;/strong>&lt;/li>
&lt;/ul>
&lt;h1 id="索引的底层数据结构">索引的底层数据结构&lt;a class="anchor" href="#%e7%b4%a2%e5%bc%95%e7%9a%84%e5%ba%95%e5%b1%82%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84">#&lt;/a>&lt;/h1>
&lt;h2 id="hash表">Hash表&lt;a class="anchor" href="#hash%e8%a1%a8">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>哈希表是键值对的集合，通过&lt;strong>键（key）&lt;strong>即可&lt;/strong>快速取出对应的值（value）&lt;/strong>，因此哈希表可以&lt;strong>快速检索数据（接近O(1))&lt;/strong>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>为何能够通过key快速取出value呢？原因在于&lt;strong>哈希算法（也叫散列算法）&lt;/strong>。通过哈希算法，我们可以&lt;strong>快速找到key对应的index&lt;/strong>，找到了index也就找到了对应的value&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>hash &lt;span style="color:#f92672">=&lt;/span> hashfunc(key)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>index &lt;span style="color:#f92672">=&lt;/span> hash &lt;span style="color:#f92672">%&lt;/span> array_size&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>注意，图中keys[天蓝色]是&lt;strong>字符串&lt;/strong>，&lt;strong>不是什么莫名其妙的人&lt;/strong>
&lt;img src="img/ly-20241212141858665.png" alt="ly-20241212141858665" />&lt;/p>
&lt;/li>
&lt;li>
&lt;p>哈希算法有个 &lt;strong>Hash 冲突&lt;/strong> 问题，也就是说&lt;strong>多个不同的 key 最后得到的 index 相同&lt;/strong>。通常情况下，我们常用的解决办法是 &lt;strong>链地址法&lt;/strong>。链地址法就是&lt;strong>将哈希冲突数据存放在链表中&lt;/strong>。就比如 JDK1.8 之前 &lt;code>HashMap&lt;/code> 就是通过&lt;strong>链地址法来解决哈希冲突&lt;/strong>的。不过，JDK1.8 以后&lt;code>HashMap&lt;/code>&lt;strong>为了减少链表过长&lt;/strong>的时候搜索时间过长引入了&lt;strong>红黑树&lt;/strong>。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>为了减&lt;strong>少 Hash 冲突&lt;/strong>的发生，一个&lt;strong>好的哈希函数&lt;/strong>应该**“均匀地”将数据分布**在整个可能的哈希值集合中&lt;/p>
&lt;/li>
&lt;li>
&lt;p>由于&lt;strong>Hash索引&lt;/strong>不支持&lt;strong>顺序&lt;/strong>和&lt;strong>范围查询&lt;/strong>，假如要对表中的数据进行&lt;strong>排序&lt;/strong>或者&lt;strong>进行范围查询&lt;/strong>，那&lt;strong>Hash索引&lt;/strong>就不行了，并且，&lt;strong>每次IO&lt;/strong>只能取一个&lt;/p>
&lt;blockquote class='book-hint '>
&lt;p>例如： &lt;code>SELECT * FROM tb1 WHERE id &amp;lt; 500 ; &lt;/code>&lt;/p>
&lt;ul>
&lt;li>这种范围查询中，B+树 优势非常大 直接遍历比500小的&lt;strong>叶子&lt;/strong>节点即可&lt;/li>
&lt;li>如果使用Hash索引，由于&lt;strong>Hash索引&lt;/strong>是根据hash算法来定位的，难不成把1 ~499 （小于500）的数据都进行一次hash计算来定位吗？这就是Hash最大的缺点&lt;/li>
&lt;/ul>
&lt;p>这里其实说的是已经找到了索引，但是索引没有数据的情形。要么通过&lt;strong>hash&lt;/strong>一个个取数据，要么利用&lt;strong>B+树&lt;/strong>的特性（叶子节点有完整数据）&lt;/p></description></item><item><title>字符集详解</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/ly0502lycharactor-set/</link><pubDate>Tue, 10 Jan 2023 16:48:22 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/ly0502lycharactor-set/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;p>图示总结&lt;br>
&lt;img src="img/ly-20241212141855666.png" alt="ly-20241212141855666" />&lt;/p>
&lt;ul>
&lt;li>MySQL字符编码集有&lt;strong>两套UTF-8&lt;/strong>编码实现：&lt;strong>utf-8&lt;/strong> 和 &lt;strong>utf8mb4&lt;/strong>&lt;br>
而其中，utf-8 &lt;strong>不支持存储&lt;/strong>emoji符号和一些比较复杂的汉字、繁体字，会出错&lt;/li>
&lt;/ul>
&lt;h1 id="何为字符集">何为字符集&lt;a class="anchor" href="#%e4%bd%95%e4%b8%ba%e5%ad%97%e7%ac%a6%e9%9b%86">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>
&lt;p>字符是&lt;strong>各种文字&lt;/strong>和&lt;strong>符号&lt;/strong>的统称，包括&lt;strong>各个国家文字&lt;/strong>、&lt;strong>标点符号&lt;/strong>、&lt;strong>表情&lt;/strong>、&lt;strong>数字&lt;/strong>等等&lt;/p>
&lt;ul>
&lt;li>字符集就是&lt;strong>一系列字符&lt;/strong>的集合，字符集的种类较多，每个字符集可以表示的&lt;strong>字符范围&lt;/strong>通常不同，就比如说&lt;strong>有些字符集&lt;/strong>无法表示汉字&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>计算机只能存储&lt;strong>二进制&lt;/strong>的数据，那&lt;strong>英文&lt;/strong>、&lt;strong>汉字&lt;/strong>、&lt;strong>表情&lt;/strong>等字符应该如何存储呢&lt;/p>
&lt;ul>
&lt;li>
&lt;p>我们要将这些&lt;strong>字符和二进制的数据一一对应&lt;/strong>起来，比如说字符“a”对应“01100001”，反之，“01100001”对应 “a”。我们将字符对应二进制数据的过程称为&amp;quot;&lt;strong>字符编码&lt;/strong>&amp;quot;，反之，二进制数据解析成字符的过程称为“&lt;strong>字符解码&lt;/strong>”。&lt;/p>
&lt;p>&lt;img src="img/ly-20241212141855958.png" alt="ly-20241212141855958" />&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h1 id="有哪些常见的字符集">有哪些常见的字符集&lt;a class="anchor" href="#%e6%9c%89%e5%93%aa%e4%ba%9b%e5%b8%b8%e8%a7%81%e7%9a%84%e5%ad%97%e7%ac%a6%e9%9b%86">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>常见的字符集有&lt;strong>ASCLL&lt;/strong>、&lt;strong>GB2312&lt;/strong>、&lt;strong>GBK&lt;/strong>、&lt;strong>UTF-8&lt;/strong>&lt;/li>
&lt;li>不同的字符集的主要区别在于
&lt;ol>
&lt;li>可以表示的&lt;strong>字符范围&lt;/strong>&lt;/li>
&lt;li>&lt;strong>编码方式&lt;/strong>&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ul>
&lt;h2 id="ascll">ASCLL&lt;a class="anchor" href="#ascll">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>ASCII&lt;/strong> (&lt;strong>A&lt;/strong>merican &lt;strong>S&lt;/strong>tandard &lt;strong>C&lt;/strong>ode for &lt;strong>I&lt;/strong>nformation &lt;strong>I&lt;/strong>nterchange，美国信息交换标准代码) 是一套主要用于现代美国英语的字符集（这也是 ASCII 字符集的局限性所在）&lt;/p>
&lt;blockquote class='book-hint '>
&lt;p>&lt;strong>为什么 ASCII 字符集没有考虑到中文等其他字符呢？&lt;/strong> 因为计算机是美国人发明的，当时，计算机的发展还处于比较雏形的时代，还未在其他国家大规模使用。因此，美国发布 ASCII 字符集的时候没有考虑兼容其他国家的语言&lt;/p>&lt;/blockquote>&lt;/li>
&lt;li>
&lt;p>ASCII 字符集至今为止共定义了 128 个字符，其中有 33 个控制字符（比如回车、删除）无法显示&lt;/p>
&lt;/li>
&lt;li>
&lt;p>一个 ASCII 码长度是一个字节也就是 8 个 bit，比如“a”对应的 ASCII 码是“01100001”。不过，最高位是 0 仅仅作为校验位，其余 7 位使用 0 和 1 进行组合，所以，ASCII 字符集可以定义 128（2^7）个字符&lt;/p>
&lt;blockquote class='book-hint '>
&lt;p>由于，ASCII 码可以表示的字符实在是太少了。后来，人们对其进行了扩展得到了 &lt;strong>ASCII 扩展字符集&lt;/strong> 。ASCII 扩展字符集使用 8 位（bits）表示一个字符，所以，ASCII 扩展字符集可以定义 256（2^8）个字符&lt;/p></description></item><item><title>数据库基础</title><link>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/ly0501lybasis/</link><pubDate>Tue, 20 Dec 2022 11:19:14 +0000</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/Review/java_guide/database/ly0501lybasis/</guid><description>&lt;blockquote class='book-hint '>
&lt;p>转载自https://github.com/Snailclimb/JavaGuide（添加小部分笔记）感谢作者!&lt;/p>&lt;/blockquote>&lt;blockquote class='book-hint '>
&lt;p>这部分内容由于涉及太多概念性内容，所以参考了维基百科和百度百科相应的介绍。&lt;/p>&lt;/blockquote>&lt;h1 id="什么是数据库数据库管理系统数据库系统数据库管理员">什么是数据库，数据库管理系统，数据库系统，数据库管理员&lt;a class="anchor" href="#%e4%bb%80%e4%b9%88%e6%98%af%e6%95%b0%e6%8d%ae%e5%ba%93%e6%95%b0%e6%8d%ae%e5%ba%93%e7%ae%a1%e7%90%86%e7%b3%bb%e7%bb%9f%e6%95%b0%e6%8d%ae%e5%ba%93%e7%b3%bb%e7%bb%9f%e6%95%b0%e6%8d%ae%e5%ba%93%e7%ae%a1%e7%90%86%e5%91%98">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>&lt;strong>数据库&lt;/strong>：数据库（&lt;strong>DataBase 简称DB&lt;/strong>）就是&lt;strong>信息的集合&lt;/strong>或者说&lt;strong>数据库管理系统管理的数据的集合&lt;/strong>。&lt;/li>
&lt;li>&lt;strong>数据库管理系统&lt;/strong>：数据库管理系统（&lt;strong>Database Management System 简称DBMS&lt;/strong>）是一种&lt;strong>操纵和管理数据库&lt;/strong>的大型软件，通常用于建立、使用和维护 &lt;strong>数据库&lt;/strong>。&lt;/li>
&lt;li>&lt;strong>数据库系统（范围最大）&lt;/strong>：数据库系统（Data Base System，简称DBS）通常由**软件、数据和数据管理员（DBA）**组成。&lt;/li>
&lt;li>&lt;strong>数据库管理员&lt;/strong>：数据库管理员（Database Adminitrator，简称DBA）负责全面&lt;strong>管理和控制&lt;/strong>数据库系统 &lt;strong>(是一个人)&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>数据库系统基本构成&lt;/strong>如下图所示&lt;br>
&lt;img src="img/ly-20241212141854630.png" alt="ly-20241212141854630" />&lt;/p>
&lt;h1 id="什么是元组码候选码主码外码主属性非主属性">什么是元组，码，候选码，主码，外码，主属性，非主属性&lt;a class="anchor" href="#%e4%bb%80%e4%b9%88%e6%98%af%e5%85%83%e7%bb%84%e7%a0%81%e5%80%99%e9%80%89%e7%a0%81%e4%b8%bb%e7%a0%81%e5%a4%96%e7%a0%81%e4%b8%bb%e5%b1%9e%e6%80%a7%e9%9d%9e%e4%b8%bb%e5%b1%9e%e6%80%a7">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>&lt;strong>元组&lt;/strong>：元组（tuple）是&lt;strong>关系数据库&lt;/strong>中的&lt;strong>基本概念&lt;/strong>，&lt;strong>关系&lt;/strong>是一张表，表中的&lt;strong>每行&lt;/strong>（即数据库中的每条&lt;strong>记录&lt;/strong>）就是一个元组，每列就是一个属性。在&lt;strong>二维表&lt;/strong>里，元组也成为&lt;strong>行&lt;/strong>&lt;/li>
&lt;li>&lt;strong>码&lt;/strong>：码就是能&lt;strong>唯一标识实体&lt;/strong>的属性，对应表中的&lt;strong>列&lt;/strong>&lt;/li>
&lt;li>&lt;strong>候选码&lt;/strong>：若关系中的&lt;strong>某一属性&lt;/strong>或&lt;strong>属性组的值&lt;/strong>能&lt;strong>唯一的标识一个元组&lt;/strong>，而&lt;strong>其任何、子集都不能再标识&lt;/strong>，则称该&lt;strong>属性组&lt;/strong>为&lt;strong>候选码&lt;/strong>。例如：在学生实体中，&lt;strong>“学号”&lt;strong>是能唯一的区分学生实体的，同时又假设&lt;/strong>“姓名”、“班级”的属性组合&lt;/strong>足以区分学生实体，那么**{学号}&lt;strong>和&lt;/strong>{姓名，班级}&lt;strong>都是&lt;/strong>候选码**。&lt;/li>
&lt;li>&lt;strong>主码&lt;/strong>：主码也叫&lt;strong>主键&lt;/strong>，主码是&lt;strong>从候选码&lt;/strong>中选出来的。一个实体集中只能有&lt;strong>一个主码&lt;/strong>，但可以有&lt;strong>多个候选码&lt;/strong>&lt;/li>
&lt;li>&lt;strong>外码&lt;/strong>：外码也叫&lt;strong>外键&lt;/strong>。如果&lt;strong>一个关系中的一个属性&lt;/strong>是&lt;strong>另外一个关系中的主码&lt;/strong>则这个属性为外码。&lt;/li>
&lt;li>&lt;strong>主属性&lt;/strong> ： &lt;strong>候选码中出现过的属性&lt;/strong>称为主属性(&lt;strong>这里强调单个&lt;/strong>）。比如关系 工人（工号，身份证号，姓名，性别，部门）. 显然&lt;strong>工号和身份证号&lt;/strong>都能够唯一标示这个关系，所以都是候选码。&lt;strong>工号、身份证号这两个属性就是主属性&lt;/strong>。如果主码是一个属性组，那么属性组中的属性都是主属性。&lt;/li>
&lt;li>&lt;strong>非主属性：&lt;/strong> &lt;strong>不包含在任何一个候选码中的属性&lt;/strong>称为非主属性。比如在关系——学生（学号，姓名，年龄，性别，班级）中，主码是“学号”，那么其他的“姓名”、“年龄”、“性别”、“班级”就都可以称为非主属性。&lt;/li>
&lt;/ul>
&lt;h1 id="主键和外键有什么区别">主键和外键有什么区别&lt;a class="anchor" href="#%e4%b8%bb%e9%94%ae%e5%92%8c%e5%a4%96%e9%94%ae%e6%9c%89%e4%bb%80%e4%b9%88%e5%8c%ba%e5%88%ab">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>&lt;strong>主键(主码)&lt;/strong> ：主键用于&lt;strong>唯一标识一个元组&lt;/strong>，不能有重复，不允许为空。一个表只能有一个主键。&lt;/li>
&lt;li>&lt;strong>外键(外码)&lt;/strong> ：外键用来和其他表建立联系用，&lt;strong>外键是另一表的主键&lt;/strong>，外键是可以有重复的，可以是空值。一个表可以有多个外键&lt;/li>
&lt;/ul>
&lt;h1 id="为什么不推荐使用外键与级联">为什么不推荐使用外键与级联&lt;a class="anchor" href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e4%b8%8d%e6%8e%a8%e8%8d%90%e4%bd%bf%e7%94%a8%e5%a4%96%e9%94%ae%e4%b8%8e%e7%ba%a7%e8%81%94">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>
&lt;p>对于外键和级联，阿里巴巴开发手册这样说道&lt;/p>
&lt;blockquote class='book-hint '>
&lt;p>【强制】不得使用外键与级联，一切&lt;strong>外键概念&lt;/strong>必须在应用层解决。&lt;/p>
&lt;p>说明: 以学生和成绩的关系为例，学生表中的 student_id 是主键，那么成绩表中的 student_id 则为外键。如果更新学生表中的 student_id，同时触发成绩表中的 student_id 更新，即为级联更新。&lt;/p>
&lt;p>缺点： &lt;strong>外键与级联更新适用于单机低并发，不适合分布式、高并发集群; 级联更新是强阻塞，存在数据库更新风暴的风 险; 外键影响数据库的插入速度&lt;/strong>&lt;/p>&lt;/blockquote>&lt;/li>
&lt;li>
&lt;p>为什么不要使用外键&lt;/p>
&lt;ol>
&lt;li>
&lt;p>增加了复杂性&lt;/p>
&lt;blockquote class='book-hint '>
&lt;p>a. 每次做DELETE 或者UPDATE都必须考虑外键约束，会导致开发的时候很痛苦, &lt;strong>测试数据极为不方便&lt;/strong>; b. 外键的主从关系是定的，假如那天需求有变化，&lt;strong>数据库中的这个字段根本不需要和其他表有关联的话就会增加很多麻烦&lt;/strong>。&lt;/p>&lt;/blockquote>&lt;/li>
&lt;li>
&lt;p>增加了额外操作&lt;/p>
&lt;blockquote class='book-hint '>
&lt;p>数据库需要增加维护外键的工作，比如当我们做一些涉及外键字段的增，删，更新操作之后，需要触发相关操作去检查，保证数据的的一致性和正确性，这样会不得不消耗资源；（&lt;strong>个人觉得这个不是不用外键的原因&lt;/strong>，因为即使你不使用外键，你在应用层面也还是要保证的。所以，我觉得这个影响可以忽略不计。）&lt;/p></description></item></channel></rss>