<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Yang&#39;s log</title>
  
  
  <link href="http://example.com/atom.xml" rel="self"/>
  
  <link href="http://example.com/"/>
  <updated>2024-03-07T00:00:00.000Z</updated>
  <id>http://example.com/</id>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>操作手册之建立博客</title>
    <link href="http://example.com/2023/12/13/DIY/DIY-blog-create/"/>
    <id>http://example.com/2023/12/13/DIY/DIY-blog-create/</id>
    <published>2023-12-13T00:00:00.000Z</published>
    <updated>2024-03-07T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>本人很懒，不多介绍</p><span id="more"></span><h2 id="1-git 代理"><a href="#1-git 代理" class="headerlink" title="1.git 代理"></a>1.git 代理 </h2><p> 第一步首先处理好 git 网络问题。</p><h3 id="代理配置"><a href="# 代理配置" class="headerlink" title="代理配置"></a>代理配置</h3><p>1. 对 http 和 https 代理：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"># http and https</span><br><span class="line">git config --global http.proxy http://127.0.0.1:7890</span><br><span class="line">git config --global https.proxy https://127.0.0.1:7890</span><br><span class="line"></span><br><span class="line"># socks5</span><br><span class="line">git config --global http.proxy socks5://127.0.0.1:7890</span><br><span class="line">git config --global https.proxy socks5://127.0.0.1:7890</span><br><span class="line"></span><br><span class="line"># unset</span><br><span class="line">git config --global --unset http.proxy</span><br><span class="line">git config --global --unset https.proxy</span><br></pre></td></tr></table></figure><p>2. 对 ssh 代理：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">sudo apt install connect-proxy</span><br><span class="line"># (or) https://github.com/larryhou/connect-proxy</span><br><span class="line">vim ~/.ssh/config</span><br><span class="line"></span><br><span class="line"># socks5</span><br><span class="line">Host github.com</span><br><span class="line">User git</span><br><span class="line">ProxyCommand connect -S 127.0.0.1:7890 %h %p</span><br><span class="line"></span><br><span class="line"># http || https</span><br><span class="line">Host github.com</span><br><span class="line">User git</span><br><span class="line">ProxyCommand connect -H 127.0.0.1:7890 %h %p</span><br></pre></td></tr></table></figure><p>3. 打开 Git 的配置文件 <code>~/.gitconfig</code>，在文件末尾添加以下内容：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[http]</span><br><span class="line">   proxy = http:// 代理地址: 端口号</span><br><span class="line">[https]</span><br><span class="line">   proxy = https:// 代理地址: 端口号</span><br></pre></td></tr></table></figure><p>如果你的代理需要账号密码验证，可以使用以下内容：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[http]</span><br><span class="line">   proxy = http:// 用户名: 密码 @代理地址: 端口号</span><br><span class="line">[https]</span><br><span class="line">   proxy = https:// 用户名: 密码 @代理地址: 端口号</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">[https]</span><br><span class="line">proxy = http://127.0.0.1:7890</span><br><span class="line">[http]</span><br><span class="line">proxy = http://127.0.0.1:7890</span><br></pre></td></tr></table></figure><p>参考：<a href="https://juejin.cn/post/7216147029230993445">Git 配置代理和取消的两种方法 - 掘金 (juejin.cn)</a></p><h3 id="git-clone- 链接（免密登录 -git-push 无需密码）"><a href="#git-clone- 链接（免密登录 -git-push 无需密码）" class="headerlink" title="git clone 链接（免密登录 git push 无需密码）"></a>git clone 链接（免密登录 git push 无需密码）</h3><p>git 可以使用四种主要的协议来传输资料: 本地协议（Local），HTTP 协议，SSH（Secure Shell）协议及 git 协议。其中，本地协议由于目前大都是进行远程开发和共享代码所以一般不常用，而 git 协议由于缺乏授权机制且较难架设所以也不常用。</p><p>最常用的便是 SSH 和 HTTP(S)协议。git 关联远程仓库可以使用 http 协议或者 ssh 协议。</p><p><strong>ssh：</strong></p><ul><li>一般使用 22 端口；</li><li>通过先在本地生成 SSH 密钥对再把公钥上传到服务器；</li><li>速度相较慢点</li></ul><p><strong>https：</strong></p><ul><li>一般使用 443 端口；</li><li>通过用户名 &#x2F; 密码授权，可用性比较高；</li><li>速度相较快点</li></ul><p>一般企业防火墙会打开 80 和 443 这两个 http&#x2F;https 协议的端口，因此在架设了企业防火墙的时候使用 http 就可以很好的绕开安全限制使用 git 了，很方便；而对于 ssh 来说，企业防火墙很可能没打开 22 端口。</p><p><strong>【使用区别】</strong></p><p><strong>clone 项目：</strong></p><p>　　** 使用 ssh 方式时，需要配置 ssh key，即要将生成的 SSH 密钥对的公钥上传至服务器；<br>**</p><p>　　<strong>使用 http 方式时，没有要求，可以直接克隆下来。</strong></p><p><strong>push 项目：</strong></p><p>　　<strong>使用 ssh 方式时，不需要验证用户名和密码，*<em>** 之前配置过 ssh key，(如果你没设置密码)**</em>* 直接 push 即可；</strong></p><p>　　<strong>使用 http 方式时，需要验证用户名和密码。</strong></p><p> <strong>总结：</strong></p><p>HTTPS 利于匿名访问，适合开源项目，可以方便被别人克隆和读取(但没有 push 权限)；</p><p>SSH 不利于匿名访问，比较适合内部项目，只要配置了 SSH 公钥极可自由实现 clone 和 push 操作。</p><h4 id="1-【github 上切换 SSH-HTTP 方式】"><a href="#1-【github 上切换 SSH-HTTP 方式】" class="headerlink" title="1.【github 上切换 SSH&#x2F;HTTP 方式】"></a>1.<strong>【github 上切换 SSH&#x2F;HTTP 方式】</strong></h4><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312122011305.png" alt="image-20231211222839311" style="zoom:67%;" /><h4 id="2-【如何生成 SSH 密钥以及上传】"><a href="#2-【如何生成 SSH 密钥以及上传】" class="headerlink" title="2.【如何生成 SSH 密钥以及上传】"></a>2.<strong>【如何生成 SSH 密钥以及上传】</strong></h4><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312122030728.png" alt="image-20231211222811442" style="zoom:67%;" /><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312122031340.png" alt="image-20231211222925339-17023049665181" style="zoom:67%;" /><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312122033088.png" alt="image-20231211222941917"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">git config --global user.name &#x27;yourname&#x27; </span><br><span class="line">git config --global user.email &#x27;youremail&#x27;</span><br><span class="line"></span><br><span class="line">// 如果之前已经设置了 那就不要加后面的 yourname/youremail 直接获取即可 </span><br><span class="line"> 输入指令：ssh-keygen -t rsa -C “youremail”；</span><br></pre></td></tr></table></figure><p>检验配置成功：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh -T git@github.com</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312122114045.png" alt="image-20231212211408011"></p><p><strong>注意：</strong></p><p>按回车即表示默认这个文件路径名，接着又会提示你输入两次密码（<strong>该密码是你 push 文件的时候要输入的密码，而不是 github 管理者的密码</strong>），当然，你也可以不输入密码，直接按回车。那么 push 的时候就不需要输入密码，直接提交到 github 上了。</p><h4 id="3-【http 如何保存凭证信息】"><a href="#3-【http 如何保存凭证信息】" class="headerlink" title="3.【http 如何保存凭证信息】"></a>3.<strong>【http 如何保存凭证信息】</strong></h4><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312122033897.png" alt="image-20231211223158533"></p><p>参考：<a href="https://www.cnblogs.com/wannananana/p/12059806.html">【git】git 中使用 https 和 ssh 协议的区别以及它们的用法 - WANNANANANA - 博客园 (cnblogs.com)</a></p><h2 id="2-git 操作"><a href="#2-git 操作" class="headerlink" title="2.git 操作"></a>2.git 操作 </h2><p> 常用操作：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">git pull name branch</span><br><span class="line">git add .</span><br><span class="line">git commit -m &quot;message&quot;</span><br><span class="line">git push name branch</span><br><span class="line"></span><br><span class="line">git remote add name url(github repositories)</span><br><span class="line">git remote remove name</span><br><span class="line">git remote -v</span><br><span class="line"></span><br><span class="line">git status</span><br></pre></td></tr></table></figure><p>初始化 git 仓库（标准化流程）：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">echo &quot;# realVG&quot; &gt;&gt; README.md</span><br><span class="line">git init</span><br><span class="line">git add README.md</span><br><span class="line">git commit -m &quot;first commit&quot;</span><br><span class="line">git branch -M main</span><br><span class="line">git remote add origin git@github.com:AngelYang23/realVG.git</span><br><span class="line">git push -u origin main</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git remote add origin git@github.com:AngelYang23/realVG.git</span><br><span class="line">git branch -M main</span><br><span class="line">git push -u origin main</span><br></pre></td></tr></table></figure><p>Git commit 规范：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;type&gt;(&lt;scope&gt;): &lt;subject&gt;</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line">type(必须)</span><br><span class="line"></span><br><span class="line">用于说明 git commit 的类别，只允许使用下面的标识。</span><br><span class="line"></span><br><span class="line">feat：新功能（feature）。</span><br><span class="line"></span><br><span class="line">fix/to：修复 bug，可以是 QA 发现的 BUG，也可以是研发自己发现的 BUG。</span><br><span class="line"></span><br><span class="line">fix：产生 diff 并自动修复此问题。适合于一次提交直接修复问题 </span><br><span class="line">to：只产生 diff 不自动修复此问题。适合于多次提交。最终修复问题提交时使用 fix</span><br><span class="line">docs：文档（documentation）。</span><br><span class="line"></span><br><span class="line">style：格式（不影响代码运行的变动）。</span><br><span class="line"></span><br><span class="line">refactor：重构（即不是新增功能，也不是修改 bug 的代码变动）。</span><br><span class="line"></span><br><span class="line">perf：优化相关，比如提升性能、体验。</span><br><span class="line"></span><br><span class="line">test：增加测试。</span><br><span class="line"></span><br><span class="line">chore：构建过程或辅助工具的变动。</span><br><span class="line"></span><br><span class="line">revert：回滚到上一个版本。</span><br><span class="line"></span><br><span class="line">merge：代码合并。</span><br><span class="line"></span><br><span class="line">sync：同步主线或分支的 Bug。</span><br><span class="line"></span><br><span class="line">scope(可选)</span><br><span class="line"></span><br><span class="line">scope 用于说明 commit 影响的范围，比如数据层、控制层、视图层等等，视项目不同而不同。</span><br><span class="line"></span><br><span class="line"> 例如在 Angular，可以是 location，browser，compile，compile，rootScope， ngHref，ngClick，ngView 等。如果你的修改影响了不止一个 scope，你可以使用 * 代替。</span><br><span class="line"></span><br><span class="line">subject(必须)</span><br><span class="line"></span><br><span class="line">subject 是 commit 目的的简短描述，不超过 50 个字符。</span><br><span class="line"></span><br><span class="line">建议使用中文（感觉中国人用中文描述问题能更清楚一些）。</span><br><span class="line"></span><br><span class="line">结尾不加句号或其他标点符号。</span><br><span class="line">根据以上规范 git commit message 将是如下的格式：</span><br><span class="line">fix(DAO): 用户查询缺少 username 属性 </span><br><span class="line">feat(Controller): 用户查询接口开发</span><br></pre></td></tr></table></figure><p><a href="https://zhuanlan.zhihu.com/p/182553920">https://zhuanlan.zhihu.com/p/182553920</a></p><h2 id="3-markdown 图片上传"><a href="#3-markdown 图片上传" class="headerlink" title="3.markdown 图片上传"></a>3.markdown 图片上传 </h2><p>typora 与<a href="https://so.csdn.net/so/search?q=picgo&spm=1001.2101.3001.7020">picgo</a> 下载与安装（想办法）</p><p><a href="https://github.com/Molunerfinn/PicGo/releases">PicGo</a></p><h3 id="github 操作："><a href="#github 操作：" class="headerlink" title="github 操作："></a>github 操作：</h3><p>1）<strong>github 创建新仓库作为图床</strong></p><p>1、如果没有 GitHub 的账号的话可以申请注册一个</p><p>2、登陆以后，点击右上角的 <strong>+</strong> 号，然后点击 new repository 新建仓库（这个仓库作为你的图床）</p><p>3、新建仓库时，仓库名必填（仓库名尽量不要有空格），私有性选择公开，然后点击 create repository</p><p>2）<strong>新建 token 令牌 </strong> 作为 picgo 的配置输入</p><p>1、点击右上角头像列表中 <strong>Setting</strong> 选项</p><p>2、进入后点击最后一项： <strong>Developer setting</strong></p><p>3、进入后点击右边的最后一项，并且创建一个新的 <strong>token</strong></p><p>4、在 Note 填写你的 token 的名字，将 repo 打上勾就行，其余的不用管，然后直接点击 绿色图标 Generate token。</p><p>5、完成后，一定要保存此 token，因为只出现一次，一定要保存！！！！</p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312122131035.png" alt="img"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312122131254.png" alt="img"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312122132122.png" alt="image-20231212213233077"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312122134388.png" alt="img"></p><h3 id="PicGo 操作："><a href="#PicGo 操作：" class="headerlink" title="PicGo 操作："></a>PicGo 操作：</h3><p>1、下载完成后打开 PicGo</p><p>2、首次使用时进入 PicGo，点击设置 Server，将监听窗口设为：36677。可保持默认。</p><p>3、点击左边图床设置进入 GitHub 图床。</p><p>4、设定仓库名，填写格式：你的 GitHub 名 &#x2F; 新建的仓库名</p><p>5、设定分支名，填写自己想要填写的分支，也可以填写默认的 main</p><p>6、设定 Token，填写刚刚保存的 token 令牌。</p><p>7、指定存储路径，默认为 img&#x2F;，这个路径是你 GitHub 的新建仓库中某一个文件夹的路径</p><p>8、自定义域名：这里使用 <a href="https://raw.githubusercontent.com/%E4%BD%A0%E7%9A%84GitHub%E5%90%8D/%E4%BB%93%E5%BA%93%E5%90%8D/master%EF%BC%8C%E8%BF%99%E9%87%8C%E7%9A%84">https://raw.githubusercontent.com/ 你的 GitHub 名 / 仓库名 /master，这里的</a> master 是你的仓库下的一个分支</p><p>9、最后点击确定和设为默认图床。</p><p>设置时间戳命名图片</p><p>设置日志文件日志记录等级  全部 -all</p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312122137567.png" alt="image-20231212213748535"></p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312122138857.png" alt="image-20231212213834808" style="zoom:67%;" /><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312122139649.png" alt="image-20231212213942607" style="zoom:67%;" /><h3 id="Typora 操作："><a href="#Typora 操作：" class="headerlink" title="Typora 操作："></a>Typora 操作：</h3><p>1、设置完 PicGo 之后，打开 Typora，找到文件中的 偏好设置。</p><p>2、插入图片第一项选择上传图片。</p><p>3、点击 图像 ，前三项 以及 最后一项 打钩。</p><p>4、将 上传服务改为 PicGo（app）。</p><p>5、PicGo 路径改为你的本地 PicGo 安装目录中的 PicGo.exe 文件</p><p>6、最后点击验证图片上传来验证。</p><p>7、查看 PicGo 相册 和 GitHub 同步的上传</p><p>8、在 Typora 中插入图片时，图片可以通过 PicGo 直接上传到 GitHub 仓库中，以后传输 Typora 文件时便不用再将图片一起打包上传。</p><p>9、配置代理</p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312122143113.png" alt="image-20231212214311060"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312122345866.png" alt="image-20231212234527745"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312122341214.png" alt="image-20231212234156906"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&quot;flags&quot;: [[&quot;proxy-server&quot;, &quot;http://127.0.0.1:7890&quot;]]</span><br></pre></td></tr></table></figure><p>参考：<a href="https://shenxiaojian.com/set-proxy-for-typora/">typora 设置代理 – SXJ 的小站 (shenxiaojian.com)</a></p><h2 id="4-hexo"><a href="#4-hexo" class="headerlink" title="4.hexo"></a>4.hexo</h2><h3 id="hexo 安装"><a href="#hexo 安装" class="headerlink" title="hexo 安装"></a>hexo 安装 </h3><p> 安装 hexo 之前，需安装 node.js，git</p><p>安装命令：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install -g hexo-cli --registry=https://registry.npm.taobao.org</span><br></pre></td></tr></table></figure><p>检验是否安装成功：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">node -v</span><br><span class="line">npm -v</span><br><span class="line">hexo -v</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312131024423.png" alt="image-20231213102451323"></p><p><strong>补充</strong>(加速)</p><p>1.npm 镜像网址：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">npm 官方原始镜像网址是：https://registry.npmjs.org/</span><br><span class="line">淘宝 NPM 镜像：https://registry.npm.taobao.org</span><br><span class="line">阿里云 NPM 镜像：https://npm.aliyun.com</span><br><span class="line">腾讯云 NPM 镜像：https://mirrors.cloud.tencent.com/npm/</span><br><span class="line">华为云 NPM 镜像：https://mirrors.huaweicloud.com/repository/npm/</span><br><span class="line">网易 NPM 镜像：https://mirrors.163.com/npm/</span><br><span class="line">中科院大学开源镜像站：http://mirrors.ustc.edu.cn/</span><br><span class="line">清华大学开源镜像站：https://mirrors.tuna.tsinghua.edu.cn/</span><br></pre></td></tr></table></figure><p>设置镜像加速：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm config set registry + 对应的镜像网址</span><br></pre></td></tr></table></figure><p>查看镜像：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm config get registry</span><br></pre></td></tr></table></figure><p>2.npm 安装命令：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install -g xxx --registry= 镜像网址</span><br></pre></td></tr></table></figure><p>3.nrm 是一个 npm 源管理器，允许你快速地在 npm 源间切换。（本人感觉很局限）</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">npm install -g nrm</span><br><span class="line">nrm ls    </span><br><span class="line">nrm use taobao/tencent</span><br><span class="line">nrm test</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312131103322.png" alt="image-20231213110305278"></p><h3 id="hexo 本地搭建博客"><a href="#hexo 本地搭建博客" class="headerlink" title="hexo 本地搭建博客"></a>hexo 本地搭建博客</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"># First create</span><br><span class="line">npm install hexo-cli -g(已做)</span><br><span class="line">hexo init blog/hexo</span><br><span class="line">cd blog/hexo</span><br><span class="line">npm install</span><br><span class="line">hexo server</span><br><span class="line"># Existing project open</span><br><span class="line">cd blog/AngelYang23.github.io</span><br><span class="line">npm install</span><br><span class="line">hexo server/hexo s</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312131119284.png" alt="image-20231213111908094"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312131120931.png" alt="image-20231213112039870"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312131125575.png" alt="image-20231213112557520"></p><p>参考：<a href="https://hexo.io/zh-cn/">Hexo</a></p><p><a href="https://juejin.cn/post/7120189037104594980">Hexo 搭建与部署指南 - 掘金 (juejin.cn)</a></p><p><a href="https://zhuanlan.zhihu.com/p/547520780">2022 Hexo 博客搭建和使用教程(Windows) - 知乎 (zhihu.com)</a></p><h3 id="hexo 样式设计"><a href="#hexo 样式设计" class="headerlink" title="hexo 样式设计"></a>hexo 样式设计</h3><h4 id="hexo 项目目录"><a href="#hexo 项目目录" class="headerlink" title="hexo 项目目录"></a>hexo 项目目录</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">hexo-install-directory</span><br><span class="line">├── CNAME</span><br><span class="line">├── _config.yml  //Hexo 的配置文件，可以配置主题、语言等</span><br><span class="line">├── avatar.jpg</span><br><span class="line">├── db.json</span><br><span class="line">├── debug.log</span><br><span class="line">├── node_modules</span><br><span class="line">├── public     // 执行 hexo g 命令后，生成的内容会在这里，包括所有的文章、页面、分类、tag 等.</span><br><span class="line">├── scaffolds    // 保存着默认模板，自定义模板就是修改该目录下的文件</span><br><span class="line">│   ├── draft.md // 默认的草稿模板</span><br><span class="line">│   ├── page.md  // 默认的页面模板</span><br><span class="line">│   └── post.md  // 默认的文章模板</span><br><span class="line">├── source  //Hexo 存放编辑页面的地方，可以使用 vim 或其他编辑器编辑这里的内容</span><br><span class="line">│   ├── 404.html // 自定义 404 页面，可以使用腾讯公益 404 页面</span><br><span class="line">│   ├── Staticfile </span><br><span class="line">│   ├── _drafts  // 存放所有的草稿文件的目录</span><br><span class="line">│   ├── _posts // 存放所有的文章文件的目录，用的最多，比如执行 hexo n &quot;post_name&quot; 之后，post_name 这篇文章就存放在这个目录下</span><br><span class="line">│   ├── categories</span><br><span class="line">└── themes //Hexo 的所有主题</span><br><span class="line">    ├── landscape // 原始 hexo 主题</span><br><span class="line">    ├── next     // 这是我目前用的主题</span><br></pre></td></tr></table></figure><p><strong>Front-matter</strong> 是文件最上方以 <code>---</code> 分隔的区域，用于指定个别文件的变量，举例来说：（注意—隐藏）</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">---</span><br><span class="line">title: 操作手册之建立博客</span><br><span class="line">date: 2023-12-13  </span><br><span class="line">categories:</span><br><span class="line">- Study</span><br><span class="line">- blog_create</span><br><span class="line">tags:</span><br><span class="line">- blog</span><br><span class="line">- config</span><br><span class="line">description: 本篇博客记录我从零到一创建博客的所有操作过程：包括 git 相关操作，设置图床，还有 hexo 框架的搭建和使用。</span><br><span class="line">copyright: true</span><br><span class="line">---</span><br></pre></td></tr></table></figure><p>注意：hexo 报错 YAMLException: end of the stream or a document separator is expected</p><p>可能是空格问题，冒号以后需要加空格</p><p><strong>hexo 分类和标签</strong></p><p><strong>1.YAML 格式</strong></p><p>YAML 中允许表示三种格式，分别是常量值，对象和数组</p><p>使用 #作为注释，YAML 中只有行注释。</p><p>基本格式要求：<br>1，YAML 大小写敏感；<br>2，使用缩进代表层级关系；<br>3，缩进只能使用空格，不能使用 TAB，不要求空格个数，只需要相同层级左对齐（一般 2 个或 4 个空格）</p><p>** 分类(categories)** 具有顺序性和层次性。Hexo 不支持指定多个同级分类。</p><p>** 标签(tags)** 没有顺序和层次。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">categories:</span><br><span class="line">- Diary</span><br><span class="line">- Life</span><br><span class="line">tags:</span><br><span class="line">- PS3</span><br><span class="line">- Games</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">categories:</span><br><span class="line">- 分类</span><br><span class="line">- 子分类</span><br><span class="line">- 子子分类</span><br></pre></td></tr></table></figure><p><strong>2.JSON Front-matter</strong></p><p>除了 YAML 外，你也可以使用 JSON 来编写 Front-matter，只要将 <code>---</code> 代换成 <code>;;;</code> 即可。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&quot;title&quot;: &quot;Hello World&quot;,</span><br><span class="line">&quot;date&quot;: &quot;2013/7/13 20:46:25&quot;</span><br><span class="line">;;;</span><br></pre></td></tr></table></figure><p><strong>文章截断</strong></p><p>在需要截断的地方加入：</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;!-- more --&gt;</span><br></pre></td></tr></table></figure><p><a href="https://hexo.io/zh-cn/docs/front-matter">Front-matter | Hexo</a></p><p><a href="https://mp.weixin.qq.com/s/2Spv9KHO6mLHui0CFBmCnQ">Hexo 搭建个人博客网站 (qq.com)</a></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312132222632.png" alt="image-20231213222240581"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312132230217.png" alt="image-20231213223022175"></p><h4 id="常见命令"><a href="# 常见命令" class="headerlink" title="常见命令"></a>常见命令</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">hexo new 文章文件名                新建文章</span><br><span class="line">hexo new draft 草稿文件名          新建草稿</span><br><span class="line">hexo new page 导航选项页文件名      新建导航选项页界面</span><br><span class="line">hexo new [layout] &lt;title&gt;        新建新文章或者新的页面</span><br><span class="line">hexo publish 文章文件名  发布草稿</span><br></pre></td></tr></table></figure><h4 id="布局（Layout）"><a href="# 布局（Layout）" class="headerlink" title="布局（Layout）"></a>布局（Layout）</h4><p>Hexo 有三种默认布局：<code>post</code>、<code>page</code> 和 <code>draft</code>。在创建者三种不同类型的文件时，它们将会被保存到不同的路径；而您自定义的其他布局和 <code>post</code> 相同，都将储存到 <code>source/_posts</code> 文件夹。</p><p>通过修改 <code>_config.yml</code> 的<code>default_layout</code>参数修改。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">default_layout: post</span><br></pre></td></tr></table></figure><p>在博客的 <code>scaffolds</code> 目录下有三个 <code>md</code> 文档。分别为 <code>post.md</code> ， <code>draft.md</code> 和<code>page.md</code>。</p><p>当您新建文章时，Hexo 会根据 scaffold 来建立文件。Hexo 的模板是指在新建的文章文件中默认填充的内容。例如，如果您修改 scaffold&#x2F;post.md 中的 Front-matter 内容，那么每次新建一篇文章时都会包含这个修改。</p><p><code>hexo</code>最大的优势就是可以结合 <code>GitHub page</code> 来搭建一个免费的个人博客系统，将文章都托管到 <code>GitHub</code> 上，在也不用担心服务器过期的问题了，而且可以自己买一个域名，解析了 <code>GitHub</code> 上就可以直接使域名访问了。很多小伙伴给自己个博客添加了很多其他的功能，但是每次写文章的时候都需要在文章的开头去写一遍，这简直就是重复造轮子。其实，你可以自己在 <code>scaffolds</code> 中去修改属于你自己的模板</p><h4 id="配置"><a href="# 配置" class="headerlink" title="配置"></a>配置 </h4><p> 在 Hexo 中有两份主要的配置文件，其名称都是 <code>_config.yml</code>。其中，一份位于站点根目录下，主要包含 Hexo 本身的配置；另一份位于主题目录下，这份配置由主题作者提供，主要用于配置主题相关的选项。</p><p>为了描述方便，在以下说明中，将前者称为 **<code>站点配置文件 </code>**， 后者称为 **<code> 主题配置文件</code>**。</p><p>Hexo 默认使用的主题是 landscape，对应 .&#x2F;themes 目录下的 landscape 文件夹。可切换成其他 主题，选好之后，先将对应的主题 clone 到或下载好拷贝到 .&#x2F;themes 目录下，再启用即可。建议使用 clone ，使用 clone ，假如有一天这个主题更新了，只需要 pull 一下就可以获取到最新样式了。</p><p>我用的主题：<strong>Icarus</strong> </p><h5 id="config-yml"><a href="#config-yml" class="headerlink" title="_config.yml"></a>_config.yml</h5><p><strong>网站</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">title: Yang&#x27;s log</span><br><span class="line">subtitle: &#x27;&#x27;</span><br><span class="line">description: &#x27;Welcome to my blog, I&#x27;m AngelYang&#x27;</span><br><span class="line">keywords: The good old days</span><br><span class="line">author: Yang</span><br><span class="line">language: zh-CN</span><br><span class="line">timezone: &#x27;&#x27;</span><br></pre></td></tr></table></figure><p><strong>文章</strong></p><p><a href="https://zhuanlan.zhihu.com/p/127755045">超全 Windows10 快捷键大全 - 知乎 (zhihu.com)</a></p><p><a href="https://zhuanlan.zhihu.com/p/44044896">VS Code 的常用快捷键 - 知乎 (zhihu.com)</a></p><p><a href="https://www.cnblogs.com/ljhdo/p/13373208.html">VSCode 快捷键（整理） - 悦光阴 - 博客园 (cnblogs.com)</a></p><p><a href="https://blog.csdn.net/jeikerxiao/article/details/84105529">SSH 三步解决免密登录_免密登录 ssh-CSDN 博客</a></p><p><a href="https://easyhexo.com/2-Theme-use-and-config/2-12-hexo-theme-icarus/#%E5%AE%89%E8%A3%85">hexo-theme-icarus | Easy Hexo 👨‍💻</a></p><p><a href="https://leimao.github.io/archives/">Archives - Lei Mao’s Log Book</a></p><p><a href="https://www.mad-coding.cn/2019/08/02/%E8%87%AA%E5%AE%9A%E4%B9%89hexo%E5%88%9B%E5%BB%BA%E6%96%87%E7%AB%A0%E7%9A%84%E6%A8%A1%E6%9D%BF/#0x02-%E4%BF%AE%E6%94%B9%E6%AD%A5%E9%AA%A4">https://www.mad-coding.cn/2019/08/02/%E8%87%AA%E5%AE%9A%E4%B9%89hexo%E5%88%9B%E5%BB%BA%E6%96%87%E7%AB%A0%E7%9A%84%E6%A8%A1%E6%9D%BF/#0x02-%E4%BF%AE%E6%94%B9%E6%AD%A5%E9%AA%A4</a></p><p><a href="https://shmilybaozi.github.io/2018/11/05/hexo%E6%96%87%E7%AB%A0%E6%A8%A1%E6%9D%BF%E8%AE%BE%E7%BD%AE/">https://shmilybaozi.github.io/2018/11/05/hexo%E6%96%87%E7%AB%A0%E6%A8%A1%E6%9D%BF%E8%AE%BE%E7%BD%AE/</a></p><p><a href="https://www.cnblogs.com/eryoyo/p/16678333.html">https://www.cnblogs.com/eryoyo/p/16678333.html</a></p><p><a href="https://mp.weixin.qq.com/s?__biz=MzA4MzA2NDUxOQ==&mid=2247484078&idx=1&sn=2e2c698e3c17b62f46d668c278955867&chksm=9ffd6106a88ae810da69f20e204b2a9ec2f5020b5fbe58586333a02ce769b5091fefcc0c1e30&cur_album_id=1339610139661484036&scene=189#wechat_redirect">Hexo 主题配置 - Icarus (qq.com)</a></p><p><a href="https://blog.csdn.net/cxy35/article/details/104854763">Hexo 主题配置 - Icarus_hexo icalus-CSDN 博客</a></p><p><a href="https://wyh0517.github.io/2020/06/24/rule/">https://wyh0517.github.io/2020/06/24/rule/</a></p><p><a href="https://leimao.github.io/faq/">https://leimao.github.io/faq/</a></p>]]></content>
    
    
    <summary type="html">本篇博客记录我从零到一创建博客的所有操作过程：包括git相关操作，设置图床，还有hexo框架的搭建和使用。</summary>
    
    
    
    <category term="Study" scheme="http://example.com/categories/Study/"/>
    
    <category term="blog_create" scheme="http://example.com/categories/Study/blog-create/"/>
    
    
    <category term="blog" scheme="http://example.com/tags/blog/"/>
    
    <category term="config" scheme="http://example.com/tags/config/"/>
    
  </entry>
  
  <entry>
    <title>常识积累</title>
    <link href="http://example.com/2023/12/27/CommonSense/CommonSense/"/>
    <id>http://example.com/2023/12/27/CommonSense/CommonSense/</id>
    <published>2023-12-27T00:00:00.000Z</published>
    <updated>2024-03-07T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>本人很懒，不多介绍</p><span id="more"></span><h2 id="中国近现代重要战争"><a href="# 中国近现代重要战争" class="headerlink" title="中国近现代重要战争"></a>中国近现代重要战争 </h2><h3 id="列强侵华："><a href="# 列强侵华：" class="headerlink" title="列强侵华："></a> 列强侵华：</h3><p>一、鸦片战争（1840）</p><p>起因（导火线）：林则徐虎门销烟（1839），为了改变贸易逆差（中国出口丝绸，茶叶，瓷器；外国出口鸦片）</p><p><strong>林则徐名言：苟利国家生死以，岂因祸福避趋之。</strong></p><p>南京条约（1840），割地（香港）</p><p>历史香港三个割地：除第一个，1860 北京条约（九龙），1898 中英展拓香港界址专条</p><p>意义：开始沦为</p><p>二、第二次鸦片战争（1856-1860）</p><p>起因：进一步扩大贸易</p><p>火烧圆明园</p><p>英法主力军，俄美帮凶</p><p>天津条约（1858，英法俄美）瑷珲条约（1858，俄）北京条约（1860，英法俄，九龙）</p><p>瑷珲条约，领土最多的条约</p><p>意义：加深</p><p>三、中法战争（1883-1885）</p><p><strong>刘永福（黑旗军）、冯子才（镇南关大捷）、刘铭传（台湾军务，首任巡抚）</strong></p><p>法国不胜而胜，中国不败而败</p><p><strong>中法新约（越南享主权，打开中国西南开口岸）</strong></p><p>（1）<a href="https://baike.baidu.com/item/%E6%B8%85%E6%94%BF%E5%BA%9C/9915502?fromModule=lemma_inlink">清政府 </a> 承认法国对越南的保护权，允许对越南订立条约。</p><p>（2）勘定中越边界，并在边界保胜以上和 <a href="https://baike.baidu.com/item/%E8%B0%85%E5%B1%B1/3020843?fromModule=lemma_inlink"> 谅山 </a> 以北指定两处为通商地点，允许法国商人在此居住并设领事；</p><p>（3）降低中国云南、广西同越南边界的进出口税率；</p><p>（4）日后中国修筑铁路应向法国商办；</p><p>（5）法军退出台湾、澎湖。</p><p>四、甲午战争（1894）</p><p>日本，明治维新，资本主义</p><p>大陆政策：台、朝鲜、满蒙、中国、亚洲</p><p>北洋水师全军覆没：黄海（邓世昌撞舰），威海卫海战（靖远舰，丁汝昌自杀）</p><p>马关条约（1895）：辽东（俄法德）、台湾（50 年）</p><p>2 亿两（3000 万赎回）</p><p>意义：大大加深</p><p>根本原因：社会制度落后</p><p><strong>旅顺大屠杀</strong></p><p>五、八国联军侵华</p><p>义和团运动（扶清灭洋）农民运动</p><p>英、俄、德、法、美、日、意、奥</p><p>11 国（荷兰，比利时，西班牙）</p><p>辛丑条约（庚子赔款）4.5 亿</p><p>意义：完全彻底沦为</p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312271121005.png" alt="image-20231227112133951"></p><p>尼布楚条约，平等条约</p><p>雅尔塔协议（1945 年，外蒙维持现状，苏联在东北特权）</p><h3 id="中山革命："><a href="# 中山革命：" class="headerlink" title="中山革命："></a>中山革命：</h3><p>一、辛亥革命</p><p>起因：</p><p>黄花岗起义（72 烈士）</p><p>保路运动（修铁路；商办铁路（农民，地主，商人），股份归国有，不归还股金；四川，武昌调兵）</p><p>1911 年 10 月 10 日</p><p>炸弹爆炸，9 日</p><p>标志：武昌起义</p><p>意义：反帝反封建资产阶级民主革命</p><p>中国半殖民地半封建社会性质没有改变</p><p>张勋、袁世凯</p><p>亚洲第一个民主共和国（资产阶级共和国）</p><p>列宁：亚洲的觉醒</p><p>1840-1949 半殖民地半封建社会</p><p>1949-1956 新民主主义社会</p><p>1956- 社会主义社会</p><p>二、二次革命</p><p>起因：</p><p>孙中山于 1913 年发动的反对袁世凯武装革命</p><p>孙中山：临时约法</p><p>袁世凯：解散国会，废止约法</p><p>宋教仁遇刺</p><p>结果：</p><p>北洋军胜，孙中山海外</p><p>三、护国运动（1915）</p><p>起因：中华帝国（帝制），出兵伐袁</p><p>蔡锷与小凤仙</p><p>取消帝制（83 天）</p><p>四、护法运动（1917-1918）</p><p>段祺瑞 三不要：不要约法，国会，旧总统</p><p>西南军阀（夺地盘）</p><p>失败</p><p>五、第二次护法运动（1921-1922）</p><p>陈炯明叛变，炮轰总统府</p><p>永丰舰</p><p>后续 1924 年，国共广州召开</p><p>国共第一次合作，联俄，联共，扶助农工</p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312271152213.png" alt="image-20231227115202175"></p><p>帝国主义并未统治中国</p><h3 id="毛蒋斗法："><a href="# 毛蒋斗法：" class="headerlink" title="毛蒋斗法："></a>毛蒋斗法：</h3><p>一、北伐战争</p><p>时间：1926 年 7 月</p><p>目的：推翻北洋军阀（吴佩孚、孙传芳、张作霖）统治。</p><p>主攻湖南、湖北</p><p>退回东北，皇姑屯事件爆炸案</p><p>1927 年，412 反革命政变，<strong>剿共</strong></p><p>1928 年，张学良东北易帜，青天白日满地红旗</p><p><strong>形式上统一中国</strong></p><p>二、南昌起义</p><p>时间：1928 年 8 月 1 日</p><p>打响了第一枪</p><p>上了井冈山</p><p>三、秋收起义</p><p>时间：1927 年 9 月</p><p>湖南江西边界</p><p>打长沙 -&gt; 文家市决策(农村)-&gt; 三湾改编（党的绝对领导）-&gt; 上井冈山</p><p>城市 -&gt; 农村</p><p>四、中原大战</p><p>阎锡山、冯玉祥、李宗仁</p><p>新军阀混战 规模最大，耗时最长的军阀混战</p><p>东北虎张学良  东北军</p><p>以蒋介石胜利</p><p>三次改变历史：</p><p>东北易帜，中原大战，西安事变</p><p>五、长征</p><p>时间：1934 年 10 月至 1936 年 10 月</p><p>1930-1934 五次围剿</p><p>前四次反围剿取得成功</p><p>王明，阵地站战，第五次反围剿失败</p><p>遵义会议</p><p>性质：被迫进行战略转移</p><p>结束：1935 年 10 月</p><p>吴起镇会师</p><p>会宁会师</p><p>红一，红二，红四</p><p>14 年之后百万雄师</p><p>18 年抗美援朝</p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312271520127.png" alt="image-20231227152042066"></p><p>六、抗日战争</p><p>九一八事变</p><p>南满铁路，北大营</p><p>张学良，不抵抗政策 1932.02 东北全境沦陷</p><p>开端 局部</p><p>华北事变</p><p>五省自治运动</p><p>中日民族矛盾上升为主要矛盾</p><p>一二九运动</p><p>学生</p><p><strong>瓦窑堡会议</strong></p><p>统一战线策略方针</p><p>西安事变</p><p>七七事变</p><p>全面侵华</p><p><strong>洛川会议</strong></p><p>工作重心战区和敌后</p><p>淞沪会战</p><p>三个月灭亡中国计划</p><p>民族工业内迁争取时间</p><p>太原会战</p><p>平型关战役</p><p>不可战胜的神话</p><p>徐州会战</p><p>李宗仁台儿庄大捷</p><p>抗战以来最大胜利</p><p>武汉会战</p><p>中国抗日进入战略相持阶段</p><p>枣宜会战</p><p>张自忠</p><p>百团大战</p><p>我军兵力最多、规模最大、时间最长</p><p>皖南事变</p><p>新四军</p><p>陕北，八路军；游击，新四军</p><p>陈毅</p><p>日本投降</p><p>1945 年 8 月 15 日</p><p>9 月 2 日仪式密苏里</p><p>9 月 3 日抗日战争纪念日</p><p>七、解放战争</p><p>重庆谈判</p><p>双十协议 1946 撕毁</p><p>1945.9-10 上党战役（山西）谈判</p><p>歼灭阎锡山势力</p><p>1947 延安保卫战 胡宗南 转战陕北 38 个地方</p><p>1947 孟良崮战役 （山东）</p><p>张临甫 74 师</p><p>1947 刘邓挺进大别山</p><p>三大战役（辽沈，淮海，平津）</p><p>渡江战役</p><p>蒋 1975</p><p>毛 1976</p><p>大一圈</p><p>1950-1953 抗美援朝“立国”（上甘岭）</p><p>1962 中印自卫反击战</p><p>1969 中苏珍宝岛自卫反击战</p><p>1979 中越战争</p><p><strong>8 年改为 14 年抗战</strong></p><p><strong>1927-1937 年 10 年土地革命</strong></p><p><strong>秋收起义 —土地革命</strong></p><p>三大起义：南昌起义、秋收起义、广州起义（张太雷，叶挺，叶剑英）</p><p><strong>昆仑关大捷，广西，北部湾，登陆中国</strong>    抗日战争</p><h2 id="中国的古代制度"><a href="# 中国的古代制度" class="headerlink" title="中国的古代制度"></a>中国的古代制度 </h2><h3 id="官职制度"><a href="# 官职制度" class="headerlink" title="官职制度"></a> 官职制度 </h3><h4 id="一、皇位"><a href="# 一、皇位" class="headerlink" title="一、皇位"></a> 一、皇位</h4><p>1、禅让制</p><p>权臣篡位</p><p>曹丕 汉献帝 禅让</p><p>2、嫡长子继承制</p><p>嫡 庶</p><p>贤 没有客观标准</p><h4 id="二、诸侯"><a href="# 二、诸侯" class="headerlink" title="二、诸侯"></a>二、诸侯</h4><p>1、分封制</p><p>八百诸侯会孟津</p><p>齐</p><p>世袭</p><p>郡县 任命</p><p>2、宗法制</p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312271654722.png" alt="image-20231227165413595"></p><p>3、五等爵</p><p>公、候、伯、子、男</p><p>刘协 山阳公 韦小宝 涿鼎公</p><h4 id="三、选官"><a href="# 三、选官" class="headerlink" title="三、选官"></a>三、选官</h4><p>1、世官制(先秦)</p><p>春秋中叶 商鞅变法 军功爵制 虎狼之师</p><p>2、察举制（汉代）</p><p>举 入仕</p><p>出身</p><p>举秀才不知书，举孝廉父别局</p><p>3、征辟制（汉代）</p><p><strong>征召和辟除</strong></p><p>征召，是皇帝亲自下旨，聘请一些声望极高，有特殊才能或者品学兼优的人授以官职。 辟除是汉代中央或者地方高官把一些有才能的人网罗到自己身边为僚属。 </p><p>4、九品中正制（魏晋南北朝）</p><p>中正官</p><p>出身</p><p>上品无寒门，下品无世族</p><p>5、科举制（隋–清）</p><p>隋炀帝设进士科</p><p>武则天武举和殿试</p><p>北宋糊名法 誊录法</p><p>明清 八股取士</p><p>清朝 1905 年科举被废除</p><p>乡试、会试、殿试</p><p>读书人  童生试（县试、府试、院试）秀才</p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312271712707.png" alt="image-20231227171206659"></p><p>唐伯虎，唐解元</p><p>连中三元</p><p>状元，榜眼，探花</p><p>金榜题名、蟾宫折桂、（月宫）、独占鳌头、五子登科（窦禹豹 窦燕山）、名落孙山</p><p>学通行修，经中博士 (察举制)</p><p>戊戌变法 1898 科举制 1905</p><p>桂冠（比喻拿到冠军）</p><p>问鼎中原（楚庄王）</p><h3 id="中央与地方制度"><a href="# 中央与地方制度" class="headerlink" title="中央与地方制度"></a>中央与地方制度</h3><p>1、郡县制（秦汉盛行）</p><p>2、三公九卿制（秦）</p><p>太尉、丞相、御史大夫（互相牵制，互不相属）</p><p>军务、政务、监察</p><p>四世三公</p><p>3、刺史制（汉武帝）</p><p>监察地方</p><p>最高行政长官</p><p>吕布</p><p>4、三省六部制（始于隋朝，完善于唐朝）</p><p>中书省决策</p><p>门下省审议</p><p>尚书省执行：</p><p>工部（工程，水利）</p><p>刑部（司法）</p><p>兵部（军队）</p><p>礼部（科举考试，祭祀，外交）</p><p>户部（财政，户籍）</p><p>吏部（官吏）</p><p>5、行省制（元）</p><p>中央只保留中书省（国务院）直辖</p><p>10 个行省</p><p>省制开端</p><p>宣政院（西藏）</p><p>澎湖巡检司（澎湖，琉球）</p><p>6、内阁制</p><p>朱元璋 废丞相</p><p>朱棣 顾问 -&gt; 提升</p><p>万历首辅张居正</p><p>7、八旗制（满族）</p><p>上三旗（正黄旗、正白旗、镶黄旗）</p><p>下五旗（正蓝旗，正红旗，镶白旗、镶蓝旗、镶红旗）</p><p>8、军机处</p><p>雍正 军政大权 秘书处</p><p>君主专制，达到顶峰</p><p>两汉时期政治经济制：</p><p>刺史制、察举制、编户齐民（户籍制度，百姓姓名年龄身份财富 载入户籍）</p><p>一条鞭法（明朝）</p><h3 id="礼仪制度"><a href="# 礼仪制度" class="headerlink" title="礼仪制度"></a>礼仪制度</h3><h4 id="1、政治礼仪"><a href="#1、政治礼仪" class="headerlink" title="1、政治礼仪"></a>1、政治礼仪</h4><p>1）礼乐制 贵贱有别，符合身份</p><p>西周 周公制礼乐制</p><p>不同身份 不同礼仪，不同音乐</p><p>歌舞 天子 64 人 诸侯 36 人</p><p>2）封禅 泰山祭祀</p><p>受命于天 秦始皇 刘封，刘禅</p><p>3）<strong>五礼</strong> 吉（祭祀）、凶（哀悯，吊唁 葬礼）、军（检阅，出征 军事）、嘉（登基，婚礼 喜庆）、宾（宾客、外交）  西周时期</p><h4 id="2、生活礼仪"><a href="#2、生活礼仪" class="headerlink" title="2、生活礼仪"></a>2、生活礼仪</h4><p>1）诞生礼 三朝、满月、百日、周岁</p><p>三朝 3 日 男孩 弄璋之喜（玉） 女孩 弄瓦之喜（纺织）</p><p>满月 胎发</p><p>百日 百家锁</p><p>周岁 抓周</p><p>2）排行  伯 仲 叔 季</p><p>司马仲达</p><p>3）冠礼、<strong>笄 ji-（错误：笈 ji&#x2F;）</strong>礼（男子二十，女子十五）</p><p>年龄别称</p><p>垂髫 三四岁至七八岁儿童</p><p>总角 八九岁至十三四岁的少年</p><p>豆蔻 初夏 没到盛夏 十三四岁的女孩子</p><p>束发——男子十五岁。</p><p>弱冠——男子二十岁。</p><p>而立——三十岁。</p><p>不惑——四十岁。</p><p>知命——五十岁。</p><p>花甲——六十岁。60 甲子</p><p>古稀——七十岁。人生七十古来稀</p><p>耄耋——八九十岁。</p><p>期颐——一百岁。期望长命百岁，颐养天年</p><p>子曰:“吾十有五而志于学，三十而立，四十而不惑，五而知天命，六十而耳顺，七十而从心所欲，不逾矩。</p><p>4）婚姻六礼</p><p>纳采（请媒人提亲）、问名（问女方名字，生辰八字年月日时）、纳吉（占卜）、纳征（聘礼送到女方家）、请期（婚期，请求女方同意不同意）、亲迎（新郎至女方家，迎娶新娘）</p><p>5）七出三不去</p><p>七出：不顺父母、无子、淫、妒、有恶疾、多言（离间亲属）、窃盗</p><p>三不出：有所取无所归（没有娘家了）、与更三年丧、前贫贱后富贵</p><p>6）见面礼 作揖、拜</p><p>略弯，抱拳前推</p><p>一般：右拳， 左在外边</p><p>跪拜</p><p>7）座次礼</p><p>筵席 西北南东</p><p>朝会 皇帝背北面南</p><p>南面称帝 北面称臣</p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312281705051.png" alt="image-20231228170505956"></p><p>风树之悲 树欲静而风不止，子欲养而亲不带</p><p>金兰之交 二人同心，其利断金，同心之言，其臭如兰</p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312281707678.png" alt="image-20231228170755629"></p><p>人比黄花瘦 菊花</p><p>巾帼 妇女</p><p>及笄</p><p>笈笄: 古代指女孩子已经到了出嫁的年龄。这里笈 ，应该通“及”</p><p>笄，古代女子用以装饰发耳的一种簪子，用来插住挽起的头发，或插住帽子。曾在河姆渡遗址出土。</p><p>笈，多用竹、藤编织，用以放置书籍、衣巾、药物等，即书箱，例如：负～从师。</p><h2 id="中国古代帝王将相"><a href="# 中国古代帝王将相" class="headerlink" title="中国古代帝王将相"></a>中国古代帝王将相 </h2><p> 黄袍加身 赵匡胤</p><p>约法三章 刘邦</p><p>开辟西域 张骞</p><p>资治通鉴 司马光</p><h3 id="古代帝王将相"><a href="# 古代帝王将相" class="headerlink" title="古代帝王将相"></a>古代帝王将相 </h3><h4 id="先秦"><a href="# 先秦" class="headerlink" title="先秦"></a> 先秦 </h4><h5 id="帝王"><a href="# 帝王" class="headerlink" title="帝王"></a> 帝王 </h5><p> 舜 孝感天地</p><p>尧 娥皇，女英嫁给他</p><p>禹 三过家门而不入、<strong>建夏</strong></p><p>启 夏  旧 禹 夏 新</p><p>汤 建商 鸣条之战 伊尹</p><p>周文王 姬昌 西伯拘而演《周易》</p><p>伏羲 八卦 </p><p>乾 qián</p><p>坤 kūn</p><p>震 zhèn</p><p>巽 xùn</p><p>坎 kǎn</p><p>离 lí</p><p>艮 gèn</p><p>兑 duì</p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312282101490.png" alt="image-20231228210114388"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312282120851.png" alt="image-20231228212015744"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202312282150752.png" alt="image-20231228215013695"></p><p>乾清宫</p><p>坤宁宫</p><p>文王 六十四卦 6 个线</p><p>百子</p><p>文王百子</p><p>周武王 姬发 武王伐纣 八百里诸侯会孟津 牧野之战</p><p>周幽王 烽火戏诸侯</p><p>褒姒 犬戎</p><p>攻破镐京</p><p>平王东迁</p><p>春秋五霸 </p><p>齐桓公（五霸之首 葵丘之盟）晋文公（退避三舍）楚庄王（问鼎中原 一鸣惊人）吴王阖闾 hé lǘ和越王勾践（卧薪尝胆）</p><p><strong>鲁国  庆父不死，鲁难未已</strong></p><p>成语“ 南橘北枳” 是与齐国大夫晏婴出使楚国有关  </p><p>苏武牧羊在贝加尔湖一带  </p><h5 id="将相"><a href="# 将相" class="headerlink" title="将相"></a>将相 </h5><p> 姜尚 百家宗师、六韬 太公兵法 齐</p><p>管仲 尊王攘夷（周天子 夷族）、老马识途（放一匹老马）、管鲍之交（鲍叔牙 管 公子纠 鲍 小白）仲父 法家先驱</p><p>范蠡 （辅佐勾践，复国）兔死狗烹、商圣（经商、陶朱公）、西施（泛舟湖上）</p><p>财神 文 范蠡 比干 武 赵公明 关羽</p><p>沉鱼（西施、西施浣纱）落雁（王昭君、昭君出塞）、闭月（貂蝉、貂蝉拜月）羞花（杨贵妃、贵妃赏花）</p><p>千山万壑赴荆门，生长明妃尚有村  </p><p>司马昭 避免 称为明妃</p><p>伍子胥 一夜白发（楚国追杀，过昭关）、倒行逆施（违法常理，不择手段 楚平王 开坟、300 下鞭尸）、年糕（夫差赐死 瓦地三尺 城砖 年糕做的）</p><p><strong>秦孝公</strong> （嬴渠梁）商鞅变法（立木为信）</p><p>孙膑、庞涓—孙庞斗智</p><p>桂陵之战 （围魏救赵）马陵之战（减灶诱敌）</p><p><strong>孙膑著有《孙膑兵法》， 《孙子兵法》不是由他所写，而是由孙武所写</strong>  </p><p><strong>田忌赛马：孙膑的典故，孙膑曾经给田忌出主意帮助赛马，改变马的出场顺序，最终 2： 1 取得胜利。</strong>  </p><p>苏秦、张仪—合纵连横。  </p><p>合纵 ：“ 合众弱以攻一强”  </p><p>连横： “ 事一强以攻众弱”  </p><p>与苏秦相关的典故：前倨后恭、悬梁刺股。  （刺股” 指苏秦， “悬梁” 指东汉的孙敬）</p><p>蔺相如—负荆请罪、完璧归赵（秦昭襄王）、渑池之会  （mian/）</p><p>白起—战神、长平之战 (100 万) 赵括（纸上谈兵）白起</p><p>战国四将：白起、王翦、廉颇和李牧。</p><p>范睢（sui- ju-）—睚眦必报、远交近攻、固干削枝  </p><p>吕不韦—一字千金</p><p>荆轲—图穷匕见  </p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202401071551564.png" alt="image-20240107155111435"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202401071701013.png" alt="image-20240107155633864"></p><h4 id="秦汉"><a href="# 秦汉" class="headerlink" title="秦汉"></a>秦汉 </h4><p> 嬴政—统一六国、书同文、车同轨、统一度量衡  </p><p><strong>官方的是李斯创立的小篆，</strong>  </p><p><strong>非官方的是隶书，</strong>   </p><p>度” 是长度, “量” 是容积 , “衡” 是轻重 </p><p>赵高： 指鹿为马  </p><p>项羽—** 破釜沉舟(巨鹿之战  项羽 章邯、王离 秦军主力)**、力能扛鼎、四面楚歌 (垓下之战) </p><p>刘邦—约法三章、建西汉  垓下之战  </p><p>萧何—萧规曹随  (萧何、 曹参)</p><p>张良—博浪沙刺秦、孺子可教(黄石公)</p><p>韩信—一饭千金、胯下之辱、背水一战、十面埋伏、多多益善、暗度陈仓</p><p>一字千金（吕不韦）、一饭千金（韩信）、一顾千金（伯乐是相 <br> 马大师，哪批马能被他看一眼，这匹马身价倍增）、一诺千金（季布以讲诚信而 <br> 闻名)</p><p>汉文帝、汉景帝—文景之治  景帝时期有七国之乱。  </p><p>刘彻——北击匈奴、独尊儒术、盐铁官营（桑弘羊是专门搞经济的）、巫蛊之祸（江充  诬陷太子要谋反  夷江充三族）、金屋藏娇  </p><p>司马迁—著有《史记》，是第一本纪传体通史  </p><p><strong>“ 本纪” 写的是帝王， “ 世家”写的是诸侯， “ 列传” 写的是重要人物， “ 表” 是大事年表， “ 书” 是典章制度。</strong>  </p><p>张骞—开辟西域  凿空之旅  改变了汉朝的地域观念</p><p>主父偃—推恩令  </p><p>刘秀—昆阳之战、建东汉、光武中兴</p><p>马援—马革裹尸、老当益壮  最终马援病死在征战的途中  </p><p>班超—投笔从戎、不入虎穴焉得虎子</p><p>投笔从戎的是班超，班固是他哥哥，著有《汉书》</p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202401071700227.png" alt="image-20240107170002135"></p><h4 id="三国两晋南北朝"><a href="# 三国两晋南北朝" class="headerlink" title="三国两晋南北朝"></a>三国两晋南北朝 </h4><p> 曹操——官渡之战、赤壁之战、 “奸雄”（治世之能臣，乱世之奸雄 挟天子以令诸侯   ） 、望梅止渴  </p><p>曹丕——建魏  著作： 《典论》   文艺理论批评专著  </p><p>文艺理论批评专著  </p><p>刘备——三顾茅庐、建蜀汉  </p><p>刘禅——乐不思蜀  </p><p>关羽——斩颜良、（文丑无关）单刀赴会（鲁肃请他谈谈荆州  ）、水淹七军（擒于禁、 斩庞德，威震华夏  ）、败走麦城（吕蒙偷袭荆州，关羽败走麦城，最终被马忠所擒  ）</p><p>诸葛亮——鞠躬尽瘁、平孟获（南征孟获，七擒七纵平定了孟获  ）、北伐（最终没有成功，在五丈原病死  对手（司马懿）太强大，生生耗死了诸葛亮    ）、八阵图  （是后人复制出的，真假无法考据  ）</p><p>木牛流马（手推车）、孔明灯、 诸葛连弩  </p><p>孙权——建吴  </p><p>周瑜——赤壁之战、羽扇纶巾  </p><p>吕蒙——刮目相看  </p><p>陆逊——火烧连营  </p><p>司马炎——建西晋  晋武帝，建西晋（三家归晋）  </p><p>司马睿——建东晋  </p><p>谢安——淝水之战、东山再起  在后方坐镇，打赢淝水之战。谢安曾在东山隐居， 后官居相位，故称为东山再起。  </p><p>祖逖——闻鸡起舞、中流击楫（jī jí）  东晋名将  在河边用手敲桨，说北伐不成功不回来了 ，功败垂成，忧愤而死  </p><p>北魏孝文帝——汉化改革、迁都洛阳  拓跋宏  </p><p>郦道元——水经注  北魏官员  地理学著作  </p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202401072006213.png" alt="image-20240107200616162"></p><h4 id="隋唐"><a href="# 隋唐" class="headerlink" title="隋唐"></a>隋唐 </h4><p> 杨坚——建隋、开皇之治  </p><p>杨广——开科举、修运河  </p><p>（唐）皮日休：尽道隋亡为此河，至今千里赖通波。若无水殿龙舟事，共禹论功不较多。写大运河，即“隋亡为此河”。   </p><p>李渊——建唐 <br> 李世民——玄武门之变、贞观之治</p><p>太子 <strong> 李建成 </strong> 看他不顺眼，与四弟 <strong> 李元吉 </strong> 合谋想害他，最终李世民射杀李建成，名将尉迟恭射死李元吉。</p><p>魏征——水能载舟，亦能覆舟；兼听则明，偏信则暗</p><p>秦琼、尉迟恭——门神</p><p>程咬金——“莽汉”</p><p>几个“莽汉”形象：  三国张飞、唐朝程咬金、北宋末年李逵、南宋牛皋。</p><p><strong>薛仁贵 </strong>——灭高句丽、大破突厥、三箭定天山、脱帽退万敌、<strong> 瞒天过海</strong>  </p><p>玄奘：高僧。  西行印度取经。历史上玄奘取经不是李世民送走的，而是偷渡走的，取回的经书放在 <strong> 大雁塔。</strong>  </p><p>①玄奘是西行印度取经。<br>②僧一行：编纂《大衍历》，测量子午线长度。<br>③鉴真：东渡日本，六次东渡，终得成功。<br>④怀素：草书和尚，张旭草书。<br>⑤惠能：六祖惠能。<br>⑥佛印：宋朝人，苏轼的小伙伴，常作为干扰项。  </p><p>武则天——中国唯一正统女皇帝、 举行殿试、开创武举、无字碑 </p><p>狄仁杰——桃李满天下 </p><p>张柬之（得意门生）：在他的兵谏之下，武则天才将皇位重新传给李家后人。  </p><p>李隆基——开元盛世、安史之乱 马嵬坡兵变  </p><p>周宣王：周厉王之子；周厉王：“防民之口甚于防川”，后引发国人暴动。唐睿宗：李旦，李隆基的父亲。  </p><p>锦帆未落干戈起——隋炀帝  </p><p>萧绰：契丹萧太后。  </p><h4 id="宋元"><a href="# 宋元" class="headerlink" title="宋元"></a>宋元 </h4><p> 赵匡胤——建北宋、黄袍加身、杯酒释兵权  </p><p>赵光义——烛影斧声、开卷有益  </p><p><strong>赵普——半部《论语》 治天下</strong>  </p><p><strong>包拯——笑比河清</strong>  </p><p>范仲淹——庆历新政， 先天下之忧而忧、 后天下之乐而乐  </p><p>王安石——变法  </p><p>司马光——《资治通鉴》  </p><p><strong>赵构——建南宋</strong>  </p><p>赵构：北宋末年金兵南下，掳走宋徽宗和宋钦宗，史称“靖康之耻”，赵构建南宋  </p><p>岳飞——抗金、精忠报国、直捣黄龙  </p><p>岳母在岳飞后背刺下四个大字“尽忠报国”，后传闻成“精忠报国”  </p><p>文天祥——抗击蒙古、过零丁洋  </p><p>忽必烈：建大元。元朝不是由成吉思汗建立的，成吉思汗统一蒙古各部，其孙忽必烈建立大元。  </p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202401072055005.png" alt="image-20240107205529951"></p><h4 id="明"><a href="# 明" class="headerlink" title="明"></a>明 </h4><p> 朱元璋——建明  洪武之治</p><p>朱棣——靖难之役  </p><p>朱祁镇——土木堡之变、 夺门之变  </p><p><strong>解缙——永乐大典  主要功绩是主持编纂永乐大典，被西方称为“世界最大的百科全书”</strong>，收书规模超出清朝的四库全书，据统计全本达到 11095 册，可惜现在已失传，能找到的约 400 册。  </p><p>郑和：七下西洋 从明朝出发，最远横渡印度洋，到达过红海。  <strong>15 世纪初</strong></p><p>郑和的船队规模巅峰时一次有 200 多艘船，总计人数 2 万多人；哥伦布三艘船， 88 人 比哥伦布早</p><p><strong>于谦——北京保卫战 瓦剌 蒙古族</strong></p><p>张居正——改革、一条鞭法  </p><p>戚继光——抗倭  北御鞑靼  </p><p>郑成功——收复台湾 台湾被荷兰人占据  </p><p>吴三桂——冲冠一怒为红颜   </p><p>吴三桂推翻明朝 错误</p><h4 id="清"><a href="# 清" class="headerlink" title="清"></a>清 </h4><p> 努尔哈赤——建后金</p><p>皇太极——改大清  </p><p>康熙、雍正、乾隆——康乾盛世  </p><p>康熙：在位 61 年，历史上在位时间最长的皇帝。一生有很多成就：如擒鳌拜、平三藩、收台湾、征噶尔丹、保卫雅克萨等。  </p><p>雍正：以勤政而著名。常考点：设立军机处， 标志君主专制达到顶峰。  </p><p>乾隆：很高寿，活到 89 岁。主要成就：打大小金川、平定西藏、打缅甸、打越南、平准噶尔等。不好的地方：大兴文字狱、六下江南，耗费很多钱粮。后期走下坡路，给后面留下烂摊子，但总体上称为“康乾盛世” 。</p><p><strong>纪昀——《四库全书》    编修于乾隆时期 ，在编纂过程中纪晓岚贡献突出  ，分经、史、子、集四目</strong>  </p><p>因为大兴文字狱，所以修少毁多。《阅微草堂笔记》： 纪昀编纂。  </p><p>林则徐——虎门销烟  </p><p>曾国藩——剿灭太平天国  洋务运动中开创的企业主要是 <strong> 安庆内军械所。</strong>  </p><p>左宗棠——收复新疆  他抬棺出征，经过艰苦战斗，历时 1 年收复新疆。  洋务运动中办的企业是福州船政局。  </p><p>张之洞——中学为体、西学为用 兴办企业：<strong>汉阳铁厂。</strong>  </p><p>李鸿章——大清王朝的“裱糊匠” 兴办企业：<strong>轮船招商局、江南制造总局</strong>  </p><p>康有为、梁启超——公车上书、戊戌变法  </p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202401072115437.png" alt="image-20240107211552384"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202401072101288.png" alt="image-20240107210111237"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202401072048787.png" alt="image-20240107204849729"></p><h3 id="古代史书"><a href="# 古代史书" class="headerlink" title="古代史书"></a>古代史书</h3><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202401071614359.png" alt="image-20240107161404296"></p><p>春秋三传： 《左传》左丘明  《公羊传》公羊高  《谷梁传》  谷梁赤</p><p>《春秋》第一部编年体史书    《左传》第一部叙事详细的编年体史书    《资治通鉴》  第一部编年体通史  </p><p>《国语》  最早的一部国别体著作  </p><p>《史记》  第一部纪传体通史  </p><p>《汉书》  第一部纪传体断代史 东汉班固    </p><h3 id="古代变法（重要改革）"><a href="# 古代变法（重要改革）" class="headerlink" title="古代变法（重要改革）"></a>古代变法（重要改革）</h3><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202401032221356.png" alt="image-20240103222110244"></p><p>管仲改革(春秋) 相地而衰征、山泽各致其时</p><p>土地好坏征收赋税 伐木 适当时间 禁渔期</p><p>李悝（kuī）变法(战国) 尽地力、平籴（dí）法 指官府在丰年以平价收购农民余粮，以备荒年出售 战略储备粮食</p><p>著《法经》 系统地封建成文法典</p><p>商鞅变法(战国 - 秦孝公) </p><p>实行军功爵制，打击世卿世禄制</p><p>编制户籍，实行什伍连坐法（<strong>什伍之中，一家有罪，其余各家均应告发，否则将连同惩罚</strong>，户籍以五家为伍，十家为什）</p><p>重农抑商，奖励耕织</p><p>废井田、开阡陌，实行土地私有制</p><p>推行县制</p><p>统一度量衡</p><p>赵武灵王改革战国 胡服骑射短衣窄袖</p><p>北魏孝文帝改革 (北魏)</p><p>迁都洛阳（（平城）大同 -&gt; 洛阳）<br>改革鲜卑旧俗，实行汉化 <br> 实行均田制（无主土地 人口 小农）</p><p>范仲淹庆历新政(北宋) 宋仁宗</p><p>王安石变法 (北宋) 宋神宗 <strong> 熙宁变法 积贫积弱</strong></p><p>富国之法: 均输法，青苗法，方田均税法，农田水利法，市易法，募役法</p><p>强兵之法: 将兵法，置军器监，保甲法，保马法</p><p>取士之法: 改革科举制度，整顿太学，惟才用人</p><p>张居正改革(明朝)</p><p>实行“一条鞭法”</p><p>田赋、徭役、杂征 合并一条</p><h3 id="古代著作"><a href="# 古代著作" class="headerlink" title="古代著作"></a>古代著作</h3><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202401071729885.png" alt="image-20240107172939779"></p><p>《墨经》：战国时期，作者是墨子及其弟子，里面写了很多物理学原理，比如力学、光学等。最有名的是“光学八条”和小孔成像。  </p><p>《甘石星经》： 成书于战国， 作者是甘德和石申，世界上现存最早的天文著作之一。  </p><p>《周髀算经》：西汉，中国最古老的天文学和数学著作，也称为《天文算学》，<strong>记载了勾股定理（常考） 。</strong>  </p><p>《九章算术》：东汉，作者不详，标志中国古代数学形成了完整的体系。  </p><p>《齐民要术》：北魏贾思勰，“齐民”是平民之意，中国现存最早的一部完整农书。西汉《氾胜之书》是最早的农书，但是没有完整版本存在。  </p><p>《水经注》： 北魏郦道元，给水经做注解，古代中国地理名著。  </p><p>《梦溪笔谈》：沈括， 是一本笔记体， 中国科学史上的里程碑。  </p><p>《营造法式》：北宋李诫，当时的首席建筑师，建筑学著作。  </p><p>《农政全书》：徐光启，农书，体现农政的思想，即将农学上升到治国理政的高度。  </p><p>《天工开物》：宋应星，中国 17 世纪的工艺百科全书。  （纺织染色，制盐制糖，砖瓦，陶瓷，车船，金属，兵器等等）</p><p><strong>固若金汤  出自《汉书》</strong>  </p><p><strong>殃及池鱼  出自  《吕氏春秋》</strong>  </p><p><strong>高阳酒徒  出自《史记》</strong>  </p><p>东汉张衡发明浑天仪；元朝郭守敬著有《授时历》  </p><p>唐朝画圣吴道子， 代表作《送子天王图》；东晋顾恺之， 传世名作《洛神赋图》和《女史箴图》。  </p><h3 id="古代盛世"><a href="# 古代盛世" class="headerlink" title="古代盛世"></a>古代盛世</h3><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202401072015442.png" alt="image-20240107201555345"></p><p>商朝：武丁盛世。商朝开始政局不稳，盘庚迁殷之后才稳定。后来政权传到盘庚的侄子武丁（在位 59 年）手中，他统治时期殷商达到鼎盛时期，称为武丁盛世  </p><p>西周：成康之治，在周公辅佐之下，周公东征扫平叛乱、治礼乐，开创成康之治，是西周最强盛的阶段。  <a href="https://zh.wikipedia.org/wiki/%E5%91%A8%E6%88%90%E7%8E%8B">周成王 </a>、<a href="https://zh.wikipedia.org/wiki/%E5%91%A8%E5%BA%B7%E7%8E%8B"> 周康王 </a> 的治世</p><p>西汉：  文景之治：文帝刘恒，景帝刘启，这时期采取黄老之术治国，轻徭薄赋、与民休息。  </p><p>汉武盛世：刘彻，有北击匈奴、盐铁官营、独尊儒术、采纳推恩令等  </p><p>昭宣中兴：汉昭帝刘弗陵，宣帝刘洵（ 他的历史评价在帝王中非常高）。  </p><p>东汉：<br>（1）光武中兴：汉光武帝刘秀，开国皇帝。<br>（2）明章之治：东汉汉明帝刘庄（求佛典：去西边求佛典，回来建立第一个官办寺庙——白马寺，被称为中国第一古刹），汉章帝刘炟。  </p><p>北魏：孝文中兴。孝文帝拓跋宏进行汉化改革，史称孝文中兴。  </p><p>隋：开皇之治，隋文帝杨坚开创。  </p><p>唐：<br>（1）贞观之治：唐太宗李世民 。</p><p>（2）永徽之治：唐高宗李治。李治看起来怕武则天，但是很有作为，他统 <br> 治时期大唐版图达到最大化。<br>（3）武周之治：武则天。<br>（4）开元盛世：唐玄宗李隆基。</p><p>北宋：<br>（1）建隆之治：宋太祖赵匡胤统治时期。<br>（2）咸平之治：宋真宗赵恒。重要考点：澶渊之盟。<br>（3）仁宗盛世：宋仁宗赵祯，在位 42 年，北宋达到全盛阶段，他统治时期名臣辈出，比如范仲淹、包拯、欧阳修等。小故事：他死后消息传到辽国，辽国国君痛哭，说要建一座衣冠冢，以寄托哀思，说明仁宗的名声特别好。  </p><p>明：<br>（1）洪武之治：朱元璋。<br>（2）永乐盛世：永乐大帝即明成祖朱棣。<br>（3）仁宣之治：明仁宗朱高炽，明宣宗朱瞻基。  </p><p>清：康乾盛世，即康熙、雍正、乾隆。  </p><h3 id="少数民族政权"><a href="# 少数民族政权" class="headerlink" title="少数民族政权"></a>少数民族政权</h3><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202401072106019.png" alt="image-20240107210605955"></p><p>前秦：氐族，苻健创立。苻坚（注意与创始人进行区分）：淝水之战。  </p><p>北魏：鲜卑族，创始人拓跋珪，“珪”是美玉之意。拓跋宏进行汉化改革 。</p><p>辽：契丹族，创始人耶律阿保机。  </p><p>金（辽被金取代）：女真族，创始人完颜阿骨打。  </p><p>大理：白族，创始人段思平。电视剧《天龙八部》里有体现。  </p><p>吐蕃：藏族，创始人松赞干布。  </p><p>西夏：党项族，创始人李元昊。  </p><p>元：蒙古族，创始人忽必烈。  </p><p>后金：女真族，创始人努尔哈赤。  </p><p>清：满族，创始人皇太极。努尔哈赤建后金，其儿子皇太极改女真族名为满族，改后金为清，满清从皇太极开始。入关后第一个皇帝是顺治帝。  </p><h2 id="诸子百家"><a href="# 诸子百家" class="headerlink" title="诸子百家"></a>诸子百家 </h2><h3 id="一、儒家"><a href="# 一、儒家" class="headerlink" title="一、儒家"></a> 一、儒家</h3><p>（一）孔子(春秋 至圣，万世师表)<br>1. 思想<br>（1）礼——“克（约束）己复礼”、“君君、臣臣、父父、子子” 等级有序<br>（2）仁——“爱人（人）”、“因民之所利而利之”（官）<br>（3）中庸（不偏不倚，折中调和）——“过犹不及”、“和（和谐）而不同（苟同）”<br>（4）德——“为政以德，譬如北辰居其所而众星共之”  （众星拱北）</p><p>2. 教育 <br>（1）对象——有教无类（不问出身）；兴办私学（官学）<br>（2）态度——“不耻下问”、“知之为知之，不知为不知，是知也”<br>（3）方法——“学（勤学多问 韦编三绝）、思（思考）、习（复习）、行（实践）”；循循善诱；因材施教；不愤不启、不悱不发；举一反三<br>（4）内容——《诗》《书》《礼》《乐》（失传）《易》《春秋》（<strong> 五经 </strong>）3. 著作<br>《论语》 ——记录孔子及其弟子言行的一部书，共 20 篇。语录体为主，孔子弟子、再传弟子编著。<br> 宋代 <strong> 朱熹 </strong> 将它与《大学》《中庸》《孟子》合称 <strong> 四书</strong>。  </p><p>（二）孟子（战国 亚圣 孟母三迁）（孔 73，孟 84）<br>1. 思想<br>（1）仁政（统治者）——“威天下不以兵革之利”、“乐以天下，忧以天下”、“生于忧患，死于安乐”、“天时不如地利， 地利不如人和”<br>（2）义——道义（君 仁政 臣 忠心不二），“得道者多助”、“富贵不能淫（骄奢），贫贱不能移（改移），威武不能屈（屈服）”<br>（3）民贵君轻——“民为贵，社稷次之，君为轻”<br>（4）性善论——“恻隐之心，人皆有之”<br>（5）以德服人——“以德服人者，中心悦诚服也<br>2. 著作  《孟子》 ——作者：孟子及其弟子。  </p><p>（三）荀子（学生 李斯 韩非）<br>1. 思想<br>（1）性恶论——礼法并用。<br>（2）“君者，舟也；庶人者，水也。水则载舟，水则覆舟”。（魏征）<br>（3）先义后利——“先义而后利者荣，先利而后义者辱”。<br>（4）“天行有常”、“制天命而用之”。<br>2. 著作<br>《荀子》 ——作者：荀子及其弟子。  </p><p>（四）其他<br>1. 董仲舒（天人三策）——“罢黜百家，独尊儒术”；“大一统（政治 思想）”；天人感应<br>2. 朱熹（四书集注）——程（程颢 程颐）朱（朱熹）理学，“存天理（三纲五常 君 父 夫 仁义礼智信），灭人欲”（格物致知）<br>3. 王阳明（王守仁 大学问 心无外物）——陆（陆九渊 吾心即是宇宙）王心学，“知行合一”  明代</p><p>颜氏家训 颜之推 南北朝</p><p>子夏 学而优则仕  </p><p>以德为国者，甘如饴蜜，固于胶漆，是以圣勉而崇本而不敢失也  董仲舒</p><p>君子以德，小人以力，力者德之役也  荀子</p><p>以德服人者，中心悦而诚服也   孟子</p><p>独与天地精神相往来   庄子</p><p>虽千万人，吾往矣——孟子  </p><p>知其不可而为之——孔子  </p><p>摩顶放踵利天下——墨子  </p><h3 id="二、道家"><a href="# 二、道家" class="headerlink" title="二、道家"></a>二、道家 </h3><p> 道家 思想 老子（太上老君）</p><p>道教 宗教 张道陵 五斗米</p><p>（一）老子（李耳 聃 春秋）<br>1. 思想<br>（1）“道”是世界本原（道生一，一生二，二生三，三生万物）<br>（2）朴素的辩证法——祸兮福所倚（依），福兮祸所伏（隐）（有无相生，难易相成，长短相形）<br>（3）无为而治——“我无为，而民自化”、“上善若水”<br>（4）“小国寡民”<br>2. 著作<br>《道德经》 ——作者：老子（中国首部完整的哲学著作）<br>（二）庄子（战国）<br>1. 思想<br>（1）无为<br>（2）齐物论（没有差别）<br>（3）天人合一——“万物与我为一”  （同为一体）制度 藩篱</p><p>（ 4）“逍遥”的人生态度。<br>2. 著作 <br>《庄子》，亦称《南华经》（南华真人） ——作者：庄周及其后学（庄周梦蝶 知鱼之乐 庖丁解牛）<br>（三）魏晋玄学<br> 玄学又称新道家，是对《老子》《庄子》和《周易》（<strong>三玄</strong>）的研究和解说，产生于魏晋。玄学是中国魏晋时期到宋朝中叶之间出现的一种崇尚老庄的思潮。  </p><p>吾生也有涯，而知也无涯——庄子  </p><p>我思故我在——笛卡尔（主观唯心）  </p><p>他人即地狱——萨特  （过人依赖他人）</p><p>A. 心学——明代<br>B. 玄学——魏晋<br>C. 理学——宋代  </p><p>D. 儒学——春秋  </p><h3 id="三、法家"><a href="# 三、法家" class="headerlink" title="三、法家"></a>三、法家</h3><p>（一）商鞅（战国 卫国 商君）<br>“治世不一道，便国不法古”<br>（二）韩非（战国）<br>“事在四方，要在中央”（中央集权）<br>“以法为教”、“刑过不避大臣，赏善不遗匹夫”（人人平等）<br>“法”“术”“势”结合  （律商鞅 手段申不害 地位慎 君主专制）</p><h3 id="四、墨家"><a href="# 四、墨家" class="headerlink" title="四、墨家"></a>四、墨家 </h3><p> 墨子，名翟。（战国 平民）<br>1. 思想 <br> 兼爱（博爱）、非攻（不打仗）、节用、节葬、尚贤、尚同（上下一心）、非命（命定）、非乐等。<br>2. 著作<br>《墨子》（《墨经》光学八条 最早 小孔成像） ——作者：墨子和弟子。  </p><h3 id="五、兵家"><a href="# 五、兵家" class="headerlink" title="五、兵家"></a>五、兵家 </h3><p> 孙武：兵圣，《孙子兵法》（最早军事著作 春秋 三十六计（不是一回事，后人对军事的总结，成立于明清时期））<br>孙膑：《孙膑兵法》（战国 围魏救赵 田忌赛马）  </p><h3 id="六、杂家"><a href="# 六、杂家" class="headerlink" title="六、杂家"></a>六、杂家 </h3><p>“兼儒墨，合名法”<br> 吕不韦：《吕氏春秋》  （一字千金）</p><p>A. 孔子：“性相近也，习相远也”<br>B. 孟子：“尽信书，则不如无书”<br>C. 墨子：“道之所存，师之所存”<br>D. 荀子：“骐骥一跃，不能十步；驽马十驾，功在不舍”  </p><p>墨子：“道之所存，师之所存 错  韩愈 师说</p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202401101121494.png" alt="image-20240110112144377"></p><p>诸子百家要点总结<br>1. 儒家——仁、礼、德、义、教学、求知<br>2. 道家——道、辩证、无为、自然<br>3. 法家——法治、变法、君主集权<br>4. 墨家——平民、节俭、大爱、技术<br>5. 兵家——打赢就行<br>6. 杂家——啥都研究  </p><h2 id="中国历史事件排序"><a href="# 中国历史事件排序" class="headerlink" title="中国历史事件排序"></a>中国历史事件排序 </h2><p> 一、夏 <br> 禹传启，家天下→划分九州→桀行暴政而亡</p><p>二、商 <br> 商汤灭夏（鸣条之战）→盘庚迁殷→武丁盛世→纣暴政亡国</p><p>三、西周 <br> 武王伐纣（牧野之战）→实行分封制→国人暴动→幽王烽火戏诸侯→犬戎攻破镐京→平王东迁洛邑</p><p><strong>周公旦： 典故周公吐哺、天下归心。</strong> 周武王打下天下后过于劳累，两年后死亡， 儿子周成王继位，周公辅佐周成王， 在辅佐过程中如果听见有人求见，食物都会来不及咽下去，吐出来后立即接见求见的人， 所以周公吐哺说明礼贤下士、 求才心切</p><p>道路以目   防民之口甚于防川  </p><p>四、春秋战国 <br> 春秋五霸（齐桓公、晋文公、楚庄王、吴王阖闾和越王勾践）</p><p><strong>和范蠡相关的成语有鸟尽弓藏和兔死狗烹。</strong>  </p><p>战国七雄（商鞅变法、桂陵之战、马陵之战、长平之战、荆轲刺秦）</p><p><strong>桂陵之战、马陵之战：主要人物是孙膑和庞涓。 桂陵之战的典故是围魏救赵（孙膑使的计策）， 马陵之战的典故是减灶诱敌， 孙庞二人的斗智以孙膑的完胜而告终</strong></p><p>百家争鸣（儒、道、法、墨、兵、杂）</p><p>名家：名（概念）实（事物） 惠施（子非鱼）公孙龙（白马非马）</p><p>阴阳：五行</p><p>农：农业</p><p>五、秦 <br> 秦灭六国→郡县制、统一度量衡、车同轨、书同文（秦小篆）、焚书坑儒、北征匈奴、南平百越、修筑长城→昏庸腐朽的秦二世→陈胜、吴广起义→刘邦、项羽起义→刘邦灭秦    </p><p>四大爱情传说——孟姜女哭长城、牛郎织女、梁祝、 白蛇传。</p><p>六、汉 <br> 楚汉之争→垓下之战→白登之围→文景之治→七国之乱→汉武帝击匈奴→<br>巫蛊之祸→昭君出塞→王莽改制，绿林赤眉起义→刘秀称帝→光武中兴→黄巾大起义 <br> 七、三国两晋南北朝 <br> 军阀割据混战→官渡之战→赤壁之战→魏、蜀、吴三国鼎立→夷陵之战→魏灭蜀→司马炎篡魏，建立晋国→晋灭吴→八王之乱→五胡乱华，匈奴灭西晋→司马睿称帝，史称东晋→淝水之战→南北朝对峙（北魏孝文帝改革）</p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202401101527918.png" alt="image-20240110152738849"></p><p>三国两晋南北朝时期的政权更迭：<br>（ 1）三国时期指魏蜀吴时期，后来司马家族夺取了曹魏政权， 建立了西晋。<br>西晋后来被少数民族匈奴灭亡了， 一部分贵族在南方建立了东晋，北方的匈奴等 <br> 五个主要的少数民族内迁，建立了大小十六个政权， 史称 <strong> 五胡乱华 </strong>。<br>（ 2）在南方，东晋大将刘裕夺取政权建立宋， 此后南方经历宋齐梁陈四个<br> 朝代， 合称南朝。<br>（ 3）在北方，十六国之后， 又先后经历了北魏、 东魏、西魏、 北齐、 北周 <br> 等政权， 这段时期称为北朝。 南朝和北朝长期对峙的局面合称南北朝。 直到北周 <br> 外戚杨坚代周称帝建立隋朝后，中国又进入统一的时代。</p><p>  魏、蜀、吴三国鼎立：<br>（ 1）曹丕称帝建立魏国，都城在洛阳。<br>（ 2）刘备称帝建立蜀汉政权，都城在成都。<br>（ 3）孙权称帝建立东吴， 都城在建邺（今南京）。  </p><p>5. 夷陵之战：刘备称帝 3 个月后率兵进攻东吴， 因为关羽败走麦城，被东吴 <br> 将领打败了， 所以刘备要给关羽报仇， 发动了夷陵之战。 夷陵之战也叫猇亭之战，<br>刘备气势汹汹进攻东吴， 东吴的大将陆逊以逸待劳， 将刘备从正月耗到六月， 天 <br> 热了后刘备将军营设在深山密林里， 还用木栅栏围了营寨， 陆逊看到后顺风放火，<br>这就是历史上著名的火烧连营。 这一战几乎让刘备全军覆没，最后逃到白帝城，<br>就有了白帝城托孤。  </p><p>淝水之战：西晋灭亡后，少数民族不断内迁， 在北方先后建立了 16 个国 <br> 家， 其中氐族建立了前秦政权， 后来在其中一任首领苻坚的带领下快速强大起来，<br>统一了整个黄河流域， 至此北方剩下前秦，前秦和东晋之间发生了著名的淝水之 <br> 战。 淝水之战的交战双方是前秦（首领苻坚） 和东晋（谢安坐镇后方是总指挥，<br>前线是谢玄）， 最终东晋以少胜多打败前秦。 常考典故风声鹤唳、草木皆兵和投 <br> 鞭断流。  </p><p>八、隋 <br> 杨坚称帝→开皇之治→炀帝暴政，科举确立，兴修运河→农民起义→炀帝被弑</p><p>九、唐 <br> 李渊自立为帝，建唐朝→玄武门之变→贞观之治→永徽之治→武则天建周→开元盛世→安史之乱→黄巢起义→亡于藩镇</p><p>贞观遗风：武则天虽为女皇帝，但治理国家有一套政策， 一点都没有拖大唐的后腿， 其统治时期称为贞观遗风（延续了贞观时期社会前进的步伐）。武则天做得最酷的一件事情可能是其坟前的无字碑，其他的皇帝可能想要写无数的丰功伟绩， 但武则天却选择了沉默，将是非功过留给后人说  </p><p>唐朝后期政局混乱， 各个藩镇之间战乱不断，因此爆发了农民起义， 比如 <br> 黄巢起义。<br>（1）黄巢“高考” 未考上，于是带领大家起兵造反， 即黄巢起义（发生于唐朝末年）。<br>（2） 考试的时候也可能考查黄巢所写的诗句，常考“冲天香阵透长安， 满城尽带黄金甲”，该句诗描写的是菊花。黄巢与陶渊明一样都很爱写菊花， 但黄巢笔下的菊花带有杀气（黄金甲），该句诗出自《不第后赋菊》。 “不第” 即考科举未中，整个社会黑暗、腐败， 对李唐王朝非常不满， 于是创作该诗（也可以说是一首反诗）  </p><p>十、宋 <br> 赵匡胤陈桥兵变→北宋建立→杯酒释兵权→烛影斧声→澶渊之盟→王安石变法→靖康之难→康王赵构继承皇位，史称南宋→岳飞抗金→文天祥抗击蒙古→南宋灭亡</p><p>北宋的都城： 东京（ 今河南开封）， 别称“汴州”“汴梁” 。  </p><p>烛影斧声：讲述的是赵光义（ 赵匡胤的弟弟）。 赵匡胤的死因成谜， 某天赵光义去看望其哥哥，下人远远看到宫内烛影撩动，仿佛赵光义在离座退避，不一会儿又听到有斧子敲地的声音， 等第二天的时候发现赵匡胤已经去世， 是一个千古悬案。赵匡胤去世后， 其弟弟赵光义成为皇帝， 即宋太宗。  </p><p>庆历新政：宋仁宗时期（ 庆历年间）由范仲淹推行， 最终失败。<br>（ 2） 王安石变法：<br>①宋神宗时期任用王安石进行变法， 因发生在宋神宗熙宁年间， 故王安石变法又称熙宁变法。<br>②结果： 失败。 一方面可能是因为用人不当， 出现了危害百姓的现象； 另一方面是变法得罪了很多人，保守派极力的反对和阻挠， 等保守派登上台后（ 比如司马光）王安石变法被废止。  </p><p>十一、元 <br> 蒙古国创始人铁木真→忽必烈建立元朝→设宣政院，西藏正式成为中国的行政区域→在澎湖设巡检司，正式在台湾设立行政机构→元末农民起义→朱元璋推翻元朝</p><p>十二、明 <br> 朱元璋建明朝→靖难之役，朱棣迁都北京→郑和七下西洋→仁宣之治→土木堡之变→戚继光抗倭→张居正改革→李自成起义，崇祯自缢煤山</p><p>崇祯帝朱由检，他并不像其他的亡国之君一样残暴， 只是有点疑心， 但时运不济， 明朝已经走到末路， 靠其一个人也无力回天 。</p><p>十三、清 <br> 女真族努尔哈赤建立后金→皇太极改国号大清→吴三桂引清入关→顺治入关→郑成功收复台湾→康乾盛世→鸦片战争→太平天国起义→第二次鸦片战争→洋务运动→甲午战争→戊戌变法→义和团运动→八国联军侵华→清末立宪→辛亥革命        </p><p>关键词“改革方案”“发展资本主义”“未能实施” ，对应《<strong>资政新篇 </strong>》（<strong> 洪仁玕所提 </strong>），是最早的带有资本主义色彩的改革方案， 但并未实行（因为<strong> 太平天国运动 </strong> 是农民阶级的运动， 农民对资本主义不感兴趣）。A 项错误： 《海国图志》 的作者是魏源， 该书介绍了西方的历史和地理， 并且阐述了“师夷长技以制夷” 的思想， 即要学习西方的先进技术， 从而抵制外国人对我们的侵略。    </p><table><thead><tr><th>8.（2018—陕西）下列历史事件中，发生在黄河流域的有（ ）。</th><th></th></tr></thead><tbody><tr><td>A. 商鞅变法  C. 魏孝文帝迁都<br />B. 王莽新政 D. 赤壁之战</td><td></td></tr></tbody></table><h2 id="笔墨丹青"><a href="# 笔墨丹青" class="headerlink" title="笔墨丹青"></a>笔墨丹青 </h2><h3 id="书法专题"><a href="# 书法专题" class="headerlink" title="书法专题"></a> 书法专题 </h3><p> 一、先秦 <br>1. 甲骨文<br> 甲骨文是指商朝占卜记事时契刻在龟甲、兽骨上的文字。这种文字是我国书法史上有实证的最古老且相对成熟的文字。<br>2. 金文 <br> 比甲骨文稍晚出现的是金文，金文即为铸刻在青铜器上的铭文。</p><p>二、秦朝 <br> 秦始皇统一六国后，由宰相李斯负责，在大篆的基础. 上进行简化，创制了统一的书写形式——小篆。</p><p>三、汉朝 <br>1. 隶书<br> 隶书是在篆书基础上，为适应书写便捷的需要产生的字体。<br>特点： “蚕头燕尾”、“一波三折”<br>代表人物：蔡邕——“飞白书”<br>2. 草书 <br> 草书有章草、今草之分。<br>（1） 章草是隶书的快写体，点画较简略，书写便捷。<br>（2） 今草由东汉的张芝创立。</p><p>四、魏晋 <br>1. 楷书<br> 楷书即“真书”，是由隶书演变而逐渐形成的一种端庄、工整的字体，大约 <br> 在东汉末年形成，到魏晋时代逐渐成熟。<br>特点：横平竖直，结构紧凑。  </p>]]></content>
    
    
    <summary type="html">本篇博客记录常识笔记。</summary>
    
    
    
    <category term="knowledge" scheme="http://example.com/categories/knowledge/"/>
    
    
    <category term="knowledge" scheme="http://example.com/tags/knowledge/"/>
    
  </entry>
  
  <entry>
    <title>每日书籍</title>
    <link href="http://example.com/2024/02/24/Thinking/Book/"/>
    <id>http://example.com/2024/02/24/Thinking/Book/</id>
    <published>2024-02-24T00:00:00.000Z</published>
    <updated>2024-03-07T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>本人很懒，不多介绍</p><span id="more"></span><h2 id="小狗钱钱"><a href="# 小狗钱钱" class="headerlink" title="小狗钱钱"></a>小狗钱钱 </h2><h3 id="前言"><a href="# 前言" class="headerlink" title="前言"></a> 前言 </h3><p><strong> 关键词摘取：</strong></p><p>结束错误</p><p>为什么要讲这样一个故事</p><p>故事形式并非无懈可击</p><p>出乎意料的反响</p><p>故事产生距离感</p><p>明确方向十分必要</p><p>所有的原则自古有之</p><p>有益和必要的知识</p><p>肤浅的危险</p><p>财富法则</p><p>一切皆有可能</p><p>忽视是一种认输</p><p>什么都无法阻挡你</p><p><strong>有触动的话：</strong></p><p>所有人都希望自己变得富有一些，只是有些人的这一愿望更为强烈，而有些人却假装自己满足于现在的生活。事实上，大多数人都希望自己更幸福、更成功，也想拥有更多的钱。</p><p>认为我们必须忍受拮据的生活，甚至认为这样才是高尚的—这种想法是人类犯下的最重大的错误之一。</p><p>忽视是一种认输</p><p>并非困难使我们放弃，而是因为我们放弃，才显得如此困难。</p><h3 id="第一章 - 白色的拉布拉多犬"><a href="# 第一章 - 白色的拉布拉多犬" class="headerlink" title="第一章  白色的拉布拉多犬"></a>第一章  白色的拉布拉多犬 </h3><p> 想出 10 个你想变得富有的原因，也就是你的 10 个愿望，然后用笔写下来。</p><p>1、我想给自己买个苹果手机</p><p>2、我想给宝子买个键盘</p><p>3、我想给家里买个洗衣机</p><p>4、我想给妹妹弟弟买个平板</p><p>5、我想去做个体检</p><p>6、我想去旅游几次</p><p>7、我想有自己的小房子</p><p>8、我想有自己的一套厨具</p><p>9、我想有自己的一套化妆品</p><p>10、我想有自己风格的几套衣服</p><p>11、我想有一份舒服的工作</p><p>12、我想给宝子买个饮水机</p><p>吃穿住行</p><p>样样俱全</p><p>哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈</p><p><strong>有触动的话：</strong></p><p>老子说过：‘天下难事，必作于易；天下大事，必作于细。’</p><h3 id="第二章 - 梦想储蓄罐和梦想相册"><a href="# 第二章 - 梦想储蓄罐和梦想相册" class="headerlink" title="第二章  梦想储蓄罐和梦想相册"></a>第二章  梦想储蓄罐和梦想相册 </h3><p> 还是要请你再仔细看一看你的单子，并且把最重要的 3 项圈出来。</p><p>1、我想给自己买个苹果手机</p><p>7、我想有自己的小房子</p><p>11、我想有一份舒服的工作</p><p>第一，我建议你拿一本相册作为你的梦想相册。收集一些与自己的愿望有关的照片，把它们贴在相册里。我们要通过图片来思考。”</p><p>第二件你可以做的事，就是每天看几遍相册，然后想象着，做梦。人们把这种行为称作‘视觉化’。成功的人之所以成功，就是因为他们一直梦想着自己成功的那一天，不停地想象着自己实现了理想时的情形。</p><p>第三件事就是准备一个梦想储蓄罐。只有当你心中有了强烈的渴望，你才会去寻觅机会。而当你想象的时候，强烈的渴望就产生了。</p><p>（我马上联想到我的克里丝特阿姨。她总是觉得要做的事情太多，无法应付，<strong>她的神经快要崩溃了。结果就是她连一件小事都做不成。</strong>我也想到了爸爸。爸爸的脑子里装的全是“<strong>如何让我们渡过眼前的难关 </strong>”这样的问题，而他的<strong> 这种想法却在某种程度上使情况越来越糟。</strong>）</p><p><strong>有触动的话：</strong></p><p>好奇是好的，但是绝不能让好奇阻碍你做事。太多的人做事犹豫不决，就是因为他们觉得没有完全弄懂这件事。真正付诸实践要比纯粹的思考有用多了。</p><p>‘尝试’纯粹是一种借口，你还没有做，就已经给自己想好了退路。不能试验，你只有两个选择<strong>—做或者不做。</strong>”</p><p>学习就是认识新观念和新想法的过程。假如人们始终以同一种思维方式来考虑问题的话，那么始终只会得到同样的结果。</p><p>如果你的零花钱是现在的 10 倍的话，你的问题只会变得更加严重。因为我们的支出永远是随着我们的收入而增长的。我们首先必须学会 <strong> 量入为出</strong>，只有这样，我们才有能力获得更多的钱。</p><p>有一只海鸥曾经对我说过：‘在你展翅飞翔之前，你就必须相信自己能到达目的地。</p><h3 id="第三章 - 达瑞，一个很会挣钱的男孩"><a href="# 第三章 - 达瑞，一个很会挣钱的男孩" class="headerlink" title="第三章  达瑞，一个很会挣钱的男孩"></a>第三章  达瑞，一个很会挣钱的男孩 </h3><p> 准备一个本子，给它取名叫‘成功日记’，然后把所有做成功的事情记录进去。你最好每天都做这件事，每次都写至少 5 条你的个人成果，任何小事都可以。开始的时候也许你觉得不太容易，可能会问自己，这件或那件事情是否真的可以算作成果。在这种情况下，你的回答应该是肯定的。过于自信比不够自信要好得多。</p><p><strong>有触动的话：</strong></p><p>你是否能挣到钱，最关键的并不是你有没有好点子，也不是你有多聪明，而是你的 <strong> 自信程度。</strong></p><p>你的自信程度决定了你是否相信自己的能力，是否相信你自己。假如你根本不相信你能做到的话，那么你就根本不会动手去做，而假如你不开始去做，那么你就什么也得不到。</p><p>商人给了他两个重要的建议：第一，<strong>为别人解决一个难题，那么你就能赚到许多钱 </strong>；第二，<strong> 把精力集中在你知道的、能做的和拥有的东西上。</strong></p><h3 id="第四章 - 堂兄的挣钱之道"><a href="# 第四章 - 堂兄的挣钱之道" class="headerlink" title="第四章  堂兄的挣钱之道"></a>第四章  堂兄的挣钱之道 </h3><p> 不去 <strong> 寻找机会 </strong> 的人，最多不过是在走运的时候捡到天上掉下来的馅饼。告诉你吧，我之所以能挣到这么多的钱，那是因为我自己有一家公司。</p><p>第一，无论在什么时候都不能把希望只寄托在一份工作上，它持续的时间不会像你设想的那么长，所以你要立即寻找 <strong> 另一份替代的工作</strong>。</p><p>第二，你肯定会遇到一些困难，情况顺利的时候，人人都能挣到钱。只有在 <strong> 逆境 </strong> 中，一切才能见分晓。</p><h3 id="第五章 - 钱钱以前的主人"><a href="# 第五章 - 钱钱以前的主人" class="headerlink" title="第五章  钱钱以前的主人"></a>第五章  钱钱以前的主人 </h3><p> 困难总是在不断地出现。尽管如此，你每天还是要不间断地去做对你的未来意义重大的事情。你为此花费的时间不会超过 10 分钟，但是就是这 10 分钟会让一切变得不同。大多数人总是在现有的水平上停滞不前，就是因为他们没有 <strong> 拿出这 10 分钟 </strong>。他们总是期望情况能向有利于自己的方向转变，但是他们忽视了一点，那就是他们首先必须<strong> 改变自己</strong>。</p><p>这 10 分钟就是你用来改变自己的最好机会。你最好现在大声地发誓，从现在开始会不间断地记录你的成功日记，并且不间断地设想你的未来。而且不论在什么情况下，每天都坚持这么做。</p><p>你决定做一件事情的时候，你必须在 <strong>72 小时</strong> 之内完成，否则你很可能永远不会再做了。</p><p><strong>有触动的话：</strong></p><p>他们总是有那么多紧急的事情要做，以至于没有时间来关注重要的事情。</p><p>我要告诉你 3 件很重要的事情。首先，在遇到困难的时候，仍然要坚持自己的想法。一切正常的时候，每个人都能做到这一点。只有当真正的困难出现时才能见分晓。只有少数人能坚定不移地贯彻自己的计划。那些非常成功的人，甚至有能力在他们最困难的时候作出最杰出的表现。”</p><h3 id="第六章 - 爸爸妈妈犯下的错误"><a href="# 第六章 - 爸爸妈妈犯下的错误" class="headerlink" title="第六章  爸爸妈妈犯下的错误"></a>第六章  爸爸妈妈犯下的错误 </h3><p> 第一，欠债的人应当毁掉所有的信用卡。</p><p>第二个忠告是，应当尽可能少地偿还贷款—也就是大人们说的分期付款。</p><p>第三个忠告是针对消费贷款的。消费贷款是与住房无关的贷款。假如人们为了购置新的汽车、家具、电视机或其他用于生活的商品而贷款，就是消费贷款。</p><p>最后一个忠告，债务人都应该在自己的钱包里贴一张纸条，上面写着‘这真的有必要吗’。</p><p><strong>有触动的话：</strong></p><p>其实只有做自己喜欢的事情的人，才能真正获得成功。</p><h3 id="第七章 - 在金先生家"><a href="# 第七章 - 在金先生家" class="headerlink" title="第七章  在金先生家"></a>第七章  在金先生家 </h3><p> 大多数人生来并没有‘鹅’。这就是说，他们的钱不足以让他们 <strong> 依靠利息 </strong> 来生活。</p><p>这完全要根据你的目标来决定。如果你总是把 10% 的钱变成‘鹅’，那么你一定会变得富有。但如果你想有一天真的非常有钱的话，你存的比例可能得再高一些。我的习惯是把我收入的 50% 变成我的‘鹅’。</p><h3 id="第八章 - 陶穆太太"><a href="# 第八章 - 陶穆太太" class="headerlink" title="第八章  陶穆太太"></a>第八章  陶穆太太 </h3><h3 id="第九章 - 冒险经历"><a href="# 第九章 - 冒险经历" class="headerlink" title="第九章  冒险经历"></a> 第九章  冒险经历 </h3><h3 id="第十章 - 在地下室里"><a href="# 第十章 - 在地下室里" class="headerlink" title="第十章  在地下室里"></a> 第十章  在地下室里 </h3><h3 id="第十一章 - 爸爸妈妈不明白"><a href="# 第十一章 - 爸爸妈妈不明白" class="headerlink" title="第十一章  爸爸妈妈不明白"></a> 第十一章  爸爸妈妈不明白 </h3><p> 幸运其实只是充分准备加上努力工作的结果。</p><p>勇敢的人也会害怕，一个人虽然害怕却仍然敢于前进，这才叫勇敢。</p><p>你干的活最多只值报酬的一半，另一半报酬源于你的想法和实施这个想法的勇气。</p><h3 id="第十二章 - 陶穆太太归来"><a href="# 第十二章 - 陶穆太太归来" class="headerlink" title="第十二章  陶穆太太归来"></a>第十二章  陶穆太太归来 </h3><p> 首先，因为我有时喜欢把这些东西拿在手里 <strong> 欣赏</strong>，我很喜欢黄金和钞票。</p><p>第二，这一笔钱是留着应 <strong> 急用 </strong> 的。不管发生什么事，我放在箱子里的东西总够我花上几年的。</p><p>第三，我把很大一部分钱投到了股票上面，这包含了一定的 <strong> 风险</strong>。所以，至少要把一部分钱放在手头，这是明智的做法。</p><p>钱只会留在那些为之付出努力的人身边。用非法手段取得不义之财的人，反而会比没钱的时候感觉更糟糕。</p><p>要想过更幸福、更满意的生活，人就得改变自身。这和钱无关，金钱本身既不会使人幸福，也不会带来不幸。金钱是中性的，既不好，也不坏。只有当钱属于某一个人的时候，它才会对这个人产生好的影响或者坏的影响。钱可以被用于好的用途，也可以被用于坏的用途。一个幸福的人有了钱会更幸福；而一个悲观忧虑的人，钱越多，烦恼就越多。</p><p>金钱会暴露一个人的 <strong> 本性</strong>，金钱就像一个放大镜，它帮你更充分地展现出你本来的样子。好人可以用钱做很多好事。而如果你是盗贼，那你很可能会把钱挥霍在一些蠢事上。</p><p>金钱能成为我们生活中非常强大的助推力。金钱可以在一定程度上提高我们的生活水平—生活的许多方面都是以钱为基础的。有了钱，我们就更容易实现我们的目标和梦想—当然，包括好的目标和梦想，也包括坏的目标和梦想。</p><p>我只是把一部分现金放在箱子里，还有一部分存在银行的保险柜里。盗贼不可能让我陷入困境的。</p><p>只有你自己才能强迫自己去做。</p><p>兴趣是有的！不过往往也伴随着恐惧。你以为我中断了学业跑到世界各地，很轻松吗？我常常感到不安。</p><p>最珍贵的礼物是我们自己争取来的。<strong>克服了丢面子的恐惧</strong>，世界就会向你敞开大门！</p><h3 id="第十三章 - 巨大的危机"><a href="# 第十三章 - 巨大的危机" class="headerlink" title="第十三章  巨大的危机"></a>第十三章  巨大的危机 </h3><p> 你可以做一个有能力帮助别人的人，而别人也会相信你，愿意接受你的帮助。</p><p>成功会使人骄傲。如果你骄傲自大，你就会停止学习。不学习，人就不会再进步。</p><p>当你写成功日记的时候，你会对自己，对世界，还有对成功的规律作更深入的思考，会越来越多地了解自己和自己的愿望，这样你才会有能力去理解别人。彻底了解自己和世界上的所有秘密，是我们无法完全实现的一种理想，但我们可以一步一步地慢慢接近这种理想。</p><p>你不能在困难面前逃跑。困难、犯错误和丢面子引起的恐惧已经破坏了无数人的生活。</p><p>每当你觉得有些事情不好办的时候，你可以做一件事，只要翻一翻成功日记，你就会从过去的事情中找到证据，相信自己未来也有能力完成任何事情。</p><p>恐惧总是出现在我们设想事情会如何不顺的时候。我们对失败的可能性想得越多，就会越害怕。而当你看着自己的成功日记时，你就会注意到那些成功的事情，自然而然也就会想到应该怎样去做。</p><p>当你朝着积极的目标去思考的时候，就不会心生畏惧。</p><h3 id="第十四章 - 投资俱乐部"><a href="# 第十四章 - 投资俱乐部" class="headerlink" title="第十四章  投资俱乐部"></a>第十四章  投资俱乐部</h3><p>\1. 应该把钱投资在安全的地方。</p><p>\2. 我的钱应该下很多“金蛋”。</p><p>\3. 我们的投资应该简单明了。</p><p>决定一件东西价值多少的唯一因素就是，你愿意为它支付多少钱。</p><p>因为只有当别人相信这些股份将来可以卖出一个更好的价钱的时候，他才会买进。这就是每天在交易所里发生的事情。交易所是人们聚在一起买卖公司股份的地方，每个人都希望将来会有人以更高的价钱买下他手里的股份。</p><p>每当公司赢利，就会把利润分配给所有持有股份的人，这叫红利。</p><h3 id="第十五章 - 演 - 讲"><a href="# 第十五章 - 演 - 讲" class="headerlink" title="第十五章  演 讲"></a>第十五章  演 讲 </h3><h3 id="第十六章 - 俱乐部的投资行动"><a href="# 第十六章 - 俱乐部的投资行动" class="headerlink" title="第十六章  俱乐部的投资行动"></a> 第十六章  俱乐部的投资行动 </h3><p> 基金就像一口大锅，许多没有时间、没有相关的知识或者没有兴趣亲自去买股票的投资人都会把钱投进这口锅里，这些钱由金融界的专家—也就是所谓的基金经理人—去投资买股票。国家对此进行严格的监督，基金经理人必须遵守一定的规定。比如，他们至少必须购买 20 种不同的股票。</p><p>在实际情况中，会有几种股票行情下跌，有几种上涨，还有几种几乎保持不变。总体来说行情还是上涨的，因为基金经理人相当精通此道。</p><p>基金符合投资的一切要求。由于它的这些特点，它也非常适合儿童和青少年。如果能够在 5～10 年内不动用这些钱，基金投资是很保险的，它会带来丰厚的利润……</p><p>挑选基金时的注意事项：</p><p>\1. 基金应该至少有 10 年历史。假如它在这么长时间内一直有丰厚的利润，那我们可以认为，未来它也会运作良好。</p><p>\2. 应该选择大型的跨国股票基金。这种基金在世界各地购买股票，以此分散风险，所以十分安全。</p><p>\3. 对基金的走势图进行比较。我们应该观察在过去 10 年间哪些基金的年终利润最好。</p><p>你们直接用 72 除以你们投资的年利润百分比，得出的数字就是这笔钱翻一倍所要的年数。</p><p>最好再买另一种基金，这样有利于分散风险。</p><h3 id="第十七章 - 爷爷奶奶害怕风险"><a href="# 第十七章 - 爷爷奶奶害怕风险" class="headerlink" title="第十七章  爷爷奶奶害怕风险"></a>第十七章  爷爷奶奶害怕风险 </h3><p> 逢低买进，他是这么说的。</p><p>第一次股市行情暴跌的时候，我的反应和你们完全一样。我痛恨自己为什么要买下这些股票，而且我非常担心行情会继续下跌。在这种时候，报纸上充满了悲观的预测，说这是世界性经济危机的开端，是证券交易所永远的冬天。</p><p>只有当我实际卖出基金的时候，才会有损失；行情总是会回升的，证券交易所总会有‘夏天’和‘冬天’，而总的趋势始终是逐渐上升的；过去已经出现过很多次危机，也有几次形势的确很严峻，但是行情总是一次又一次地回升。</p><p>比如你可以投资日拆—这是一种银行向证券公司提供的短期贷款，当天结算。这种投资的收入是根据市场行情变化的，目前收益率大概是 3.5%。这笔钱你随时可以动用。</p><p>对，用这种方法你肯定不会变富，甚至可以说，事实上你的财产根本没有增加，因为通货膨胀会完全吞掉你的利息。</p><p>在一定通货膨胀率下，我们的钱在多长时间后会贬值一半。按 72 除以 3% 的通货膨胀率计算，得到 24，就是说 24 年以后，你的钱只值现在的一半。</p><h3 id="第十八章 - 大冒险的结局"><a href="# 第十八章 - 大冒险的结局" class="headerlink" title="第十八章  大冒险的结局"></a>第十八章  大冒险的结局</h3><p>50% 用来让鹅长大，40% 用来帮助实现我的目标，剩下 10% 用来零花。</p><p>不要为失去的东西而忧伤，而要对拥有它的时光心存感激。</p><h3 id="自力更生——写给成年人的后记"><a href="# 自力更生——写给成年人的后记" class="headerlink" title="自力更生——写给成年人的后记"></a>自力更生——写给成年人的后记 </h3><p> 钱钱拆除了偏见的围墙，让人眼前豁然开朗，它告诉我们：经营活动并不是童工劳动，而是一种能激发人的热情的游戏；<strong>赚钱并不枯燥，相反会带来激动人心的时刻，释放人的发明创造的才能。</strong></p><p>让孩子们在市场中学习，这也意味着在风险中学习。每一个商业决策都包含了一些 <strong> 风险</strong>。错误的决策迟早要遭受经济上的惩罚，而正确的决定最终将带来更高的收益。</p><p>“经营”和“赚钱”这两个游戏是严肃的。<strong>市场 </strong> 就像是一所课堂之外的学校，既是一条荆棘丛生的道路，也是一座错综复杂的迷宫；既是出产雷厉风行的人的场所，也是制造犹豫不决的人的工厂；既是培养思维能力的静修地，也是产生卓越策略的办公室，或是各种创意的交易所。市场这所学校是一个根植于现实生活中的梦想。</p><p>市场是一种原则—就像民主一样，它可能被滥用。市场并不意味着没有秩序，横冲直撞，而是意味着透明度、竞赛、对人和自然的责任、公平竞争和一定程度的保护。</p><p>商业活动意味着独立自主、积极主动，或者也可以说坚持己见，但那并不意味着缺乏团结友爱的精神。我们要对孩子们开展团队教育，这是因为，我们不是独自活在这个世界上，而是和其他人共同生活在一起的。</p><p>我们应该保护弱者，不能歧视少数群体，不要对不如自己的人颐指气使，不要追逐凌驾于众人之上的权力。而且商业活动不仅与人有关，也与自然有关。它关系到各种生物和这个星球上正在遭受掠夺的急需保护的资源。从伦理学的角度来说，那些有社会责任感、有生态意识的企业家是不会被市场抛弃的，并且他们时刻处于市场的前沿。</p><p>赚钱不是一件坏事，它可以为自己和他人带来好处。从小开始赚钱的人拥有对依赖思想的抵抗力，不会乐意让别人来养活自己。而且自己赚钱的人不会成为不断膨胀的消费欲望的奴隶。从事商业活动有助于人们以理智的态度珍惜和使用有限的资源。</p><p><strong>我们推崇一种聪明的、简朴的生活方式。也就是说，宁愿购买一件一流产品，也不要不停地买许多的二流产品。</strong>而且，不要仅仅因为一件产品的外观不再时髦而新产品正在流行，就不断追逐新鲜的东西。</p><p>生活质量不是由越来越多的高科技产品堆砌而成的，而体现在一些别的方面，比如悠闲地享受一下生活，增进邻里关系，表达感情或者从事艺术性和创造性的活动。</p><p>要想有所成就，必须从小做起。</p><p>分析企业家的传记，有一点很引人注目。绝大多数敢于投身商业活动的人，在童年时期就已经拥有了一些自己的想法，具有某种“怪癖”，而且善于思考。他们之中的大多数人有过小规模的经营管理的实践经验，参与过小型的经济活动。</p><p>心理治疗师和企业家彼得·戈培尔认为，思考可以是一种享受，而工作会带来无穷乐趣。具有横向思维能力的人将会受到欢迎，青少年完善自身的愿望和对独立的追求不应被遏制。</p><p>更为重要的是要从小开始培养孩子们的 <strong> 企业家精神</strong>，正确理解企业家素质（Entrepreneurship）。企业家素质不仅仅像目前大家所理解的那样，是企业家传记中描写的那些特殊的禀赋，它应更多地落实到每一个公民身上，让它成为大家都具备的基本素质。</p><p>什么是企业家素质呢？这是一个在英语国家常用的概念，很难找到恰当的译法。它指的是一种发展、革新的经营观念，以及将这种观念贯彻在市场中的能力。</p><p><strong>用“提出要求”代替“满足欲望”</strong></p><p>由于西方国家经济条件优越，使二战之后出生的这代人和他们的下一代在物质生活方面得到了充分的满足。</p><p>对于孩子们层出不穷的愿望，大人们把迅速满足他们的需要当作一剂速效镇静剂。于是孩子们失去了在发展心理学中被称作进取心和承受力的能力。被宠坏的孩子缺乏应对艰难时刻的心理准备。</p><p>中欧地区对“童年”这个概念的理解包括“废除剥削儿童的童工劳动，维护儿童的权益”等内容。它源于良好的愿望，但也有消极的一面，造成了儿童与社会的日益隔绝和童年期的延长，以及对孩子们过分保护和幼稚化的倾向。要想找出一个适合我们这个矛盾时代的对“童年”的解释，重要的是不要继续把孩子们培养成温驯听话的小绵羊，不要再用喂他们镇静剂的方式对他们进行职业素质教育。</p><p>孩子们具有掌握自己发展方向的潜力。因此，成年人不要替孩子们决定该如何发展，而是应该理解、支持他们，帮助他们成长，要相信孩子们的自觉性和进取心。</p><p>我们应该要求孩子们 <strong> 具有小心谨慎和不屈不挠的品质</strong>，并有意识地在这些方面培养他们。因此，在遇到需要解决的问题时，不要直接把答案摊在他们面前，而是应该给他们机会，让他们自己去寻找解决办法，使他们通过扩大视角、深入调查来体验研究、发现和实验的学习过程。</p><p>附  录</p><p>股票</p><p>股票是一家公司的股权证明—你可以购买这家公司的一份或若干份股权。每一份股权就是一张股票。如果公司赢利（赚钱），你就可以根据自己所拥有的股份数量，从公司的利润中分得一部分。你的股份越少，分到的利润就越少；股份越多，分到的利润就越多。如果公司亏损，那么你所持有的股票就会贬值。在这种情况下，你不应该急于卖出股票，而应该等待公司重新赢利。在第十六章中，陶穆太太对此有详细说明。</p><p>投资</p><p>一方面，投资是指通过获取利息使钱的数目增加，比如将钱投资买股票，或者存入银行；另一方面，通过购买任何一件日后会增值的物品，比如艺术品、房产、古董等，也可以进行投资。</p><p>交易所</p><p>交易所是一种特别的市场，是商人们为了进行商业交易而举行定期聚会的场所。交易所根据市场情况，并且通过官方的价格调控使供应和需求达到平衡。详情请见第十六章。</p><p>基金</p><p>出于特定用途而集中的资金（特殊财产），详情请参阅第十六章。</p><p>抵押</p><p>简而言之，抵押就是把地产等抵押品作为债务担保的行为。当房子所有权人负债时，他可以抵押这栋房子，作为法律上和经济上还款的保证，但这样一来，他的地产就记入了债权人名下。这就是说，这栋房子的所有权受到了限制，如果债务人—也就是房子所有权人—出售他的房子，获得的收益必须交给债权人。</p><p>通货膨胀</p><p>通货膨胀就是货币贬值。现在用 5 马克可以比 10 年后买到更多的东西，也就是说，货币的价值随着时间的增长而不断减少。</p><p>利息</p><p>如果你将资金借给银行（就是说把钱存入一个账户），银行就付给你一定的金额作为回报。如果你借给银行 3000 马克，银行就会按一个规定的利率—比如 3%，付给你利息，这样你每年都会得到 3000 马克的 3%，也就是 90 马克。</p><p>复利</p><p>你可以和银行约定，每年年终时将利息计入本金。我们还以上面的数字为例，那么你第二年的本金加在一起就达到了 3090 马克，这笔钱又重新开始产生利息：3090 的 3% 是 92.7 马克。这样继续下去，下一年的本金就是：3090＋92.7＝3182.70（马克）。以此类推，之后每年都这样计算。</p>]]></content>
    
    
    <summary type="html">本篇博客记录我看书的观后感。</summary>
    
    
    
    <category term="Book" scheme="http://example.com/categories/Book/"/>
    
    
    <category term="Book" scheme="http://example.com/tags/Book/"/>
    
    <category term="Thinking" scheme="http://example.com/tags/Thinking/"/>
    
  </entry>
  
  <entry>
    <title>Prompt Learning</title>
    <link href="http://example.com/2024/04/04/Study/Transformer/prompt/"/>
    <id>http://example.com/2024/04/04/Study/Transformer/prompt/</id>
    <published>2024-04-04T00:00:00.000Z</published>
    <updated>2024-04-04T00:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>本人很懒，不多介绍</p><span id="more"></span><h4 id="引言："><a href="# 引言：" class="headerlink" title="引言："></a>引言：</h4><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403262238949.png" alt="image-20240326223806832"></p><p>具体</p><p>角色扮演</p><p>给予更多信息</p><h4 id="指南："><a href="# 指南：" class="headerlink" title="指南："></a>指南：</h4><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403270908575.png" alt="image-20240327090826440"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403270909811.png" alt="image-20240327090915753"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403270910024.png" alt="image-20240327091018975">2</p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271000708.png" alt="image-20240327100044644"></p><h5 id="1"><a href="#1" class="headerlink" title="1."></a>1.</h5><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403270912505.png" alt="image-20240327091209446"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403270948086.png" alt="image-20240327094822023"></p><p>使用分割号，避免提示词冲突</p><p>eg.<code>&#123;text&#125;</code>三引号，单引号，双引号、XML 标记、章节标题等</p><h5 id="2"><a href="#2" class="headerlink" title="2."></a>2.</h5><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403270950734.png" alt="image-20240327095046678"></p><h5 id="3"><a href="#3" class="headerlink" title="3."></a>3.</h5><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403270955916.png" alt="image-20240327095547850"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403270957192.png" alt="image-20240327095747126"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403270958665.png" alt="image-20240327095842598"></p><h5 id="4"><a href="#4" class="headerlink" title="4."></a>4.</h5><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271006438.png" alt="image-20240327100600381"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271035342.png" alt="image-20240327103543277"></p><h5 id="1-1"><a href="#1-1" class="headerlink" title="1."></a>1.</h5><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271024016.png" alt="image-20240327102423934"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271024841.png" alt="image-20240327102451771"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271025840.png" alt="image-20240327102539785"></p><h5 id="2-1"><a href="#2-1" class="headerlink" title="2."></a>2.</h5><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271030089.png" alt="image-20240327103012028"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271030957.png" alt="image-20240327103044895"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271031644.png" alt="image-20240327103122580"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271031165.png" alt="image-20240327103138120"></p><h5 id="3-1"><a href="#3-1" class="headerlink" title="3."></a>3.</h5><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271032190.png" alt="image-20240327103237142"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271032549.png" alt="image-20240327103257470"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271033071.png" alt="image-20240327103329011"></p><h4 id="迭代："><a href="# 迭代：" class="headerlink" title="迭代："></a>迭代：</h4><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271100684.png" alt="image-20240327110040603"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271101168.png" alt="image-20240327110121104"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271103809.png" alt="image-20240327110320731"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271103041.png" alt="image-20240327110341975"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271104495.png" alt="image-20240327110432433"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271105920.png" alt="image-20240327110517862"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271105251.png" alt="image-20240327110542210"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271106742.png" alt="image-20240327110600689"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271107273.png" alt="image-20240327110705202"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271108138.png" alt="image-20240327110857089"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271110077.png" alt="image-20240327111048019"></p><h4 id="摘要："><a href="# 摘要：" class="headerlink" title="摘要："></a>摘要：</h4><h5 id="1-2"><a href="#1-2" class="headerlink" title="1."></a>1.</h5><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271112964.png" alt="image-20240327111204913"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271112799.png" alt="image-20240327111217750"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271847303.png" alt="image-20240327184724234"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271113701.png" alt="image-20240327111300639"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271848443.png" alt="image-20240327184829385"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271848273.png" alt="image-20240327184848179"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271849884.png" alt="image-20240327184905796"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271853708.png" alt="image-20240327185317639"></p><h4 id="推理："><a href="# 推理：" class="headerlink" title="推理："></a>推理：</h4><h5 id="1-3"><a href="#1-3" class="headerlink" title="1."></a>1.</h5><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271854003.png" alt="image-20240327185439935"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271855596.png" alt="image-20240327185500551"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271855311.png" alt="image-20240327185548248"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271856558.png" alt="image-20240327185617511"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271856594.png" alt="image-20240327185635539"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271856766.png" alt="image-20240327185650704"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271859927.png" alt="image-20240327185935837"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271900764.png" alt="image-20240327190000677"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271900547.png" alt="image-20240327190012497"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271900629.png" alt="image-20240327190025567"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271900540.png" alt="image-20240327190038489"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271901270.png" alt="image-20240327190109214"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271901892.png" alt="image-20240327190128847"></p><h4 id="转换："><a href="# 转换：" class="headerlink" title="转换："></a>转换：</h4><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271902968.png" alt="image-20240327190245906"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271903487.png" alt="image-20240327190301440"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271903018.png" alt="image-20240327190337966"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271904089.png" alt="image-20240327190418032"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271904151.png" alt="image-20240327190432065"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271904236.png" alt="image-20240327190452174"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271905301.png" alt="image-20240327190507240"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271905835.png" alt="image-20240327190532793"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271906089.png" alt="image-20240327190603040"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271905251.png" alt="image-20240327190547202"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271906290.png" alt="image-20240327190626228"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271907033.png" alt="image-20240327190732951"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271907648.png" alt="image-20240327190740584"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271907798.png" alt="image-20240327190759740"></p><h4 id="扩展："><a href="# 扩展：" class="headerlink" title="扩展："></a>扩展：</h4><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271908324.png" alt="image-20240327190834216"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271908750.png" alt="image-20240327190848690"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271909284.png" alt="image-20240327190905220"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271909235.png" alt="image-20240327190925168"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271909424.png" alt="image-20240327190943352"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271910305.png" alt="image-20240327191052231"></p><h4 id="聊天机器人："><a href="# 聊天机器人：" class="headerlink" title="聊天机器人："></a>聊天机器人：</h4><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271911551.png" alt="image-20240327191120487"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271913831.png" alt="image-20240327191352772"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271914869.png" alt="image-20240327191427813"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271914828.png" alt="image-20240327191437774"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271914841.png" alt="image-20240327191446800"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271915612.png" alt="image-20240327191506565"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271915723.png" alt="image-20240327191517669"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271915040.png" alt="image-20240327191533989"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271915845.png" alt="image-20240327191549796"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271916421.png" alt="image-20240327191602349"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271916027.png" alt="image-20240327191610985"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271916007.png" alt="image-20240327191633952"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271916555.png" alt="image-20240327191656489"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271917704.png" alt="image-20240327191719657"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403271918774.png" alt="image-20240327191823715"></p><p><a href="https://www.bilibili.com/video/BV1VZ421q7t3">https://www.bilibili.com/video/BV1VZ421q7t3</a></p><h3 id="课程总结："><a href="# 课程总结：" class="headerlink" title="课程总结："></a>课程总结：</h3><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403281652865.png" alt="image-20240328165230690"></p><p>关于这个 prompt，我初步有两个想法：</p><p>一、用大模型 LLM+prompt 帮我生成指令。我前期的第五章工作用手写的代码计算，设置规则，生成指令。可以提供信息（物体类别、颜色、位置），设置 prompt 让大模型帮我尝试生成指令，最后做测试。</p><p>二、借鉴这篇论文的思路， 设计一套二维模型的流程，用现有的检测模型，例如轻量级的 Yolo 生成检测结果，以及空间计算信息，然后使用 LLM 设置 prompt 推理为目标中的哪一个</p><h3 id="参考的论文 demo 结果："><a href="# 参考的论文 demo 结果：" class="headerlink" title="参考的论文 demo 结果："></a>参考的论文 demo 结果：</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">How many doors are there in this room?</span><br></pre></td></tr></table></figure><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403281423592.png" alt="image-20240328142346406"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403281423187.png" alt="image-20240328142325090"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403281424320.png" alt="image-20240328142431226"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403281425124.png" alt="image-20240328142509022"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403281425380.png" alt="image-20240328142538257"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403281425820.png" alt="image-20240328142552717"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202403281426977.png" alt="image-20240328142605873"></p><h3 id="分析参考论文吗 prompt："><a href="# 分析参考论文吗 prompt：" class="headerlink" title="分析参考论文吗 prompt："></a>分析参考论文吗 prompt：</h3><h3 id="角色目标："><a href="# 角色目标：" class="headerlink" title="角色目标："></a>角色目标：</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">SINGLE_TURN_MODE_SYSTEM_PROMPT = &quot;&quot;&quot;You are a dialog agent that helps users to ground visual objects and answer questiosn in a 3D room scan using dialog. The user starts the conversation with some goal object in mind, your goals are:</span><br><span class="line"></span><br><span class="line">1. Invoking an API for a neural visual grounder to obtain potential object matches. To summon the visual grounder, you utilize the API commands specified in the COMMANDS section. This API returns a JSON response containing potential target centroids, landmarks&#x27; centroids, their extents, and relationships between these elements. The API will also provide visual feedback indicating how the user&#x27;s description correlates with images of the potential matches.</span><br><span class="line">2. Examine the JSON results from the visual grounder, compare them against the user&#x27;s description, and determine the appropriate object. More specifically: </span><br><span class="line">   2.1. Contrast the centroid with the specified spatial relation given Target Candidate BBox (cx, cy, cz, dx, dy, dz) and Landmark Location (cx, cy, cz). Note that positive z is the upward direction</span><br><span class="line">   2.2. For each Target Candidate BBox give some reasoning as to why one should accept or reject a candidate, one by one. Choose and relay a unique ID that best matches these criteria. For example:</span><br><span class="line"></span><br><span class="line">.candidate 1 should be accepted because ....; it should be rejected because...</span><br><span class="line"></span><br><span class="line">.candidate 2 should be accepted because ....; it should be rejected because...</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">SINGLE_TURN_MODE_SYSTEM_PROMPT = &quot;&quot;&quot; 您是一个对话代理，可以使用对话帮助用户在 3D 房间扫描中定位可视对象并回答问题。用户带着某个目标对象开始对话，你的目标是</span><br><span class="line">1. 调用神经视觉定位器的应用程序接口，获取潜在的匹配对象。要调用视觉定位器，您需要使用 &quot; 命令 &quot; 部分中指定的 API 命令。该应用程序接口会返回一个 JSON 响应，其中包含潜在目标中心点、地标中心点、其范围以及这些元素之间的关系。API 还将提供视觉反馈，显示用户的描述与潜在匹配图像之间的关联。</span><br><span class="line">2.2. 检查视觉寻址器的 JSON 结果，将其与用户的描述进行比较，并确定合适的对象。更具体地说 </span><br><span class="line">2.1. 根据给定的目标候选 BBox（cx、cy、cz、dx、dy、dz）和地标位置（cx、cy、cz），将中心点与指定的空间关系进行对比。注意正 z 是向上的方向</span><br><span class="line">2.2. 对于每个目标候选 BBox，逐一给出接受或拒绝的理由。选择并转发一个最符合这些标准的唯一 ID。例如</span><br><span class="line">- 候选人 1 应被接受，因为 ....；它应被拒绝，因为......</span><br><span class="line">- 候选人 2 应被接受，因为 ....；它应被拒绝，因为......</span><br></pre></td></tr></table></figure><h3 id="1-4"><a href="#1-4" class="headerlink" title="1."></a>1.</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">COMMANDS:</span><br><span class="line">1. Visual grounder: &quot;ground&quot;, args: &quot;ground_json&quot;: &quot;&lt;ground_json&gt;&quot;</span><br><span class="line">2. Finish grounding: &quot;finish_grounding&quot;, args:  &quot;top_5_objects_scores&quot;: &quot;&lt;top_5_objects_scores&gt;&quot;, &quot;top_1_object_id&quot;: &quot;&lt;top_1_object_id&gt;&quot;</span><br><span class="line">You should only respond in JSON format as described below:</span><br><span class="line"></span><br><span class="line">DETAILED DESCRIPTION OF COMMANDS:</span><br><span class="line">1. Visual grounder: This command is termed &quot;ground&quot;. Its arguments are: &quot;ground_json&quot;: &quot;&lt;ground_json&gt;&quot;. The ground json should be structured as follows:</span><br><span class="line">Translate user descriptions into JSON-compatible format.</span><br><span class="line">Highlight the principal object described as the &quot;target&quot;, ensuring its uniqueness.</span><br><span class="line">Recognize one most important auxiliary object mentioned only in relation to the main object and call it &quot;landmark&quot;. Label the landmark as &quot;landmark&quot;. Do not include generic objects such as &quot;wall&quot; or &quot;floor&quot; as the landmark. Always use a more meaningful and uniquely identifable object the user mentions as a landmark.</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Example:</span><br><span class="line">User Input: &quot;I&#x27;m thinking of a white, glossy cabinet. To its left is a small, brown, wooden table, and on its right, a slightly smaller, matte table.&quot;</span><br><span class="line"></span><br><span class="line">ground_json = &#123;</span><br><span class="line">    &quot;target&quot;: &#123;</span><br><span class="line">        &quot;phrase&quot;: &quot;white, glossy cabinet&quot;</span><br><span class="line">    &#125;,</span><br><span class="line">    &quot;landmark&quot;: &#123;</span><br><span class="line">        &quot;phrase&quot;: &quot;small wooden brown table&quot;,</span><br><span class="line">        &quot;relation to target&quot;: &quot;left&quot;</span><br><span class="line">    &#125;,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">This output must be compatible with Python&#x27;s json.loads() function. Once the grounder returns information, you must make a decision in the next response by mentioning which candidate to select in the next command. Note that for the target object, only include attributes and the noun.</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">指令：</span><br><span class="line">1. Visual grounder： &quot;ground&quot;, args: &quot;ground_json&quot;： &quot;&lt;ground_json&gt;&quot;</span><br><span class="line">2. 完成接地 &quot;finish_grounding&quot;, args: &quot;top_5_objects_scores&quot;： &quot;&lt;top_5_objects_scores&gt;&quot;, &quot;top_1_object_id&quot;： &quot;&lt;top_1_object_id&gt;&quot;。</span><br><span class="line">您只能以下面描述的 JSON 格式响应：</span><br><span class="line"></span><br><span class="line">命令的详细说明：</span><br><span class="line">1. 可视化接地： 该命令称为 &quot; 接地 &quot;。其参数如下 &quot;ground_json&quot;： &quot;&lt;ground_json&gt;&quot;。地面 json 的结构如下：</span><br><span class="line">将用户描述转换为 JSON 兼容格式。</span><br><span class="line">突出显示作为 &quot; 目标 &quot; 描述的主要对象，确保其唯一性。</span><br><span class="line">识别一个仅与主要对象相关的最重要的辅助对象，并将其称为 &quot; 地标 &quot;。将地标标为 &quot; 地标 &quot;。不要将 &quot; 墙壁 &quot; 或 &quot; 地板 &quot; 等一般物体作为地标。一定要使用用户提到的更有意义且可唯一识别的物体作为地标。</span><br><span class="line"></span><br><span class="line">示例：</span><br><span class="line"></span><br><span class="line">用户输入 &quot; 我在想一个白色的光面柜子。左边是一张棕色的木质小桌子，右边是一张稍小的哑光桌子 &quot;。</span><br><span class="line"></span><br><span class="line">ground_json = &#123;</span><br><span class="line">    &quot; 目标 &quot;： &#123;</span><br><span class="line">        &quot;phrase&quot;： &quot; 白色光面柜子 &quot;</span><br><span class="line">    &#125;,</span><br><span class="line">    &quot; 地标 &quot;： &#123;</span><br><span class="line">        &quot;phrase&quot;： &quot; 棕色木质小桌 &quot;、</span><br><span class="line">        &quot; 与目标的关系 &quot;： &quot; 左 &quot;</span><br><span class="line">    &#125;,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">该输出必须与 Python 的 json.loads() 函数兼容。一旦 grounder 返回信息，您必须在下一个响应中做出决定，在下一条命令中提及选择哪个候选对象。请注意，对于目标对象，只需包含属性和名词。</span><br></pre></td></tr></table></figure><h3 id="2-2"><a href="#2-2" class="headerlink" title="2."></a>2.</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line">2. Finish Grounding: This command is termed &quot;finish_grounding&quot;, with arguments: &#123;&quot;top_5_objects_scores&quot;: &#123;&quot;&lt;object_id&gt;&quot;: &quot;&lt;object_score&gt;&quot;&#125;, &quot;top_1_object_id&quot;: &quot;&lt;top_1_object_id&gt;&quot;&#125;, where score is number between 0 and 1 that you need to decide based on all information to indicate how likely this object should be selected to match with the user query.</span><br><span class="line"></span><br><span class="line">Example:</span><br><span class="line"></span><br><span class="line">&quot;args&quot; = &#123;</span><br><span class="line">    &quot;top_5_objects_scores&quot;: &#123;&quot;7&quot;: 0.93, &quot;1&quot;: 0.81, &quot;0&quot;: 0.67, &quot;4&quot;: 0.51, &quot;9&quot;: 0.44&#125;</span><br><span class="line">    &quot;top_1_object_id&quot;: &quot;7&quot;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">RESPONSE TEMPLATE:</span><br><span class="line">&#123;</span><br><span class="line">    &quot;thoughts&quot;:</span><br><span class="line">    &#123;</span><br><span class="line">        &quot;observation&quot;: &quot;observation&quot;,</span><br><span class="line">        &quot;reasoning&quot;: &quot;reasoning&quot;,</span><br><span class="line">        &quot;plan&quot;: &quot;a numbered list of steps to take that conveys the long-term plan&quot;,</span><br><span class="line">        &quot;self-critique&quot;: &quot;constructive self-critique&quot;,</span><br><span class="line">        &quot;speak&quot;: &quot;thoughts summary to say to user&quot;</span><br><span class="line">    &#125;,</span><br><span class="line">    &quot;command&quot;: &#123;</span><br><span class="line">        &quot;name&quot;: &quot;command name&quot;,</span><br><span class="line">        &quot;args&quot;:&#123;</span><br><span class="line">            &quot;arg name&quot;: &quot;value&quot;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">Importantly, in your response JSON,  the &quot;thoughts&quot; section should be generated before the &quot;command&quot; section. Put any string in one line, do NOT include any new line character in observation, reasoning, plan, self-critique or speak.</span><br><span class="line"></span><br><span class="line">Example:</span><br><span class="line"></span><br><span class="line">&#123;</span><br><span class="line">&quot;thoughts&quot;: &#123;</span><br><span class="line">&quot;observation&quot;: &quot;The user described a silver, cube-shaped file cabinet located in the middle of the northern side of the room. There is a whiteboard above it and a black couch to its right.&quot;,</span><br><span class="line">&quot;reasoning&quot;: &quot;The user provided specific details about the file cabinet&#x27;s shape, color, and location. These details will help the visual grounder to identify the target object more accurately.&quot;,</span><br><span class="line">&quot;plan&quot;: &quot;1. Invoke the visual grounder with the translated ground_json. 2. Analyze the results from the visual grounder. 3. Choose the object that best matches the user&#x27;s description based on the centroid and spatial relation.&quot;,</span><br><span class="line">&quot;self-critique&quot;: &quot;The landmarks provided by the user are distinct and should aid in the accurate identification of the target object. However, if the visual grounder does not return a perfect match, further clarification may be required.&quot;,</span><br><span class="line">&quot;speak&quot;: &quot;I am identifying the silver, cube-shaped file cabinet that is under a whiteboard and to the left of a black couch. It&#x27;s located in the middle of the northern side of the room.&quot;</span><br><span class="line">&#125;,</span><br><span class="line">&quot;command&quot;: &#123;</span><br><span class="line">&quot;name&quot;: &quot;ground&quot;,</span><br><span class="line">&quot;args&quot;: &#123;</span><br><span class="line">&quot;ground_json&quot;: &#123;</span><br><span class="line">&quot;target&quot;: &#123;</span><br><span class="line">&quot;phrase&quot;: &quot;silver cube shaped file cabinet&quot;</span><br><span class="line">&#125;,</span><br><span class="line">&quot;landmark&quot;: &#123;</span><br><span class="line">&quot;phrase&quot;: &quot;whiteboard&quot;,</span><br><span class="line">&quot;relation to target&quot;: &quot;above&quot;</span><br><span class="line">&#125;,</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">Do not include generic objects such as &quot;wall&quot; or &quot;floor&quot; as the landmark. In the phrase for target and landmark, make sure only one noun exists in the text.</span><br><span class="line">Again, your response should be in JSON format and can be parsed by Python json.loads().</span><br><span class="line">&quot;&quot;&quot;</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line">2. 完成接地： 该命令称为 &quot;finish_grounding&quot;，参数为 &#123;&quot;top_5_objects_scores&quot;: &#123;&quot;&lt;object_id&gt;&quot;： &quot;&lt; 对象_分数 &gt;&quot;&#125;, &quot;top_1_object_id&quot;： &quot;&lt;top_1_object_id&gt;&quot;&#125;，其中 score 是介于 0 和 1 之间的数字，您需要根据所有信息来决定该对象被选中与用户查询匹配的可能性有多大。</span><br><span class="line">例如 </span><br><span class="line"></span><br><span class="line">&quot;args&quot; = &#123;</span><br><span class="line">    &quot;top_5_objects_scores&quot;： &#123;&quot;7&quot;: 0.93, &quot;1&quot;: 0.81, &quot;0&quot;: 0.67, &quot;4&quot;: 0.51, &quot;9&quot;: 0.44&#125;</span><br><span class="line">    &quot;top_1_object_id&quot;： &quot;7&quot;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"> 响应模板：</span><br><span class="line">&#123;</span><br><span class="line">    &quot; 想法 &quot;：</span><br><span class="line">    &#123;</span><br><span class="line">        &quot;observation&quot;： 观察 </span><br><span class="line">        &quot; 推理 &quot;： &quot; 推理 &quot;：</span><br><span class="line">        &quot; 计划 &quot;： &quot; 一份编号的步骤清单，传达长期计划 &quot;、</span><br><span class="line">        &quot; 自我批评 &quot; 建设性的自我批评</span><br><span class="line">        &quot; 说 &quot;：&quot; 对用户说的想法摘要 &quot;： &quot; 要对用户说的想法摘要 &quot;。</span><br><span class="line">    &#125;,</span><br><span class="line">    &quot; 命令 &quot;： &#123;</span><br><span class="line">        &quot; 名称 &quot;： &quot; 命令名称 &quot;、</span><br><span class="line">        &quot;args&quot;:&#123;</span><br><span class="line">            &quot;arg name&quot;： &quot; 值 &quot;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"> 重要的是，在您的回复 JSON 中，&quot; 想法 &quot; 部分应在 &quot; 命令 &quot; 部分之前生成。在观察、推理、计划、自我批评或发言中，请勿包含任何新行字符。</span><br><span class="line"></span><br><span class="line">例如 </span><br><span class="line"></span><br><span class="line">&#123;</span><br><span class="line">&quot; 想法 &quot;： &#123;</span><br><span class="line"> 观察 &quot; 用户描述了一个银色的立方体文件柜，位于房间的北侧中间。文件柜上方有一块白板，右侧有一张黑色沙发 &quot;、</span><br><span class="line">&quot; 推理 &quot;： &quot; 用户提供了有关文件柜形状、颜色和位置的具体细节。这些细节将帮助视觉定位仪更准确地识别目标对象。&quot;、</span><br><span class="line">&quot; 计划 &quot;：&quot;1： &quot;1. 使用翻译后的 ground_json 调用视觉 grounder。2. 2. 分析来自 visual grounder 的结果。3. 3. 根据中心点和空间关系选择最符合用户描述的对象 &quot;、</span><br><span class="line">&quot; 自我批评 &quot;： &quot; 用户提供的地标很明显，应有助于准确识别目标对象。但是，如果视觉地标不能完全匹配，则可能需要进一步说明 &quot;、</span><br><span class="line">&quot; 说 &quot;： &quot; 我正在识别白板下方、黑色沙发左侧的银色立方体文件柜。它位于房间北侧的中间位置。&quot;</span><br><span class="line">&#125;,</span><br><span class="line">&quot; 命令 &quot;： &#123;</span><br><span class="line">&quot; 名称 &quot;： &quot;ground&quot;、</span><br><span class="line">&quot;args&quot;： &#123;</span><br><span class="line">&quot;ground_json&quot;： &#123;</span><br><span class="line">&quot;target&quot;： &#123;</span><br><span class="line">&quot;phrase&quot;： &quot; 银色立方体文件柜 &quot;</span><br><span class="line">&#125;,</span><br><span class="line">&quot; 地标 &quot;： &#123;</span><br><span class="line">&quot;phrase&quot;： &quot; 白板 &quot;、</span><br><span class="line">&quot; 与目标的关系 &quot;： &quot; 上方 &quot;</span><br><span class="line">&#125;,</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">不要将 &quot; 墙壁 &quot; 或 &quot; 地板 &quot; 等一般物体作为地标。在目标和地标的短语中，确保文本中只存在一个名词。</span><br><span class="line">同样，您的响应应该是 JSON 格式，可以用 Python json.loads() 解析。</span><br><span class="line">&quot;&quot;&quot;</span><br></pre></td></tr></table></figure><h3 id="3-2"><a href="#3-2" class="headerlink" title="3."></a>3.</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line">3. Finish Grounding: This command is termed &quot;finish_grounding&quot;, with arguments: &#123;&quot;top_5_objects_scores&quot;: &#123;&quot;&lt;object_id&gt;&quot;: &quot;&lt;object_score&gt;&quot;&#125;, &quot;top_1_object_id&quot;: &quot;&lt;top_1_object_id&gt;&quot;&#125;, where score is number between 0 and 1 that you need to decide based on all information to indicate how likely this object should be selected to match with the user query.</span><br><span class="line"></span><br><span class="line">Example:</span><br><span class="line"></span><br><span class="line">&quot;args&quot; = &#123;</span><br><span class="line">    &quot;top_5_objects_scores&quot;: &#123;&quot;7&quot;: 0.93, &quot;1&quot;: 0.81, &quot;0&quot;: 0.67, &quot;4&quot;: 0.51, &quot;9&quot;: 0.44&#125;</span><br><span class="line">    &quot;top_1_object_id&quot;: &quot;7&quot;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">RESPONSE TEMPLATE:</span><br><span class="line">&#123;</span><br><span class="line">    &quot;thoughts&quot;:</span><br><span class="line">    &#123;</span><br><span class="line">        &quot;observation&quot;: &quot;observation&quot;,</span><br><span class="line">        &quot;reasoning&quot;: &quot;reasoning&quot;,</span><br><span class="line">        &quot;plan&quot;: &quot;a numbered list of steps to take that conveys the long-term plan&quot;,</span><br><span class="line">        &quot;self-critique&quot;: &quot;constructive self-critique&quot;,</span><br><span class="line">        &quot;speak&quot;: &quot;thoughts summary to say to user&quot;</span><br><span class="line">    &#125;,</span><br><span class="line">    &quot;command&quot;: &#123;</span><br><span class="line">        &quot;name&quot;: &quot;command name&quot;,</span><br><span class="line">        &quot;args&quot;:&#123;</span><br><span class="line">            &quot;arg name&quot;: &quot;value&quot;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">Importantly, in your response JSON,  the &quot;thoughts&quot; section should be generated before the &quot;command&quot; section. Put any string in one line, do NOT include any new line character in observation, reasoning, plan, self-critique or speak.</span><br><span class="line"></span><br><span class="line">Example:</span><br><span class="line"></span><br><span class="line">&#123;</span><br><span class="line">&quot;thoughts&quot;: &#123;</span><br><span class="line">&quot;observation&quot;: &quot;The user described a silver, cube-shaped file cabinet located in the middle of the northern side of the room. There is a whiteboard above it and a black couch to its right.&quot;,</span><br><span class="line">&quot;reasoning&quot;: &quot;The user provided specific details about the file cabinet&#x27;s shape, color, and location. These details will help the visual grounder to identify the target object more accurately.&quot;,</span><br><span class="line">&quot;plan&quot;: &quot;1. Invoke the visual grounder with the translated ground_json. 2. Analyze the results from the visual grounder. 3. Choose the object that best matches the user&#x27;s description based on the centroid and spatial relation.&quot;,</span><br><span class="line">&quot;self-critique&quot;: &quot;The landmarks provided by the user are distinct and should aid in the accurate identification of the target object. However, if the visual grounder does not return a perfect match, further clarification may be required.&quot;,</span><br><span class="line">&quot;speak&quot;: &quot;I am identifying the silver, cube-shaped file cabinet that is under a whiteboard and to the left of a black couch. It&#x27;s located in the middle of the northern side of the room.&quot;</span><br><span class="line">&#125;,</span><br><span class="line">&quot;command&quot;: &#123;</span><br><span class="line">&quot;name&quot;: &quot;ground&quot;,</span><br><span class="line">&quot;args&quot;: &#123;</span><br><span class="line">&quot;ground_json&quot;: &#123;</span><br><span class="line">&quot;target&quot;: &#123;</span><br><span class="line">&quot;phrase&quot;: &quot;silver cube shaped file cabinet&quot;</span><br><span class="line">&#125;,</span><br><span class="line">&quot;landmark&quot;: &#123;</span><br><span class="line">&quot;phrase&quot;: &quot;whiteboard&quot;,</span><br><span class="line">&quot;relation to target&quot;: &quot;above&quot;</span><br><span class="line">&#125;,</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">Do not include generic objects such as &quot;wall&quot; or &quot;floor&quot; as the landmark. In the phrase for target and landmark, make sure only one noun exists in the text.-【</span><br><span class="line">Again, your response should be in JSON format and can be parsed by Python json.loads().</span><br><span class="line">&quot;&quot;&quot;</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">3. 完成接地： 该命令称为 &quot;finish_grounding&quot;，参数为 &#123;&quot;top_5_objects_scores&quot;: &#123;&quot;&lt;object_id&gt;&quot;： &quot;&lt; 对象_分数 &gt;&quot;&#125;, &quot;top_1_object_id&quot;： &quot;&lt;top_1_object_id&gt;&quot;&#125;，其中 score 是介于 0 和 1 之间的数字，您需要根据所有信息来决定该对象被选中与用户查询匹配的可能性有多大。</span><br><span class="line"></span><br><span class="line">例如 </span><br><span class="line"></span><br><span class="line">&quot;args&quot; = &#123;</span><br><span class="line">    &quot;top_5_objects_scores&quot;： &#123;&quot;7&quot;: 0.93, &quot;1&quot;: 0.81, &quot;0&quot;: 0.67, &quot;4&quot;: 0.51, &quot;9&quot;: 0.44&#125;</span><br><span class="line">    &quot;top_1_object_id&quot;： &quot;7&quot;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"> 响应模板：</span><br><span class="line">&#123;</span><br><span class="line">    &quot; 想法 &quot;：</span><br><span class="line">    &#123;</span><br><span class="line">        &quot;observation&quot;： &quot; 观察 &quot;、</span><br><span class="line">        &quot; 推理 &quot;： &quot; 推理 &quot;：</span><br><span class="line">        &quot; 计划 &quot;： &quot; 一份编号的步骤清单，传达长期计划 &quot;、</span><br><span class="line">        &quot; 自我批评 &quot; 建设性的自我批评 </span><br><span class="line">        &quot; 说 &quot;：&quot; 对用户说的想法摘要 &quot;： &quot; 要对用户说的想法摘要 &quot;。</span><br><span class="line">    &#125;,</span><br><span class="line">    &quot; 命令 &quot;： &#123;</span><br><span class="line">        &quot; 名称 &quot;： &quot; 命令名称 &quot;、</span><br><span class="line">        &quot;args&quot;:&#123;</span><br><span class="line">            &quot;arg name&quot;： &quot; 值 &quot;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"> 重要的是，在您的回复 JSON 中，&quot; 想法 &quot; 部分应在 &quot; 命令 &quot; 部分之前生成。在观察、推理、计划、自我批评或发言中，将任何字符串放在一行中，不要包含任何新行字符。</span><br></pre></td></tr></table></figure><h3 id="prompt："><a href="#prompt：" class="headerlink" title="prompt："></a>prompt：</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br></pre></td><td class="code"><pre><span class="line"># 模板一 &lt;obj&gt;&lt;location&gt;</span><br><span class="line">LOC_FIRST = &#123;</span><br><span class="line">    &quot;left&quot; : &quot;on left, on the left side&quot;,</span><br><span class="line">    &quot;right&quot; : &quot;on right, on the right side&quot;,</span><br><span class="line">    &quot;front&quot; : &quot;in front&quot;,</span><br><span class="line">    &quot;back&quot; : &quot;in back&quot;,</span><br><span class="line">    &quot;top&quot; : &quot;on top, at top&quot;,</span><br><span class="line">    &quot;bottom&quot; : &quot;on bottom, at bottom&quot;,</span><br><span class="line">    &quot;top left&quot; : &quot;on top left, in top left, at top left&quot;,</span><br><span class="line">    &quot;bottom left&quot; : &quot;on bottom left, in bottom left, at bottom left&quot;,</span><br><span class="line">    &quot;top right&quot; : &quot;on top right, in top right, at top right&quot;,</span><br><span class="line">    &quot;bottom right&quot; : &quot;on bottom right, in bottom right, at bottom right&quot;,</span><br><span class="line">    &quot;front left&quot; : &quot;front left, in front left&quot;,</span><br><span class="line">    &quot;back left&quot; : &quot;back left, in the back left&quot;,</span><br><span class="line">    &quot;front right&quot; : &quot;front right, in front right&quot;,</span><br><span class="line">    &quot;back right&quot; : &quot;back right, in back right&quot;,</span><br><span class="line">    &quot;center&quot; : &quot;at center&quot;</span><br><span class="line">&#125;</span><br><span class="line"># 模板二 &lt;location&gt;&lt;obj&gt; or the &lt;location&gt; of &lt;obj&gt; </span><br><span class="line">LOC_SECOND = &#123;</span><br><span class="line">    &quot;left&quot; : &quot;left&quot;,</span><br><span class="line">    &quot;right&quot; : &quot;right&quot;,</span><br><span class="line">    &quot;top&quot; : &quot;top&quot;,</span><br><span class="line">    &quot;bottom&quot; : &quot;bottom&quot;,</span><br><span class="line">    &quot;top left&quot; : &quot;top left&quot;,</span><br><span class="line">    &quot;bottom left&quot; : &quot;bottom left&quot;,</span><br><span class="line">    &quot;top right&quot; : &quot;top right&quot;,</span><br><span class="line">    &quot;bottom right&quot; : &quot;bottom right&quot;,</span><br><span class="line">    &quot;front left&quot; : &quot;front left&quot;,</span><br><span class="line">    &quot;back left&quot; : &quot;back left&quot;,</span><br><span class="line">    &quot;front right&quot; : &quot;front right&quot;,</span><br><span class="line">    &quot;back right&quot; : &quot;back right&quot;,</span><br><span class="line">&#125;</span><br><span class="line"># 模板三 &lt;obj&gt; &lt;location&gt; &lt;obj_ref&gt;</span><br><span class="line">LOC_THIRD = &#123;</span><br><span class="line">    &quot;left&quot; : &quot;to the left of&quot;,</span><br><span class="line">    &quot;right&quot; : &quot;to the right of&quot;,</span><br><span class="line">    &quot;front&quot; : &quot;in front of&quot;,</span><br><span class="line">    &quot;back&quot; : &quot;in back of&quot;,</span><br><span class="line">    &quot;top&quot; : &quot;at the top of, on the top of&quot;,</span><br><span class="line">    &quot;bottom&quot; : &quot;at the bottom of, on the bottom of&quot;,</span><br><span class="line">    &quot;top left&quot; : &quot;on top left of&quot;,</span><br><span class="line">    &quot;bottom left&quot; : &quot;on bottom left of&quot;,</span><br><span class="line">    &quot;top right&quot; : &quot;on top right of&quot;,</span><br><span class="line">    &quot;bottom right&quot; : &quot;on bottom right of&quot;,</span><br><span class="line">    &quot;front left&quot; : &quot;front left of&quot;,</span><br><span class="line">    &quot;back left&quot; : &quot;back left of&quot;,</span><br><span class="line">    &quot;front right&quot; : &quot;front right of&quot;,   </span><br><span class="line">    &quot;back right&quot; : &quot;back right of&quot;,</span><br><span class="line">&#125;</span><br><span class="line"># 模板四 &lt;order&gt;&lt;obj&gt;&lt;direction&gt;  / &lt;order&gt;&lt;obj&gt;&lt;location&gt;</span><br><span class="line"># equal to location first</span><br><span class="line">ORDER_FOURTH = [&quot;first, 1st&quot;, &quot;second, 2nd&quot;, &quot;third, 3th&quot;, &quot;fourth, 4th&quot;, &quot;fifth, 5th&quot;, &quot;sixth, 6th&quot;, &quot;seventh, 7th&quot;, &quot;eighth, 8th&quot;, &quot;ninth, 9th&quot;]</span><br><span class="line"># DIR_FOURTH = [&quot;from left&quot;, &quot;from right&quot;, &quot;from top&quot;, &quot;from bottom&quot;, &quot;from front&quot;, &quot;from back&quot;]</span><br><span class="line">DIR_FOURTH = [&quot;from left&quot;, &quot;from right&quot;, &quot;from top&quot;, &quot;from bottom&quot;]</span><br><span class="line"># 类别 id</span><br><span class="line">ID_BBOX = &#123;</span><br><span class="line">    &#x27;0&#x27; : &quot;other&quot;,</span><br><span class="line">    &#x27;1&#x27; : &quot;bottle&quot;,</span><br><span class="line">    &#x27;2&#x27; : &quot;bowl&quot;,</span><br><span class="line">    &#x27;3&#x27; : &quot;camera&quot;,</span><br><span class="line">    &#x27;4&#x27; : &quot;can&quot;,</span><br><span class="line">    &#x27;5&#x27; : &quot;laptop&quot;,</span><br><span class="line">    &#x27;6&#x27; : &quot;mug&quot;</span><br><span class="line">&#125;</span><br><span class="line">bbox:</span><br><span class="line">rois = [(169, 435, 236, 499), (122, 85, 320, 338), (286, 52, 377, 171), (155, 322, 245, 416), (151, 522, 252, 577)]</span><br><span class="line">ids:</span><br><span class="line">ids = [6, 5, 2, 3, 4]</span><br><span class="line"></span><br><span class="line">You are a agent that helps users to ground visual objects. your goals are:</span><br><span class="line">1. given four types of template styles, or you can create your own colorful templates to describe objects and their spatial location relationships.</span><br><span class="line">2. based on the templates, generate structured instruction templates that accurately describe the positional relationships between objects based on the input bbox (h1, w1, h2, w2) with the upper left corner as the coordinate origin representing (upper left vertical coordinate, upper left horizontal coordinate, lower right vertical coordinate, lower right horizontal coordinate) based on the input ids (the categories of the objects), using an appropriate strategy.</span><br><span class="line"></span><br><span class="line">Example:</span><br><span class="line">User Input: &quot;I&#x27;m thinking of a black camera. To its left is a big, black laptop, and on its right, a slightly smaller mug.&quot;</span><br><span class="line"></span><br><span class="line">ground_json = &#123;</span><br><span class="line">&quot;id&quot;:&#123;</span><br><span class="line">&quot;3&quot;</span><br><span class="line">&#125;,</span><br><span class="line">    &quot;target&quot;: &#123;</span><br><span class="line">        &quot;phrase_mode_1&quot;: &quot;camera on right&quot;</span><br><span class="line">        &quot;phrase_mode_2&quot;: &quot;right camera&quot;</span><br><span class="line">        &quot;phrase_mode_3&quot;: &quot;camera to the right of laptop&quot;</span><br><span class="line">        &quot;phrase_mode_4&quot;: &quot;3th camera from left&quot;</span><br><span class="line">    &#125;,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">This output must be compatible with Python&#x27;s json.loads() function. Once the grounder returns information, you must make a decision in the next response by mentioning which candidate to select in the next command. Note that for the target object, only include local attributes and the noun.Don&#x27;t code, just reason about the results.What I listed is just an example of one of the objects, can you generate the appropriate instructions based on the four templates?</span><br></pre></td></tr></table></figure><h3 id="1-5"><a href="#1-5" class="headerlink" title="1."></a>1.</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line">To achieve your goals, we can create functions to generate structured instruction templates based on the provided bbox and ids using the given template styles. Here&#x27;s a Python implementation:</span><br><span class="line"></span><br><span class="line">def generate_instructions(rois, ids):</span><br><span class="line">    instructions = []</span><br><span class="line"></span><br><span class="line">    for i, roi in enumerate(rois):</span><br><span class="line">        obj_id = str(ids[i])</span><br><span class="line">        obj_type = ID_BBOX.get(obj_id, &quot;other&quot;)</span><br><span class="line">        obj_location = get_object_location(roi)</span><br><span class="line">        instructions.append((obj_type, obj_location))</span><br><span class="line"></span><br><span class="line">    return instructions</span><br><span class="line"></span><br><span class="line">def get_object_location(roi):</span><br><span class="line">    h1, w1, h2, w2 = roi</span><br><span class="line">    center_h = (h1 + h2) / 2</span><br><span class="line">    center_w = (w1 + w2) / 2</span><br><span class="line"></span><br><span class="line">    if center_h &lt;= 0.25:</span><br><span class="line">        if center_w &lt;= 0.25:</span><br><span class="line">            return &quot;top left&quot;</span><br><span class="line">        elif center_w &gt;= 0.75:</span><br><span class="line">            return &quot;top right&quot;</span><br><span class="line">        else:</span><br><span class="line">            return &quot;top&quot;</span><br><span class="line">    elif center_h &gt;= 0.75:</span><br><span class="line">        if center_w &lt;= 0.25:</span><br><span class="line">            return &quot;bottom left&quot;</span><br><span class="line">        elif center_w &gt;= 0.75:</span><br><span class="line">            return &quot;bottom right&quot;</span><br><span class="line">        else:</span><br><span class="line">            return &quot;bottom&quot;</span><br><span class="line">    else:</span><br><span class="line">        if center_w &lt;= 0.25:</span><br><span class="line">            return &quot;left&quot;</span><br><span class="line">        elif center_w &gt;= 0.75:</span><br><span class="line">            return &quot;right&quot;</span><br><span class="line">        else:</span><br><span class="line">            return &quot;center&quot;</span><br><span class="line"></span><br><span class="line">def generate_template_one(obj_type, obj_location):</span><br><span class="line">    return f&quot;&#123;obj_type&#125; &#123;LOC_FIRST[obj_location]&#125;&quot;</span><br><span class="line"></span><br><span class="line">def generate_template_two(obj_type, obj_location):</span><br><span class="line">    return f&quot;&#123;LOC_SECOND[obj_location]&#125; &#123;obj_type&#125;&quot;</span><br><span class="line"></span><br><span class="line">def generate_template_three(obj_type, obj_location, obj_ref):</span><br><span class="line">    return f&quot;&#123;obj_type&#125; &#123;LOC_THIRD[obj_location]&#125; &#123;obj_ref&#125;&quot;</span><br><span class="line"></span><br><span class="line">def generate_template_four(order, obj_type, direction):</span><br><span class="line">    return f&quot;&#123;ORDER_FOURTH[order]&#125; &#123;obj_type&#125; &#123;direction&#125;&quot;</span><br><span class="line"></span><br><span class="line">rois = [(169, 435, 236, 499), (122, 85, 320, 338), (286, 52, 377, 171), (155, 322, 245, 416), (151, 522, 252, 577)]</span><br><span class="line">ids = [6, 5, 2, 3, 4]</span><br><span class="line"></span><br><span class="line">instructions = generate_instructions(rois, ids)</span><br><span class="line"></span><br><span class="line">for i, (obj_type, obj_location) in enumerate(instructions):</span><br><span class="line">    print(f&quot;Object &#123;i+1&#125;:&quot;)</span><br><span class="line">    print(&quot;Template One:&quot;, generate_template_one(obj_type, obj_location))</span><br><span class="line">    print(&quot;Template Two:&quot;, generate_template_two(obj_type, obj_location))</span><br><span class="line">    print(&quot;Template Three:&quot;, generate_template_three(obj_type, obj_location, &quot;the object&quot;))</span><br><span class="line">    print(&quot;Template Four:&quot;, generate_template_four(i, obj_type, DIR_FOURTH[i]))</span><br><span class="line">    print()</span><br><span class="line"></span><br><span class="line">This script will generate structured instruction templates for each object based on its location within the image. You can adjust the logic in get_object_location function if you need different spatial divisions or use additional templates as needed.</span><br></pre></td></tr></table></figure><h3 id="2-3"><a href="#2-3" class="headerlink" title="2."></a>2.</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br></pre></td><td class="code"><pre><span class="line">To achieve the goals, let&#x27;s create a Python script to generate structured instruction templates based on the provided bbox and ids using the given template styles. Then, we&#x27;ll format the output to be compatible with Python&#x27;s json.loads() function. Here&#x27;s the implementation:</span><br><span class="line">import json</span><br><span class="line"></span><br><span class="line">def generate_instructions(rois, ids):</span><br><span class="line">    instructions = []</span><br><span class="line"></span><br><span class="line">    for i, roi in enumerate(rois):</span><br><span class="line">        obj_id = str(ids[i])</span><br><span class="line">        obj_type = ID_BBOX.get(obj_id, &quot;other&quot;)</span><br><span class="line">        obj_location = get_object_location(roi)</span><br><span class="line">        instructions.append((obj_type, obj_location))</span><br><span class="line"></span><br><span class="line">    return instructions</span><br><span class="line"></span><br><span class="line">def get_object_location(roi):</span><br><span class="line">    h1, w1, h2, w2 = roi</span><br><span class="line">    center_h = (h1 + h2) / 2</span><br><span class="line">    center_w = (w1 + w2) / 2</span><br><span class="line"></span><br><span class="line">    if center_h &lt;= 0.25:</span><br><span class="line">        if center_w &lt;= 0.25:</span><br><span class="line">            return &quot;top left&quot;</span><br><span class="line">        elif center_w &gt;= 0.75:</span><br><span class="line">            return &quot;top right&quot;</span><br><span class="line">        else:</span><br><span class="line">            return &quot;top&quot;</span><br><span class="line">    elif center_h &gt;= 0.75:</span><br><span class="line">        if center_w &lt;= 0.25:</span><br><span class="line">            return &quot;bottom left&quot;</span><br><span class="line">        elif center_w &gt;= 0.75:</span><br><span class="line">            return &quot;bottom right&quot;</span><br><span class="line">        else:</span><br><span class="line">            return &quot;bottom&quot;</span><br><span class="line">    else:</span><br><span class="line">        if center_w &lt;= 0.25:</span><br><span class="line">            return &quot;left&quot;</span><br><span class="line">        elif center_w &gt;= 0.75:</span><br><span class="line">            return &quot;right&quot;</span><br><span class="line">        else:</span><br><span class="line">            return &quot;center&quot;</span><br><span class="line"></span><br><span class="line">def generate_template_one(obj_type, obj_location):</span><br><span class="line">    return f&quot;&#123;obj_type&#125; &#123;LOC_FIRST[obj_location]&#125;&quot;</span><br><span class="line"></span><br><span class="line">def generate_template_two(obj_type, obj_location):</span><br><span class="line">    return f&quot;&#123;LOC_SECOND[obj_location]&#125; &#123;obj_type&#125;&quot;</span><br><span class="line"></span><br><span class="line">def generate_template_three(obj_type, obj_location, obj_ref):</span><br><span class="line">    return f&quot;&#123;obj_type&#125; &#123;LOC_THIRD[obj_location]&#125; &#123;obj_ref&#125;&quot;</span><br><span class="line"></span><br><span class="line">def generate_template_four(order, obj_type, direction):</span><br><span class="line">    return f&quot;&#123;ORDER_FOURTH[order]&#125; &#123;obj_type&#125; &#123;direction&#125;&quot;</span><br><span class="line"></span><br><span class="line">def generate_ground_json(instructions):</span><br><span class="line">    ground_json = &#123;</span><br><span class="line">        &quot;id&quot;: &#123;</span><br><span class="line">            &quot;3&quot;</span><br><span class="line">        &#125;,</span><br><span class="line">        &quot;target&quot;: &#123;</span><br><span class="line">            &quot;phrase_mode_1&quot;: instructions[2][1],  # Using Template Two for simplicity</span><br><span class="line">            &quot;phrase_mode_2&quot;: instructions[2][1] + &quot; &quot; + instructions[0][0],  # Using Template Three for simplicity</span><br><span class="line">            &quot;phrase_mode_3&quot;: f&quot;&#123;instructions[2][0]&#125; &#123;LOC_THIRD[instructions[2][1]]&#125; &#123;instructions[0][0]&#125;&quot;,</span><br><span class="line">            &quot;phrase_mode_4&quot;: f&quot;&#123;ORDER_FOURTH[2]&#125; &#123;instructions[0][0]&#125; &#123;DIR_FOURTH[1]&#125;&quot;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    return json.dumps(ground_json, indent=4)</span><br><span class="line"></span><br><span class="line"># Sample Input</span><br><span class="line">rois = [(169, 435, 236, 499), (122, 85, 320, 338), (286, 52, 377, 171), (155, 322, 245, 416), (151, 522, 252, 577)]</span><br><span class="line">ids = [6, 5, 2, 3, 4]</span><br><span class="line"></span><br><span class="line"># Generate Instructions</span><br><span class="line">instructions = generate_instructions(rois, ids)</span><br><span class="line"></span><br><span class="line"># Generate Ground JSON</span><br><span class="line">ground_json = generate_ground_json(instructions)</span><br><span class="line"></span><br><span class="line">print(ground_json)</span><br><span class="line">This script generates the structured instruction templates and then constructs a JSON output compatible with Python&#x27;s json.loads() function. Adjust the output format as needed to match your requirements.</span><br></pre></td></tr></table></figure><h3 id="3-3"><a href="#3-3" class="headerlink" title="3."></a>3.</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">Based on the provided instructions and templates, here&#x27;s how we can reason about the results:</span><br><span class="line"></span><br><span class="line">Object Descriptions:</span><br><span class="line"></span><br><span class="line">Object 1: Mug</span><br><span class="line">Object 2: Laptop</span><br><span class="line">Object 3: Bowl</span><br><span class="line">Object 4: Camera</span><br><span class="line">Object 5: Can</span><br><span class="line">Spatial Relationships:</span><br><span class="line"></span><br><span class="line">Mug (Object 1) is located towards the bottom right.</span><br><span class="line">Laptop (Object 2) is located towards the top right.</span><br><span class="line">Bowl (Object 3) is located towards the top left.</span><br><span class="line">Camera (Object 4) is located towards the bottom left.</span><br><span class="line">Can (Object 5) doesn&#x27;t have a specified location, so it might be assumed to be somewhere in the center or not relevant to the described scene.</span><br><span class="line">Template Selection:</span><br><span class="line"></span><br><span class="line">For the target object (Camera), the phrase_mode_1 &quot;camera on right&quot; could be used, as it succinctly describes the object&#x27;s position relative to the others.</span><br><span class="line">Alternatively, phrase_mode_2 &quot;right camera&quot; could also be used for brevity.</span><br><span class="line">For a more descriptive option, phrase_mode_3 &quot;camera to the right of laptop&quot; could be chosen.</span><br><span class="line">Lastly, phrase_mode_4 &quot;3th camera from left&quot; could be selected if the order of objects matters, specifying the camera&#x27;s position relative to others in the scene.</span><br><span class="line">So, based on the provided information and templates, these are the reasoned selections for the target object&#x27;s positional description.</span><br></pre></td></tr></table></figure><h3 id="4-1"><a href="#4-1" class="headerlink" title="4."></a>4.</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">Based on the user input and the provided templates, here are the appropriate instructions for the target object (camera) based on the four templates:</span><br><span class="line"></span><br><span class="line">Template One:</span><br><span class="line"></span><br><span class="line">&quot;camera on right&quot;</span><br><span class="line">Template Two:</span><br><span class="line"></span><br><span class="line">&quot;right camera&quot;</span><br><span class="line">Template Three:</span><br><span class="line"></span><br><span class="line">&quot;camera to the right of laptop&quot;</span><br><span class="line">Template Four:</span><br><span class="line"></span><br><span class="line">&quot;3rd camera from left&quot;</span><br><span class="line">These instructions describe the positional relationships of the camera relative to other objects in the scene using the specified templates.</span><br></pre></td></tr></table></figure><h3 id="5"><a href="#5" class="headerlink" title="5."></a>5.</h3><p>Sure, let’s generate appropriate instructions based on all the objects and expand to create more colorful and diverse templates for each template style.</p><h3 id="Object-Descriptions"><a href="#Object-Descriptions" class="headerlink" title="Object Descriptions:"></a>Object Descriptions:</h3><ol><li>Mug (ID: 6)</li><li>Laptop (ID: 5)</li><li>Bowl (ID: 2)</li><li>Camera (ID: 3)</li><li>Can (ID: 4)</li></ol><h3 id="Template-One"><a href="#Template-One" class="headerlink" title="Template One:"></a>Template One:</h3><ol><li>Mug (Object 1):<ul><li>“mug at bottom right”</li></ul></li><li>Laptop (Object 2):<ul><li>“laptop at top right”</li></ul></li><li>Bowl (Object 3):<ul><li>“bowl at top left”</li></ul></li><li>Camera (Object 4):<ul><li>“camera at bottom left”</li></ul></li><li>Can (Object 5):<ul><li>“can at center”</li></ul></li></ol><h3 id="Template-Two"><a href="#Template-Two" class="headerlink" title="Template Two:"></a>Template Two:</h3><ol><li>Mug (Object 1):<ul><li>“bottom right mug”</li></ul></li><li>Laptop (Object 2):<ul><li>“top right laptop”</li></ul></li><li>Bowl (Object 3):<ul><li>“top left bowl”</li></ul></li><li>Camera (Object 4):<ul><li>“bottom left camera”</li></ul></li><li>Can (Object 5):<ul><li>“center can”</li></ul></li></ol><h3 id="Template-Three"><a href="#Template-Three" class="headerlink" title="Template Three:"></a>Template Three:</h3><ol><li>Mug (Object 1):<ul><li>“mug to the right of can”</li></ul></li><li>Laptop (Object 2):<ul><li>“laptop to the left of mug”</li></ul></li><li>Bowl (Object 3):<ul><li>“bowl in front of laptop”</li></ul></li><li>Camera (Object 4):<ul><li>“camera behind bowl”</li></ul></li><li>Can (Object 5):<ul><li>“can at the top of laptop”</li></ul></li></ol><h3 id="Template-Four"><a href="#Template-Four" class="headerlink" title="Template Four:"></a>Template Four:</h3><ol><li>Mug (Object 1):<ul><li>“1st mug from left”</li></ul></li><li>Laptop (Object 2):<ul><li>“2nd laptop from right”</li></ul></li><li>Bowl (Object 3):<ul><li>“3rd bowl from top”</li></ul></li><li>Camera (Object 4):<ul><li>“4th camera from bottom”</li></ul></li><li>Can (Object 5):<ul><li>“5th can from center”</li></ul></li></ol><p>These instructions describe the positional relationships of each object using all the four templates. They are diverse and colorful, providing various ways to describe the spatial relationships between the objects.</p>]]></content>
    
    
    <summary type="html">本篇博客记录prompt learning。</summary>
    
    
    
    <category term="Prompt" scheme="http://example.com/categories/Prompt/"/>
    
    
    <category term="Study" scheme="http://example.com/tags/Study/"/>
    
  </entry>
  
  <entry>
    <title>MySQL 摘抄</title>
    <link href="http://example.com/2024/04/06/Study/MySQL/MySQL/"/>
    <id>http://example.com/2024/04/06/Study/MySQL/MySQL/</id>
    <published>2024-04-06T00:00:00.000Z</published>
    <updated>2024-04-06T02:49:07.091Z</updated>
    
    <content type="html"><![CDATA[<p>本人很懒，不多介绍！</p><span id="more"></span><h2 id="01- 基础架构：一条 SQL 查询语句是如何执行的？"><a href="#01- 基础架构：一条 SQL 查询语句是如何执行的？" class="headerlink" title="01 | 基础架构：一条 SQL 查询语句是如何执行的？"></a>01 | 基础架构：一条 SQL 查询语句是如何执行的？</h2><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404021545606.png" alt="img" style="zoom: 33%;" /><p>大体来说，MySQL 可以分为 Server 层和存储引擎层两部分。Server 层包括连接器、查询缓存、分析器、优化器、执行器等，涵盖 MySQL 的大多数核心服务功能，以及所有的内置函数（如日期、时间、数学和加密函数等），所有跨存储引擎的功能都在这一层实现，比如存储过程、触发器、视图等。</p><p>而存储引擎层负责数据的存储和提取。其架构模式是插件式的，支持 InnoDB、MyISAM、Memory 等多个存储引擎。现在最常用的存储引擎是 InnoDB，它从 MySQL 5.5.5 版本开始成为了默认存储引擎。</p><p>也就是说，你执行 create table 建表的时候，如果不指定引擎类型，默认使用的就是 InnoDB。不过，你也可以通过指定存储引擎的类型来选择别的引擎，比如在 create table 语句中使用 engine&#x3D;memory, 来指定使用内存引擎创建表。不同存储引擎的表数据存取方式不同，支持的功能也不同，在后面的文章中，我们会讨论到引擎的选择。</p><h3 id="连接器"><a href="# 连接器" class="headerlink" title="连接器"></a>连接器 </h3><p> 第一步，你会先连接到这个数据库上，这时候接待你的就是连接器。连接器负责跟客户端建立连接、获取权限、维持和管理连接。连接命令一般是这么写的：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql -h$ip -P$port -u$user -p</span><br></pre></td></tr></table></figure><p>输完命令之后，你就需要在交互对话里面输入密码。虽然密码也可以直接跟在 -p 后面写在命令行中，但这样可能会导致你的密码泄露。如果你连的是生产服务器，强烈建议你不要这么做。</p><p>连接命令中的 mysql 是客户端工具，用来跟服务端建立连接。在完成经典的 TCP 握手后，连接器就要开始认证你的身份，这个时候用的就是你输入的用户名和密码。</p><p><strong>如果用户名或密码不对，你就会收到一个”Access denied for user”的错误 </strong>，然后客户端程序结束执行。如果用户名密码认证通过，连接器会到权限表里面查出你拥有的权限。之后，<strong> 这个连接里面的权限判断逻辑，都将依赖于此时读到的权限</strong>。</p><p>这就意味着，一个用户成功建立连接后，即使你用管理员账号对这个用户的权限做了修改，也不会影响已经存在连接的权限。修改完成后，只有再新建的连接才会使用新的权限设置。</p><p>连接完成后，如果你没有后续的动作，这个连接就处于空闲状态，你可以在 <strong>show processlist</strong> 命令中看到它。文本中这个图是 show processlist 的结果，其中的 Command 列显示为“<strong>Sleep</strong>”的这一行，就表示现在系统里面有一个空闲连接。</p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404021551355.png" alt="img"></p><p>客户端如果太长时间没动静，连接器就会自动将它断开。这个时间是由参数 <strong>wait_timeout</strong> 控制的，默认值是 <strong>8 小时</strong>。</p><p>如果在连接被断开之后，客户端再次发送请求的话，就会收到一个错误提醒： <strong>Lost connection to MySQL server during query</strong>。这时候如果 <strong> 你要继续，就需要重连，然后再执行请求了。</strong></p><p>数据库里面，<strong>长连接 </strong> 是指连接成功后，如果客户端持续有请求，则一直使用同一个连接。<strong>短连接 </strong> 则是指每次执行完很少的几次查询就断开连接，下次查询再重新建立一个。建立连接的过程通常是比较复杂的，所以我建议你在使用中要尽量减少建立连接的动作，也就是 <strong> 尽量使用长连接。</strong></p><p>但是全部使用长连接后，你可能会发现，有些时候 MySQL 占用内存涨得特别快，这是因为 MySQL 在执行过程中临时使用的内存是管理在连接对象里面的。这些资源会在连接断开的时候才释放。所以如果长连接累积下来，可能导致 <strong> 内存占用太大 </strong>，被系统强行杀掉<strong>（OOM）</strong>，从现象看就是 <strong>MySQL 异常重启</strong> 了。</p><p><strong>怎么解决这个问题呢？你可以考虑以下两种方案。</strong></p><p><strong>定期断开长连接。使用一段时间，或者程序里面判断执行过一个占用内存的大查询后，断开连接，之后要查询再重连。</strong></p><p><strong>如果你用的是 MySQL 5.7 或更新版本，可以在每次执行一个比较大的操作后，通过执行 mysql_reset_connection 来重新初始化连接资源。这个过程不需要重连和重新做权限验证，但是会将连接恢复到刚刚创建完时的状态。</strong></p><h3 id="查询缓存"><a href="# 查询缓存" class="headerlink" title="查询缓存"></a>查询缓存</h3><p>MySQL 拿到一个查询请求后，会先到查询缓存看看，之前是不是执行过这条语句。之前执行过的语句及其结果可能会以 <strong>key-value</strong> 对的形式，被直接缓存在内存中。key 是查询的语句，value 是查询的结果。如果你的查询能够直接在这个缓存中找到 key，那么这个 value 就会被直接返回给客户端。</p><p>如果语句不在查询缓存中，就会继续后面的执行阶段。执行完成后，执行结果会被存入查询缓存中。你可以看到，如果 <strong> 查询命中缓存，MySQL 不需要执行后面的复杂操作，</strong>就可以直接返回结果，这个效率会很高。</p><p><strong>但是大多数情况下我会建议你不要使用查询缓存，为什么呢？因为查询缓存往往弊大于利。</strong></p><p>查询缓存的失效非常频繁，只要有对一个表的更新，这个表上所有的查询缓存都会被清空。因此很可能你费劲地把结果存起来，还没使用呢，就被一个更新全清空了。对于更新压力大的数据库来说，查询缓存的命中率会非常低。<strong>除非你的业务就是有一张静态表，很长时间才会更新一次。比如，一个系统配置表，那这张表上的查询才适合使用查询缓存。</strong></p><p>好在 MySQL 也提供了这种“按需使用”的方式。你可以将参数 <strong>query_cache_type</strong> 设置成 <strong>DEMAND</strong>，这样对于 <strong> 默认的 SQL 语句都不使用查询缓存。而对于你确定要使用查询缓存的语句，可以用 SQL_CACHE 显式指定</strong>，像下面这个语句一样：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql&gt; select SQL_CACHE * from T where ID=10；</span><br></pre></td></tr></table></figure><p><strong>需要注意的是，MySQL 8.0 版本直接将查询缓存的整块功能删掉了，也就是说 8.0 开始彻底没有这个功能了。</strong></p><h3 id="分析器"><a href="# 分析器" class="headerlink" title="分析器"></a>分析器 </h3><p> 分析器先会做“<strong>词法分析</strong>”。你输入的是由多个字符串和空格组成的一条 SQL 语句，MySQL 需要识别出里面的字符串分别是什么，代表什么。</p><p>MySQL 从你输入的”select”这个关键字识别出来，这是一个查询语句。它也要把字符串“T”识别成“表名 T”，把字符串“ID”识别成“列 ID”。</p><p>做完了这些识别以后，就要做“<strong>语法分析</strong>”。根据词法分析的结果，语法分析器会根据语法规则，判断你输入的这个 SQL 语句是否满足 MySQL 语法。</p><p>如果你的语句不对，就会收到“<strong>You have an error in your SQL syntax</strong>”的错误提醒，比如下面这个语句 select 少打了开头的字母“s”。</p><p>一般语法错误会提示第一个出现错误的位置，所以你要关注的是紧接“use near”的内容。</p><h3 id="优化器"><a href="# 优化器" class="headerlink" title="优化器"></a>优化器 </h3><p> 优化器是在表里面有多个索引的时候，决定使用哪个索引；或者在一个语句有多表关联（join）的时候，决定各个表的连接顺序。比如你执行下面这样的语句，这个语句是执行两个表的 join：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql&gt; select * from t1 join t2 using(ID)  where t1.c=10 and t2.d=20;</span><br></pre></td></tr></table></figure><p>既可以先从表 t1 里面取出 c&#x3D;10 的记录的 ID 值，再根据 ID 值关联到表 t2，再判断 t2 里面 d 的值是否等于 20。</p><p>也可以先从表 t2 里面取出 d&#x3D;20 的记录的 ID 值，再根据 ID 值关联到 t1，再判断 t1 里面 c 的值是否等于 10。</p><p>这两种执行方法的逻辑结果是一样的，但是执行的效率会有不同，而优化器的作用就是决定选择使用哪一个方案。</p><h3 id="执行器"><a href="# 执行器" class="headerlink" title="执行器"></a>执行器 </h3><p> 开始执行的时候，要先判断一下你对这个表 T 有没有执行查询的 <strong> 权限</strong>，如果没有，就会返回没有权限的错误，如下所示 (在工程实现上，如果命中查询缓存，会在查询缓存返回结果的时候，做权限验证。查询也会在优化器之前调用 precheck 验证权限)。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mysql&gt; select * from T where ID=10;</span><br><span class="line">ERROR 1142 (42000): SELECT command denied to user &#x27;b&#x27;@&#x27;localhost&#x27; for table &#x27;T&#x27;</span><br></pre></td></tr></table></figure><p>如果有权限，就打开表继续执行。打开表的时候，执行器就会根据表的引擎定义，去使用这个引擎提供的接口。</p><p>比如我们这个例子中的表 T 中，ID 字段没有索引，那么执行器的执行流程是这样的：</p><p>调用 InnoDB 引擎接口取这个表的第一行，判断 ID 值是不是 10，如果不是则跳过，如果是则将这行存在结果集中；</p><p>调用引擎接口取“下一行”，重复相同的判断逻辑，直到取到这个表的最后一行。</p><p>执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。</p><p>对于有索引的表，执行的逻辑也差不多。第一次调用的是“取满足条件的第一行”这个接口，之后循环取“满足条件的下一行”这个接口，这些接口都是引擎中已经定义好的。你会在数据库的慢查询日志中看到一个 <strong>rows_examined</strong> 的字段，表示这个语句执行过程中扫描了多少行。这个值就是 <strong> 在执行器每次调用引擎获取数据行的时候累加的</strong>。</p><p>在有些场景下，执行器调用一次，在引擎内部则扫描了多行，因此 <strong> 引擎扫描行数跟 rows_examined 并不是完全相同的</strong>。我们后面会专门有一篇文章来讲存储引擎的内部机制，里面会有详细的说明。</p><h3 id="问题："><a href="# 问题：" class="headerlink" title="问题："></a>问题：</h3><p>我给你留一个问题吧，如果表 T 中没有字段 k，而你执行了这个语句 select * from T where k&#x3D;1, 那肯定是会报“不存在这个列”的错误： “Unknown column ‘k’ in ‘where clause’”。你觉得这个错误是在我们上面提到的哪个阶段报出来的呢？</p><h2 id="02- 日志系统：一条 SQL 更新语句是如何执行的？"><a href="#02- 日志系统：一条 SQL 更新语句是如何执行的？" class="headerlink" title="02 | 日志系统：一条 SQL 更新语句是如何执行的？"></a>02 | 日志系统：一条 SQL 更新语句是如何执行的？</h2><p>一条查询语句的执行过程一般是经过连接器、分析器、优化器、执行器等功能模块，最后到达存储引擎。</p><p>那么，一条更新语句的执行流程又是怎样的呢？</p><p>MySQL 可以恢复到半个月内任意一秒的状态，惊叹的同时，你是不是心中也会不免会好奇，这是怎样做到的呢？</p><p>我们还是从一个表的一条更新语句说起，下面是这个表的创建语句，这个表有一个主键 ID 和一个整型字段 c：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql&gt; create table T(ID int primary key, c int);</span><br></pre></td></tr></table></figure><p>如果要将 ID&#x3D;2 这一行的值加 1，SQL 语句就会这么写：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql&gt; update T set c=c+1 where ID=2;</span><br></pre></td></tr></table></figure><p><strong>查询语句的那一套流程，更新语句也是同样会走一遍。</strong></p><p>你执行语句前要先连接数据库，这是连接器的工作。</p><p>前面我们说过，在一个表上有更新的时候，跟这个表有关的查询缓存会失效，所以这条语句就会把表 T 上所有缓存结果都清空。这也就是我们一般不建议使用查询缓存的原因。</p><p>接下来，分析器会通过词法和语法解析知道这是一条更新语句。优化器决定要使用 ID 这个索引。然后，执行器负责具体执行，找到这一行，然后更新。</p><p>与查询流程不一样的是，更新流程还涉及两个重要的日志模块，它们正是我们今天要讨论的主角：<strong>redo log（重做日志）</strong>和 <strong>binlog（归档日志）</strong>。如果接触 MySQL，那这两个词肯定是绕不过的，我后面的内容里也会不断地和你强调。不过话说回来，redo log 和 binlog 在设计上有很多有意思的地方，这些设计思路也可以用到你自己的程序里。</p><h3 id="重要的日志模块：redo-log"><a href="# 重要的日志模块：redo-log" class="headerlink" title="重要的日志模块：redo log"></a>重要的日志模块：redo log</h3><p>如果每一次的更新操作都需要写进磁盘，然后磁盘也要找到对应的那条记录，然后再更新，整个过程 IO 成本、查找成本都很高。为了解决这个问题，MySQL 的设计者就用了类似 <strong> 酒店掌柜粉板的思路 </strong> 来提升更新效率。</p><p>而粉板和账本配合的整个过程，其实就是 MySQL 里经常说到的 <strong>WAL 技术 </strong>，<strong>WAL 的全称是 Write-Ahead Logging</strong>，它的关键点就是<strong> 先写日志，再写磁盘</strong>，也就是先写粉板，等不忙的时候再写账本。</p><p>当有一条记录需要更新的时候，InnoDB 引擎就会先把记录写到 redo log（粉板）里面，并更新内存，这个时候更新就算完成了。同时，InnoDB 引擎会在适当的时候，将这个操作记录更新到磁盘里面，而这个更新往往是在系统比较空闲的时候做，这就像打烊以后掌柜做的事。</p><p>如果今天赊账的不多，掌柜可以等打烊后再整理。但如果某天赊账的特别多，粉板写满了，又怎么办呢？这个时候掌柜只好放下手中的活儿，把粉板中的一部分赊账记录更新到账本中，然后把这些记录从粉板上擦掉，为记新账腾出空间。</p><p>与此类似，<strong>InnoDB 的 redo log 是固定大小的，比如可以配置为一组 4 个文件，每个文件的大小是 1GB，那么这块“粉板”总共就可以记录 4GB 的操作。</strong>从头开始写，<strong>写到末尾就又回到开头循环写</strong>，如下面这个图所示。</p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404021652827.png" alt="img" style="zoom: 33%;" /><p>write pos 是当前记录的位置，一边写一边后移，写到第 3 号文件末尾后就回到 0 号文件开头。checkpoint 是当前要擦除的位置，也是往后推移并且循环的，擦除记录前要把记录更新到数据文件。</p><p>write pos 和 checkpoint 之间的是“粉板”上还空着的部分，可以用来记录新的操作。如果 write pos 追上 checkpoint，表示“粉板”满了，这时候不能再执行新的更新，得停下来先擦掉一些记录，把 checkpoint 推进一下。</p><p><strong>循环队列</strong></p><p><strong>有了 redo log，InnoDB 就可以保证即使数据库发生异常重启，之前提交的记录都不会丢失，这个能力称为 crash-safe。</strong></p><h3 id="重要的日志模块：binlog"><a href="# 重要的日志模块：binlog" class="headerlink" title="重要的日志模块：binlog"></a>重要的日志模块：binlog</h3><p>粉板 redo log 是 InnoDB 引擎特有的日志，而 Server 层也有自己的日志，称为 binlog（归档日志）。</p><p><strong>我想你肯定会问，为什么会有两份日志呢？</strong></p><p>因为最开始 <strong>MySQL 里并没有 InnoDB 引擎</strong>。<strong>MySQL 自带的引擎是 MyISAM</strong>，但是 <strong>MyISAM 没有 crash-safe 的能力</strong>，<strong>binlog 日志只能用于归档</strong>。而 InnoDB 是另一个公司以插件形式引入 MySQL 的，既然只依靠 binlog 是没有 crash-safe 能力的，所以 InnoDB 使用另外一套日志系统——也就是 redo log 来实现 crash-safe 能力。</p><p><strong>这两种日志有以下三点不同</strong>：</p><p>redo log 是 InnoDB 引擎特有的；binlog 是 MySQL 的 Server 层实现的，所有引擎都可以使用。</p><p>redo log 是物理日志，记录的是“<strong>在某个数据页上做了什么修改 </strong>”；binlog 是逻辑日志，记录的是这个语句的<strong> 原始逻辑</strong>，比如“给 ID&#x3D;2 这一行的 c 字段加 1 ”。</p><p>redo log 是 <strong> 循环写的 </strong>，空间固定会用完；binlog 是可以<strong> 追加写入 </strong> 的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个，并不会覆盖以前的日志。</p><p>有了对这两个日志的概念性理解，我们再来看执行器和 InnoDB 引擎在执行这个简单的 update 语句时的内部流程。</p><p>执行器先找引擎取 ID&#x3D;2 这一行。ID 是主键，引擎直接用树搜索找到这一行。如果 ID&#x3D;2 这一行所在的数据页本来就在内存中，就直接返回给执行器；否则，需要先从磁盘读入内存，然后再返回。</p><p>执行器拿到引擎给的行数据，把这个值加上 1，比如原来是 N，现在就是 N+1，得到新的一行数据，再调用引擎接口写入这行新数据。</p><p>引擎将这行新数据更新到内存中，同时将这个更新操作记录到 redo log 里面，此时 redo log 处于 prepare 状态。然后告知执行器执行完成了，随时可以提交事务。</p><p>执行器生成这个操作的 binlog，并把 binlog 写入磁盘。执行器调用引擎的提交事务接口，引擎把刚刚写入的 redo log 改成提交（commit）状态，更新完成。</p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404021659118.png" alt="img" style="zoom: 50%;" /><p>你可能注意到了，最后三步看上去有点“绕”，将 redo log 的写入拆成了两个步骤：prepare 和 commit，这就是”两阶段提交”。</p><h3 id="两阶段提交"><a href="# 两阶段提交" class="headerlink" title="两阶段提交"></a>两阶段提交 </h3><p> 为什么必须有“两阶段提交”呢？这是为了让两份日志之间的逻辑一致。要说明这个问题，我们得从文章开头的那个问题说起：怎样让数据库恢复到半个月内任意一秒的状态？</p><p>前面我们说过了，binlog 会记录所有的逻辑操作，并且是采用“追加写”的形式。如果你的 DBA 承诺说半个月内可以恢复，那么备份系统中一定会保存最近半个月的所有 binlog，同时系统会定期做整库备份。这里的“定期”取决于系统的重要性，可以是一天一备，也可以是一周一备。</p><p>当需要恢复到指定的某一秒时，比如某天下午两点发现中午十二点有一次误删表，需要找回数据，那你可以这么做：</p><ul><li>首先，找到最近的一次全量备份，如果你运气好，可能就是昨天晚上的一个备份，从这个备份恢复到临时库；</li><li>然后，从备份的时间点开始，将备份的 binlog 依次取出来，重放到中午误删表之前的那个时刻。</li></ul><p>这样你的临时库就跟误删之前的线上库一样了，然后你可以把表数据从临时库取出来，按需要恢复到线上库去。</p><p><strong>为什么日志需要“两阶段提交”</strong>。这里不妨用 <strong> 反证法 </strong> 来进行解释。</p><p>由于 redo log 和 binlog 是两个独立的逻辑，如果不用两阶段提交，要么就是 <strong> 先写完 redo log 再写 binlog</strong>，或者采用反过来的顺序。我们看看这两种方式会有什么问题。</p><p>假设当前 ID&#x3D;2 的行，字段 c 的值是 0，再假设执行 update 语句过程中在写完第一个日志后，第二个日志还没有写完期间发生了 crash，会出现什么情况呢？</p><p><strong>先写 redo log 后写 binlog。</strong>假设在 redo log 写完，binlog 还没有写完的时候，MySQL 进程异常重启。由于我们前面说过的，redo log 写完之后，系统即使崩溃，仍然能够把数据恢复回来，所以恢复后这一行 c 的值是 1。</p><p>但是由于 binlog 没写完就 crash 了，这时候 binlog 里面就没有记录这个语句。因此，之后备份日志的时候，存起来的 binlog 里面就没有这条语句。</p><p>然后你会发现，如果需要用这个 binlog 来恢复临时库的话，由于这个语句的 binlog 丢失，这个临时库就会少了这一次更新，恢复出来的这一行 c 的值就是 0，与原库的值不同。</p><p><strong>先写 binlog 后写 redo log。</strong>如果在 binlog 写完之后 crash，由于 redo log 还没写，崩溃恢复以后这个事务无效，所以这一行 c 的值是 0。但是 binlog 里面已经记录了“把 c 从 0 改成 1”这个日志。所以，在之后用 binlog 来恢复的时候就多了一个事务出来，恢复出来的这一行 c 的值就是 1，与原库的值不同。</p><p>可以看到，如果不使用“两阶段提交”，那么数据库的状态就有可能和用它的日志恢复出来的库的状态不一致。</p><p>你可能会说，这个概率是不是很低，平时也没有什么动不动就需要恢复临时库的场景呀？</p><p>其实不是的，不只是误操作后需要用这个过程来恢复数据。当你需要 <strong> 扩容的时候</strong>，也就是需要再多搭建一些备库来增加系统的读能力的时候，现在常见的做法也是用全量备份加上应用 binlog 来实现的，这个“不一致”就会导致你的线上出现主从数据库不一致的情况。</p><p><strong>简单说，redo log 和 binlog 都可以用于表示事务的提交状态，而两阶段提交就是让这两个状态保持逻辑上的一致。</strong></p><p><strong>总结：</strong></p><p>今天，我介绍了 MySQL 里面最重要的两个日志，即物理日志 redo log 和逻辑日志 binlog。</p><p>redo log 用于保证 crash-safe 能力。innodb_flush_log_at_trx_commit 这个参数设置成 1 的时候，表示每次事务的 redo log 都直接持久化到磁盘。这个参数我建议你设置成 1，这样可以保证 MySQL 异常重启之后数据不丢失。</p><p>sync_binlog 这个参数设置成 1 的时候，表示每次事务的 binlog 都持久化到磁盘。这个参数我也建议你设置成 1，这样可以保证 MySQL 异常重启之后 binlog 不丢失。</p><p>我还跟你介绍了与 MySQL 日志系统密切相关的“两阶段提交”。两阶段提交是跨系统维持数据逻辑一致性时常用的一个方案，即使你不做数据库内核开发，日常开发中也有可能会用到。</p><p>文章的最后，我给你留一个思考题吧。前面我说到定期全量备份的周期“取决于系统重要性，有的是一天一备，有的是一周一备”。那么在什么场景下，一天一备会比一周一备更有优势呢？或者说，它影响了这个数据库系统的哪个指标？</p><h2 id="03- 事务隔离：为什么你改了我还看不见？"><a href="#03- 事务隔离：为什么你改了我还看不见？" class="headerlink" title="03 | 事务隔离：为什么你改了我还看不见？"></a>03 | 事务隔离：为什么你改了我还看不见？</h2><p>提到事务，你肯定不陌生，和数据库打交道的时候，我们总是会用到事务。最经典的例子就是转账，你要给朋友小王转 100 块钱，而此时你的银行卡只有 100 块钱。</p><p>转账过程具体到程序里会有一系列的操作，比如查询余额、做加减法、更新余额等，这些操作必须保证是一体的，不然等程序查完之后，还没做减法之前，你这 100 块钱，完全可以借着这个时间差再查一次，然后再给另外一个朋友转账，如果银行这么整，不就乱了么？这时就要用到“事务”这个概念了。</p><p>简单来说，<strong>事务就是要保证一组数据库操作，要么全部成功，要么全部失败。</strong>在 MySQL 中，事务支持是在引擎层实现的。你现在知道，MySQL 是一个支持多引擎的系统，但并不是所有的引擎都支持事务。比如 <strong>MySQL 原生的 MyISAM 引擎就不支持事务 </strong>，<strong> 这也是 MyISAM 被 InnoDB 取代的重要原因之一</strong>。</p><h3 id="隔离性与隔离级别"><a href="# 隔离性与隔离级别" class="headerlink" title="隔离性与隔离级别"></a>隔离性与隔离级别 </h3><p> 提到事务，你肯定会想到 ACID（Atomicity、Consistency、Isolation、Durability，即原子性、一致性、隔离性、持久性），今天我们就来说说其中 I，也就是“隔离性”。</p><p>当数据库上有多个事务同时执行的时候，就可能出现 <strong> 脏读（dirty read）（读写）、不可重复读（non-repeatable read）（两次读和一次写）、幻读（phantom read）（两次写和一次读）</strong>的问题，为了解决这些问题，就有了“隔离级别”的概念。</p><p>在谈隔离级别之前，你首先要知道，<strong>你隔离得越严实，效率就会越低。因此很多时候，我们都要在二者之间寻找一个平衡点。</strong>SQL 标准的事务隔离级别包括：读未提交（read uncommitted）、读提交（read committed）、可重复读（repeatable read）和串行化（serializable ）。下面我逐一为你解释：</p><p>读未提交是指，一个事务还没提交时，它做的变更就能被别的事务看到。</p><p>读提交是指，<strong>一个事务提交之后，它做的变更才会被其他事务看到。</strong></p><p>可重复读是指，<strong>一个事务执行过程中看到的数据，总是跟这个事务在启动时看到的数据是一致的。</strong>当然在可重复读隔离级别下，未提交变更对其他事务也是不可见的。</p><p>串行化，顾名思义是对于同一行记录，“写”会加“写锁”，“读”会加“读锁”。当出现读写锁冲突的时候，后访问的事务必须等前一个事务执行完成，才能继续执行。</p><p>其中“读提交”和“可重复读”比较难理解，所以我用一个例子说明这几种隔离级别。假设数据表 T 中只有一列，其中一行的值为 1，下面是按照时间顺序执行两个事务的行为。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mysql&gt; create table T(c int) engine=InnoDB;</span><br><span class="line">insert into T(c) values(1);</span><br></pre></td></tr></table></figure><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404022213565.png" alt="img" style="zoom: 33%;" /><p>我们来看看在不同的隔离级别下，事务 A 会有哪些不同的返回结果，也就是图里面 V1、V2、V3 的返回值分别是什么。</p><p>若隔离级别是“读未提交”， 则 V1 的值就是 2。这时候事务 B 虽然还没有提交，但是结果已经被 A 看到了。因此，V2、V3 也都是 2。</p><p>若隔离级别是“读提交”，则 V1 是 1，V2 的值是 2。事务 B 的更新在提交后才能被 A 看到。所以， V3 的值也是 2。</p><p>若隔离级别是“可重复读”，则 V1、V2 是 1，V3 是 2。之所以 V2 还是 1，遵循的就是这个要求：事务在执行期间看到的数据前后必须是一致的。</p><p>若隔离级别是“串行化”，则在事务 B 执行“将 1 改成 2”的时候，会被锁住。直到事务 A 提交后，事务 B 才可以继续执行。所以从 A 的角度看， V1、V2 值是 1，V3 的值是 2。</p><p><strong>在实现上，数据库里面会创建一个视图，访问的时候以视图的逻辑结果为准。在“可重复读”隔离级别下，这个视图是在事务启动时创建的，整个事务存在期间都用这个视图。在“读提交”隔离级别下，这个视图是在每个 SQL 语句开始执行的时候创建的。这里需要注意的是，“读未提交”隔离级别下直接返回记录上的最新值，没有视图概念；而“串行化”隔离级别下直接用加锁的方式来避免并行访问。</strong></p><p><strong>我们可以看到在不同的隔离级别下，数据库行为是有所不同的。Oracle 数据库的默认隔离级别其实就是“读提交”，因此对于一些从 Oracle 迁移到 MySQL 的应用，为保证数据库隔离级别的一致，你一定要记得将 MySQL 的隔离级别设置为“读提交”。</strong></p><p>配置的方式是，将启动参数 <strong>transaction-isolation 的值设置成 READ-COMMITTED</strong>。你可以用 show variables 来查看当前的值。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">mysql&gt; show variables like &#x27;transaction_isolation&#x27;;</span><br><span class="line"></span><br><span class="line">+-----------------------+----------------+</span><br><span class="line"></span><br><span class="line">| Variable_name | Value |</span><br><span class="line"></span><br><span class="line">+-----------------------+----------------+</span><br><span class="line"></span><br><span class="line">| transaction_isolation | READ-COMMITTED |</span><br><span class="line"></span><br><span class="line">+-----------------------+----------------+</span><br></pre></td></tr></table></figure><p>总结来说，存在即合理，每种隔离级别都有自己的使用场景，你要根据自己的业务情况来定。</p><p>我想你可能会问那什么时候需要“可重复读”的场景呢？</p><p><strong>我们来看一个数据校对逻辑的案例。假设你在管理一个个人银行账户表。一个表存了账户余额，一个表存了账单明细。到了月底你要做数据校对，也就是判断上个月的余额和当前余额的差额，是否与本月的账单明细一致。你一定希望在校对过程中，即使有用户发生了一笔新的交易，也不影响你的校对结果。这时候使用“可重复读”隔离级别就很方便。事务启动时的视图可以认为是静态的，不受其他事务更新的影响。</strong></p><h3 id="事务隔离的实现"><a href="# 事务隔离的实现" class="headerlink" title="事务隔离的实现"></a>事务隔离的实现 </h3><p> 在 MySQL 中，实际上每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值，通过回滚操作，都可以得到前一个状态的值。</p><p>假设一个值从 1 被按顺序改成了 2、3、4，在回滚日志里面就会有类似下面的记录。</p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404031646698.png" alt="img" style="zoom: 50%;" /><p>当前值是 4，但是 <strong> 在查询这条记录的时候，不同时刻启动的事务会有不同的 read-view。如图中看到的，在视图 A、B、C 里面，这一个记录的值分别是 1、2、4，同一条记录在系统中可以存在多个版本，就是数据库的多版本并发控制（MVCC）</strong>。对于 read-view A，要得到 1，就必须将当前值依次执行图中所有的回滚操作得到。</p><p>同时你会发现，即使现在有另外一个事务正在将 4 改成 5，这个事务跟 read-view A、B、C 对应的事务是不会冲突的。</p><p>你一定会问，回滚日志总不能一直保留吧，什么时候删除呢？答案是，在不需要的时候才删除。也就是说，系统会判断，当没有事务再需要用到这些回滚日志时，回滚日志会被删除。</p><p>什么时候才不需要了呢？就是 <strong> 当系统里没有比这个回滚日志更早的 read-view 的时候</strong>。</p><p>基于上面的说明，我们来讨论一下为什么建议你 <strong> 尽量不要使用长事务。</strong></p><p>长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的任何数据，所以这个事务提交之前，数据库里面它可能用到的回滚记录都必须保留，这就会 <strong> 导致大量占用存储空间</strong>。</p><p>在 MySQL 5.5 及以前的版本，回滚日志是跟数据字典一起放在 ibdata 文件里的，即使长事务最终提交，回滚段被清理，文件也不会变小。我见过数据只有 20GB，而回滚段有 200GB 的库。最终只好为了清理回滚段，重建整个库。</p><p>除了对回滚段的影响，长事务还占用锁资源，也可能拖垮整个库，这个我们会在后面讲锁的时候展开。</p><h3 id="事务的启动方式"><a href="# 事务的启动方式" class="headerlink" title="事务的启动方式"></a>事务的启动方式 </h3><p> 如前面所述，长事务有这些潜在风险，我当然是建议你尽量避免。其实很多时候业务开发同学并不是有意使用长事务，通常是由于误用所致。</p><p>MySQL 的事务启动方式有以下几种：</p><p>1. 显式启动事务语句， begin 或 start transaction。配套的提交语句是 commit，回滚语句是 rollback。</p><p>2.set autocommit&#x3D;0，这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个 select 语句，这个事务就启动了，而且并不会自动提交。这个事务持续存在直到你主动执行 commit 或 rollback 语句，或者断开连接。</p><p>有些客户端连接框架会默认连接成功后先执行一个 set autocommit&#x3D;0 的命令。这就导致接下来的查询都在事务中，如果是长连接，就导致了意外的长事务。</p><p>因此，我会建议你总是使用 set autocommit&#x3D;1, 通过显式语句的方式来启动事务。</p><p>但是有的开发同学会纠结“多一次交互”的问题。对于一个需要频繁使用事务的业务，第二种方式每个事务在开始时都不需要主动执行一次 “begin”，减少了语句的交互次数。如果你也有这个顾虑，我建议你使用 commit work and chain 语法。</p><p>在 autocommit 为 1 的情况下，用 begin 显式启动的事务，如果执行 commit 则提交事务。如果执行 commit work and chain，则是提交事务并自动启动下一个事务，这样也省去了再次执行 begin 语句的开销。同时带来的好处是从程序开发的角度明确地知道每个语句是否处于事务中。</p><p>你可以在 <strong>information_schema 库的 innodb_trx 这个表中查询长事务</strong>，比如下面这个语句，用于查找持续时间超过 60s 的事务。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))&gt;60</span><br></pre></td></tr></table></figure><p>这篇文章里面，我介绍了 MySQL 的事务隔离级别的现象和实现，根据实现原理分析了长事务存在的风险，以及如何用正确的方式避免长事务。希望我举的例子能够帮助你理解事务，并更好地使用 MySQL 的事务特性。</p><h2 id="04- 深入浅出索引（上）"><a href="#04- 深入浅出索引（上）" class="headerlink" title="04 | 深入浅出索引（上）"></a>04 | 深入浅出索引（上）</h2><p>提到数据库索引，我想你并不陌生，在日常工作中会经常接触到。<strong>比如某一个 SQL 查询比较慢，分析完原因之后，你可能就会说“给某个字段加个索引吧”之类的解决方案。</strong>但到底什么是索引，索引又是如何工作的呢？</p><p>数据库索引的内容比较多，我分成了上下两篇文章。索引是数据库系统里面最重要的概念之一，所以我希望你能够耐心看完。在后面的实战文章中，我也会经常引用这两篇文章中提到的知识点，加深你对数据库索引的理解。</p><p>一句话简单来说，<strong>索引的出现其实就是为了提高数据查询的效率，就像书的目录一样。</strong>一本 500 页的书，如果你想快速找到其中的某一个知识点，在不借助目录的情况下，那我估计你可得找一会儿。同样，对于数据库的表而言，<strong>索引其实就是它的“目录”。</strong></p><h3 id="索引的常见模型"><a href="# 索引的常见模型" class="headerlink" title="索引的常见模型"></a>索引的常见模型 </h3><p> 索引的出现是为了提高查询效率，但是实现索引的方式却有很多种，所以这里也就引入了 <strong> 索引模型 </strong> 的概念。可以用于提高读写效率的数据结构很多，这里我先给你介绍三种常见、也比较简单的数据结构，它们分别是 <strong> 哈希表、有序数组和搜索树</strong>。</p><p>下面我主要从使用的角度，为你简单分析一下这三种模型的区别。</p><h4 id="哈希表"><a href="# 哈希表" class="headerlink" title="哈希表"></a>哈希表 </h4><p> 哈希表是一种以 <strong> 键 - 值（key-value）</strong>存储数据的结构，我们只要输入待查找的键即 key，就可以找到其对应的值即 Value。哈希的思路很简单，把值放在数组里，用一个哈希函数把 key 换算成一个确定的位置，然后把 value 放在数组的这个位置。</p><p>不可避免地，多个 key 值经过哈希函数的换算，会出现同一个值的情况。处理这种情况的一种方法是，拉出一个链表。假设，你现在维护着一个身份证信息和姓名的表，需要根据身份证号查找对应的名字，这时对应的哈希索引的示意图如下所示：</p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404031732990.png" alt="img" style="zoom:50%;" /><p>图中，User2 和 User4 根据身份证号算出来的值都是 N，但没关系，后面还跟了一个链表。假设，这时候你要查 ID_card_n2 对应的名字是什么，处理步骤就是：首先，将 ID_card_n2 通过哈希函数算出 N；然后，按顺序遍历，找到 User2。</p><p>需要注意的是，图中四个 ID_card_n 的值并 <strong> 不是递增的 </strong>，这样做的好处是增加新的 User 时速度会很快，<strong> 只需要往后追加。</strong>但缺点是，因为不是有序的，所以 <strong> 哈希索引做区间查询的速度是很慢的。</strong></p><p>你可以设想下，如果你现在要找身份证号在 [ID_card_X, ID_card_Y] 这个区间的所有用户，就必须全部扫描一遍了。</p><p>所以，<strong>哈希表这种结构适用于只有等值查询的场景，比如 Memcached 及其他一些 NoSQL 引擎。</strong></p><p>哈希 字典 key value </p><p>集合</p><h4 id="集合和字典有啥联系区别"><a href="# 集合和字典有啥联系区别" class="headerlink" title="集合和字典有啥联系区别"></a>集合和字典有啥联系区别 </h4><p> 集合（Set）和字典（Dictionary）都是常见的数据结构，它们在编程中有着不同的用途和特点。</p><ol><li><strong>集合（Set）</strong>：<ul><li>集合是一种无序且不重复的数据结构，它由一组唯一的元素组成。</li><li>集合中的元素没有顺序，因此不能通过索引来访问，也不能通过索引来修改元素。</li><li>集合主要用于判断一个元素是否存在于集合中，以及对集合进行交集、并集、差集等操作。</li><li>在大多数编程语言中，集合的实现通常是基于哈希表（Hash Table）或类似的数据结构。</li></ul></li><li><strong>字典（Dictionary）</strong>：<ul><li>字典是一种键值对（Key-Value Pair）的数据结构，它将键映射到值，每个键都必须是唯一的。</li><li>字典中的键是无序的，但是键值对之间的顺序是固定的（根据插入顺序或其他实现方式）。</li><li>字典通常用于存储和查找键值对数据，其中通过键来快速查找对应的值。</li><li>字典在各种编程语言中都有广泛的应用，如 Python 中的字典、JavaScript 中的对象等。</li></ul></li></ol><p>联系和区别：</p><ul><li>联系：集合和字典都是用于存储数据的数据结构，它们都支持存储不同类型的数据，并且都具有快速查找的特性。</li><li>区别：<ul><li>集合中的元素是无序的且不重复的，而字典中的键是唯一的，但值可以重复。</li><li>集合用于存储单个元素的集合，而字典用于存储键值对的集合。</li><li>集合通常用于查找和处理一组唯一的元素，而字典用于查找和处理具有特定键的值。</li></ul></li></ul><p>综上所述，集合和字典都是在编程中常用的数据结构，但它们在数据组织和使用方面有着不同的特点和用途。</p><p><strong>区别：</strong><br><strong>数据存储方式：</strong></p><p>集合是一组无序的唯一元素的集合，其中每个元素都是唯一的，没有重复的元素。<br>字典是由键 - 值对组成的集合，其中每个键都是唯一的，但值可以重复。<br>索引：</p><p>集合中的元素不能通过索引访问，因为集合是无序的。<br>字典中的元素是通过唯一的键来访问的，可以通过键来检索对应的值。</p><p><strong>联系：</strong><br><strong>可变性：</strong></p><p>集合和字典都是可变的数据结构，可以通过添加、删除和更新元素来改变它们的内容。<br>哈希表实现：</p><p>集合和字典都是通过哈希表来实现的，这使得它们在查找、插入和删除元素时具有较高的效率。</p><p><strong>集合适用于以下场景：</strong></p><p><strong>去重 </strong>：当需要从一组元素中去除重复项时，集合是一个很方便的数据结构。<br><strong> 集合操作 </strong>：集合提供了丰富的操作方法，如并集、交集、差集等，适用于对多个集合进行操作的场景。<br><strong> 成员关系测试 </strong>：集合提供了高效的成员关系测试，可以快速判断一个元素是否存在于集合中。<br><strong> 字典适用于以下场景：</strong></p><p><strong>键值对存储 </strong>：当需要将一组键与对应的值关联起来时，字典是一个理想的数据结构。<br><strong> 快速查找 </strong>：通过键来查找对应的值是字典的主要特性，适用于需要快速检索数据的场景。<br><strong> 缓存</strong>：字典可以用作缓存数据的数据结构，通过键来快速访问缓存的值，提高程序的运行效率。</p><h4 id="有序数组"><a href="# 有序数组" class="headerlink" title="有序数组"></a>有序数组 </h4><p><strong> 而有序数组在等值查询和范围查询场景中的性能就都非常优秀。</strong>还是上面这个根据身份证号查名字的例子，如果我们使用有序数组来实现的话，示意图如下所示：</p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404031810025.png" alt="img" style="zoom: 50%;" /><p>这里我们假设身份证号没有重复，这个数组就是按照身份证号递增的顺序保存的。这时候如果你要查 ID_card_n2 对应的名字，用 <strong> 二分法 </strong> 就可以快速得到，这个时间复杂度是 **O(log(N))**。</p><p>同时很显然，这个索引结构支持范围查询。你要查身份证号在 [ID_card_X, ID_card_Y] 区间的 User，可以 <strong> 先用二分法找到 ID_card_X（如果不存在 ID_card_X，就找到大于 ID_card_X 的第一个 User），然后向右遍历，直到查到第一个大于 ID_card_Y 的身份证号，退出循环。</strong></p><p>如果仅仅看查询效率，有序数组就是最好的数据结构了。但是，<strong>在需要更新数据的时候就麻烦了，你往中间插入一个记录就必须得挪动后面所有的记录，成本太高。</strong></p><p>所以，<strong>有序数组索引只适用于静态存储引擎，比如你要保存的是 2017 年某个城市的所有人口信息，这类不会再修改的数据。</strong></p><p>二叉搜索树也是课本里的经典数据结构了。还是上面根据身份证号查名字的例子，如果我们用二叉搜索树来实现的话，示意图如下所示：</p><h4 id="搜索树"><a href="# 搜索树" class="headerlink" title="搜索树"></a>搜索树 </h4><p> 二叉搜索树也是课本里的经典数据结构了。还是上面根据身份证号查名字的例子，如果我们用二叉搜索树来实现的话，示意图如下所示：</p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404031958945.png" alt="img" style="zoom:50%;" /><p>二叉搜索树的特点是：父节点左子树所有结点的值小于父节点的值，右子树所有结点的值大于父节点的值。</p><p>这样如果你要查 ID_card_n2 的话，按照图中的搜索顺序就是按照 UserA -&gt; UserC -&gt; UserF -&gt; User2 这个路径得到。这个时间复杂度是 O(log(N))。</p><p>当然为了维持 <strong>O(log(N)) 的查询复杂度 </strong>，你就需要保持这棵树是<strong> 平衡二叉树</strong>。为了做这个保证，** 更新的时间复杂度也是 O(log(N))**。</p><p>二叉树是搜索效率最高的，但是实际上大多数的数据库存储却并不使用二叉树。其原因是，索引不止存在内存中，还要写到磁盘上。树可以有二叉，也可以有多叉。<strong>多叉树就是每个节点有多个儿子，儿子之间的大小保证从左到右递增</strong>。</p><p>你可以想象一下一棵 100 万节点的平衡二叉树，树高 20。一次查询可能需要访问 20 个数据块。在机械硬盘时代，从磁盘随机读一个数据块需要 10 ms 左右的寻址时间。也就是说，对于一个 100 万行的表，如果使用二叉树来存储，单独访问一个行可能需要 20 个 10 ms 的时间，这个查询可真够慢的。</p><p>为了让一个查询尽量少地读磁盘，就必须让查询过程访问尽量少的数据块。那么，我们就不应该使用二叉树，而是要使用“N 叉”树。这里，“N 叉”树中的“N”取决于数据块的大小。</p><p>以 InnoDB 的一个整数字段索引为例，这个 N 差不多是 1200。这棵树高是 4 的时候，就可以存 1200 的 3 次方个值，这已经 17 亿了。考虑到树根的数据块总是在内存中的，一个 10 亿行的表上一个整数字段的索引，<strong>查找一个值最多只需要访问 3 次磁盘。</strong>其实，树的 <strong> 第二层也有很大概率在内存中，那么访问磁盘的平均次数就更少了。</strong></p><p>N 叉树由于在读写上的性能优点，以及适配磁盘的访问模式，已经被广泛应用在数据库引擎中了。</p><p>不管是哈希还是有序数组，或者 N 叉树，它们都是不断迭代、不断优化的产物或者解决方案。数据库技术发展到今天，跳表、LSM 树等数据结构也被用于引擎设计中，这里我就不再一一展开了。</p><p>你心里要有个概念，数据库底层存储的核心就是基于这些数据模型的。每碰到一个新数据库，我们需要先关注它的数据模型，这样才能从理论上分析出这个数据库的适用场景。</p><p>截止到这里，我用了半篇文章的篇幅和你介绍了不同的数据结构，以及它们的适用场景，你可能会觉得有些枯燥。但是，我建议你还是要多花一些时间来理解这部分内容，毕竟这是数据库处理数据的核心概念之一，在分析问题的时候会经常用到。当你理解了索引的模型后，就会发现在分析问题的时候会有一个更清晰的视角，体会到引擎设计的精妙之处。</p><h4 id="n 叉树遍历"><a href="#n 叉树遍历" class="headerlink" title="n 叉树遍历"></a>n 叉树遍历</h4><p>n 又树的遍历方式有多种，常见的有深度优先遍历和广度优先遍历。因此，n 又树遍历的时间复杂度确实存在多个正确答案。下面分别给出这两种遍历方式的时间复杂度证明。<br>1. 深度优先遍历的时间复杂度 假设 n 叉树的节点数为 N，深度为 d。由于每个节点都需要被访问一次，因此时间复杂度为 O(N)。另外，由于是通过递归或者栈实现遍历，因此空间复杂度也是 O(d)。</p><p><strong>深度优先遍历（Depth-First Search，DFS）</strong>：</p><ul><li>深度优先遍历是一种通过递归或栈的方式来遍历树的算法，其基本思想是尽可能深地搜索树的分支，直到不能继续为止，然后回溯到上一个分支继续搜索。</li><li>时间复杂度：O(N)，因为每个节点都需要被访问一次，其中 N 是树的节点数。</li><li>空间复杂度：O(d)，其中 d 是树的深度。这是由于在最坏情况下，递归调用或栈的大小与树的深度成正比。</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">class Node:</span><br><span class="line">    def __init__(self, val, children):</span><br><span class="line">        self.val = val</span><br><span class="line">        self.children = children</span><br><span class="line"></span><br><span class="line">def dfs(root: &#x27;Node&#x27;):</span><br><span class="line">    if not root:</span><br><span class="line">        return</span><br><span class="line">    # 访问当前节点</span><br><span class="line">    print(root.val)</span><br><span class="line">    # 递归遍历子节点</span><br><span class="line">    for child in root.children:</span><br><span class="line">        dfs(child)</span><br></pre></td></tr></table></figure><p>2. 广度优先遍历的时间复杂度 假设 n 叉树的节点数为 N，深度为 d。由于需要遍历每个节点一次，时间复杂度为 O(N)。另外，每次需要将当前节点的所有子节点加入队列中，因此队列的大小不会超过每层节点数的最大值，即 2^d。因此空间复杂度是 0(2^d).。<strong>广度优先遍历（Breadth-First Search，BFS）</strong>：</p><ul><li>广度优先遍历是一种通过队列的方式来遍历树的算法，其基本思想是按层级顺序逐层遍历树的节点。</li><li>时间复杂度：O(N)，因为每个节点都需要被访问一次，其中 N 是树的节点数。</li><li>空间复杂度：O(W)，其中 W 是树的最大宽度（即每层节点数的最大值）。这是因为需要使用队列来存储每层的节点。</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">from collections import deque</span><br><span class="line"></span><br><span class="line">class Node:</span><br><span class="line">    def __init__(self, val, children):</span><br><span class="line">        self.val = val</span><br><span class="line">        self.children = children</span><br><span class="line"></span><br><span class="line">def bfs(root: &#x27;Node&#x27;):</span><br><span class="line">    if not root:</span><br><span class="line">        return</span><br><span class="line">    queue = deque([root])</span><br><span class="line">    while queue:</span><br><span class="line">        node = queue.popleft()</span><br><span class="line">        # 访问当前节点</span><br><span class="line">        print(node.val)</span><br><span class="line">        # 将当前节点的所有子节点加入队列中</span><br><span class="line">        for child in node.children:</span><br><span class="line">            queue.append(child)</span><br></pre></td></tr></table></figure><p>在 MySQL 中，索引是在存储引擎层实现的，所以并没有统一的索引标准，即不同存储引擎的索引的工作方式并不一样。而即使多个存储引擎支持同一种类型的索引，其底层的实现也可能不同。由于 InnoDB 存储引擎在 MySQL 数据库中使用最为广泛，所以下面我就以 InnoDB 为例，和你分析一下其中的索引模型。</p><h4 id="InnoDB- 的索引模型"><a href="#InnoDB- 的索引模型" class="headerlink" title="InnoDB 的索引模型"></a>InnoDB 的索引模型 </h4><p> 在 InnoDB 中，表都是根据主键顺序以索引的形式存放的，这种存储方式的表称为索引组织表。又因为前面我们提到的，InnoDB 使用了 B+ 树索引模型，所以数据都是存储在 <strong>B+ 树 </strong> 中的。</p><p>每一个索引在 InnoDB 里面对应一棵 B+ 树。假设，我们有一个主键列为 ID 的表，表中有字段 k，并且在 k 上有索引。</p><p>这个表的建表语句是：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">mysql&gt; create table T(</span><br><span class="line">id int primary key, </span><br><span class="line">k int not null, </span><br><span class="line">name varchar(16),</span><br><span class="line">index (k))engine=InnoDB;</span><br></pre></td></tr></table></figure><p>表中 R1~R5 的 (ID,k) 值分别为 (100,1)、(200,2)、(300,3)、(500,5) 和 (600,6)，两棵树的示例示意图如下。</p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404032118108.png" alt="img" style="zoom:50%;" /><p>从图中不难看出，根据叶子节点的内容，索引类型分为 <strong> 主键索引和非主键索引。</strong></p><p><strong>主键索引的叶子节点存的是整行数据。</strong>在 InnoDB 里，主键索引也被称为 <strong> 聚簇索引</strong>（clustered index）。</p><p><strong>非主键索引的叶子节点内容是主键的值。</strong></p><p>在 InnoDB 里，非主键索引也被称为二级索引（secondary index）。</p><p>根据上面的索引结构说明，我们来讨论一个问题：<strong>基于主键索引和普通索引的查询有什么区别？</strong></p><p>如果语句是 select * from T where ID&#x3D;500，即主键查询方式，则只需要搜索 ID 这棵 B+ 树；</p><p>如果语句是 select * from T where k&#x3D;5，即普通索引查询方式，则需要先搜索 k 索引树，得到 ID 的值为 500，再到 ID 索引树搜索一次。这个过程称为回表。</p><p><strong>也就是说，基于非主键索引的查询需要多扫描一棵索引树。因此，我们在应用中应该尽量使用主键查询。</strong></p><h4 id="索引维护"><a href="# 索引维护" class="headerlink" title="索引维护"></a>索引维护</h4><p>B+ 树为了维护索引有序性，在插入新值的时候需要做必要的维护。以上面这个图为例，如果插入新的行 ID 值为 700，则只需要在 R5 的记录后面插入一个新记录。如果新插入的 ID 值为 400，就相对麻烦了，需要逻辑上挪动后面的数据，空出位置。</p><p>而更糟的情况是，如果 R5 所在的数据页已经满了，根据 B+ 树的算法，这时候需要申请一个新的数据页，然后挪动部分数据过去。这个过程称为页分裂。在这种情况下，性能自然会受影响。</p><p>除了性能外，页分裂操作还影响数据页的利用率。原本放在一个页的数据，现在分到两个页中，整体空间利用率降低大约 50%。</p><p>当然有分裂就有合并。当相邻两个页由于删除了数据，利用率很低之后，会将数据页做合并。合并的过程，可以认为是分裂过程的逆过程。</p><p>基于上面的索引维护过程说明，我们来讨论一个案例：</p><p><strong>你可能在一些建表规范里面见到过类似的描述，要求建表语句里一定要有自增主键。</strong>当然事无绝对，我们来分析一下哪些场景下应该使用自增主键，而哪些场景下不应该。</p><p>自增主键是指自增列上定义的主键，在建表语句中一般是这么定义的： <strong>NOT NULL PRIMARY KEY AUTO_INCREMENT。</strong></p><p>插入新记录的时候可以不指定 ID 的值，系统会获取当前 ID 最大值加 1 作为下一条记录的 ID 值。</p><p><strong>也就是说，自增主键的插入数据模式，正符合了我们前面提到的递增插入的场景。每次插入一条新记录，都是追加操作，都不涉及到挪动其他记录，也不会触发叶子节点的分裂。</strong></p><p>而有业务逻辑的字段做主键，则往往不容易保证有序插入，这样写数据成本相对较高。</p><p>除了考虑性能外，我们还可以从存储空间的角度来看。假设你的表中确实有一个唯一字段，比如字符串类型的身份证号，那应该用身份证号做主键，还是用自增字段做主键呢？</p><p>由于每个非主键索引的叶子节点上都是主键的值。如果用身份证号做主键，那么每个二级索引的叶子节点占用约 20 个字节，而如果用整型做主键，则只要 4 个字节，如果是长整型（bigint）则是 8 个字节。</p><p><strong>显然，主键长度越小，普通索引的叶子节点就越小，普通索引占用的空间也就越小。</strong></p><p>所以，从性能和存储空间方面考量，自增主键往往是更合理的选择。有没有什么场景适合用业务字段直接做主键的呢？还是有的。比如，有些业务的场景需求是这样的：</p><p><strong>只有一个索引；</strong></p><p><strong>该索引必须是唯一索引。</strong></p><p>你一定看出来了，这就是典型的 KV 场景。由于没有其他索引，所以也就不用考虑其他索引的叶子节点大小的问题。这时候我们就要优先考虑上一段提到的“尽量使用主键查询”原则，直接将这个索引设置为主键，可以避免每次查询需要搜索两棵树。</p><p>今天，我跟你分析了数据库引擎可用的数据结构，介绍了 InnoDB 采用的 B+ 树结构，以及为什么 InnoDB 要这么选择。B+ 树能够很好地配合磁盘的读写特性，减少单次查询的磁盘访问次数。由于 InnoDB 是索引组织表，一般情况下我会建议你创建一个自增主键，这样非主键索引占用的空间最小。但事无绝对，我也跟你讨论了使用业务逻辑字段做主键的应用场景。最后，我给你留下一个问题吧。对于上面例子中的 InnoDB 表 T，如果你要重建索引 k，你的两个 SQL 语句可以这么写：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">alter table T drop index k;</span><br><span class="line">alter table T add index(k);</span><br></pre></td></tr></table></figure><p>如果你要重建主键索引，也可以这么写：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">alter table T drop primary key;</span><br><span class="line">alter table T add primary key(id);</span><br></pre></td></tr></table></figure><p>我的问题是，对于上面这两个重建索引的作法，说出你的理解。如果有不合适的，为什么，更好的方法是什么？</p><h4 id="B- 树"><a href="#B- 树" class="headerlink" title="B+ 树"></a>B+ 树</h4><p>B+ 树的搜索、插入和删除操作的时间复杂度都是 **O(log n)**，其中 n 为 B+ 树中存储的关键字总数。 由于 B+ 树通常用于存储大量的数据，因此它具有较高的效率和较快的响应速度，是一种非常优秀的数据结构。</p><p>B+ 树是一种常见的数据结构，用于在磁盘上存储和管理大量的数据。它的时间复杂度主要涉及到搜索、插入和删除三个操作。</p><ol><li>搜索操作的时间复杂度为 O(log n)，其中 n 为 B+ 树中存储的关键字总数。搜索操作的过程类似于二分查找，它可以在较短的时间内找到所需的关键字。</li><li>插入操作的时间复杂度也为 O(log n)。在插入新的关键字时，B+ 树需要先进行搜索，然后在叶子节点上插入新的关键字。如果插入导致某个节点的关键字数超过了上限，则需要进行分裂操作，将该节点分成两个节点。分裂操作可能会导致树的高度增加，但是它不会影响搜索和删除操作的时间复杂度。</li><li>删除操作的时间复杂度也为 O(log n)。在删除关键字时，B+ 树需要先进行搜索，然后将关键字从叶子节点中删除。如果删除导致某个节点的关键字数低于了下限，则需要进行合并操作，将该节点与相邻节点合并。合并操作也可能会导致树的高度减小，但是它同样不会影响搜索和插入操作的时间复杂度。</li></ol><p>综上所述，B+ 树的搜索、插入和删除操作的时间复杂度都是 O(log n)，其中 n 为 B+ 树中存储的关键字总数。由于 B+ 树通常用于存储大量的数据，因此它具有较高的效率和较快的响应速度，是一种非常优秀的数据结构。</p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404032223620.png" alt="image-20240403222329505"></p><p><strong>他们看起来好像都完全重合了</strong>！</p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404032230915.png" alt="image-20240403223016854"></p><p>稍微解释一下：m 为什么可以等于 $2^x$</p><p>m 在这里就是大于 2 的自然数，这句话其实就是问 $2^x$ 能不能表示任意一个大于 2 的自然数。当然是可以的，因为 $2^x$ 是一条大于 0 的连续曲线。</p><p>所以：在内存里，当元素一样，b+ 树在一个节点内也采用二分法查找元素（最快的方式）。b 树和二叉树的时间复杂度都是 O(logN)。</p><p><a href="https://blog.csdn.net/yunduanyou/article/details/128233801">https://blog.csdn.net/yunduanyou/article/details/128233801</a></p><h2 id="05- 深入浅出索引（下）"><a href="#05- 深入浅出索引（下）" class="headerlink" title="05 | 深入浅出索引（下）"></a>05 | 深入浅出索引（下）</h2><p>在下面这个表 T 中，如果我执行 select * from T where k between 3 and 5，需要执行几次树的搜索操作，会扫描多少行？</p><p>下面是这个表的初始化语句。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">mysql&gt; create table T (</span><br><span class="line">ID int primary key,</span><br><span class="line">k int NOT NULL DEFAULT 0, </span><br><span class="line">s varchar(16) NOT NULL DEFAULT &#x27;&#x27;,</span><br><span class="line">index k(k))</span><br><span class="line">engine=InnoDB;</span><br><span class="line"></span><br><span class="line">insert into T values(100,1, &#x27;aa&#x27;),(200,2,&#x27;bb&#x27;),(300,3,&#x27;cc&#x27;),(500,5,&#x27;ee&#x27;),(600,6,&#x27;ff&#x27;),(700,7,&#x27;gg&#x27;);</span><br></pre></td></tr></table></figure><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404041005151.png" alt="img" style="zoom:50%;" /><p>现在，我们一起来看看这条 SQL 查询语句的执行流程：</p><p>在 k 索引树上找到 k&#x3D;3 的记录，取得 ID &#x3D; 300；</p><p>再到 ID 索引树查到 ID&#x3D;300 对应的 R3；</p><p>在 k 索引树取下一个值 k&#x3D;5，取得 ID&#x3D;500；</p><p>再回到 ID 索引树查到 ID&#x3D;500 对应的 R4；</p><p>在 k 索引树取下一个值 k&#x3D;6，不满足条件，循环结束。</p><p>在这个过程中，回到主键索引树搜索的过程，我们称为 <strong> 回表</strong>。可以看到，这个查询过程读了 k 索引树的 3 条记录（步骤 1、3 和 5），回表了两次（步骤 2 和 4）。</p><h3 id="覆盖索引"><a href="# 覆盖索引" class="headerlink" title="覆盖索引"></a>覆盖索引 </h3><p><strong> 文章解释的不是很清楚，见参考例文</strong></p><p>如果执行的语句是 select <strong>ID</strong> from T where k between 3 and 5，这时只需要查 ID 的值，<strong>而 ID 的值已经在 k 索引树上了</strong>，因此可以直接提供查询结果，不需要回表。也就是说，在这个查询里面，索引 k 已经“覆盖了”我们的查询需求，我们称为覆盖索引。</p><p>由于覆盖索引 <strong> 可以减少树的搜索次数，显著提升查询性能</strong>，所以使用覆盖索引是一个常用的性能优化手段。</p><p>注：</p><p><strong>创建一个索引，该索引包含查询中用到的所有字段，称为“覆盖索引”。</strong></p><p><strong>使用覆盖索引，MySQL 只需要通过索引就可以查找和返回查询所需要的数据，而不必在使用索引处理数据之后再进行回表操作。</strong></p><p><strong>覆盖索引可以一次性完成查询工作，有效减少 IO，提高查询效率。</strong></p><p><strong>也就是说，查询的列和索引的列一致，可以使用覆盖索引，查询中应该尽量使用覆盖索引，减少使用 <code>select * from</code>。</strong></p><p>需要注意的是，在引擎内部使用覆盖索引在索引 k 上其实读了三个记录，R3~R5（对应的索引 k 上的记录项），但是对于 MySQL 的 Server 层来说，它就是找引擎拿到了两条记录，因此 MySQL 认为扫描行数是 2。</p><p>基于上面覆盖索引的说明，我们来讨论一个问题：在一个市民信息表上，是否有必要将身份证号和名字建立联合索引？</p><p>假设这个市民表的定义是这样的：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">CREATE TABLE `tuser` (</span><br><span class="line">  `id` int(11) NOT NULL,</span><br><span class="line">  `id_card` varchar(32) DEFAULT NULL,</span><br><span class="line">  `name` varchar(32) DEFAULT NULL,</span><br><span class="line">  `age` int(11) DEFAULT NULL,</span><br><span class="line">  `ismale` tinyint(1) DEFAULT NULL,</span><br><span class="line">  PRIMARY KEY (`id`),</span><br><span class="line">  KEY `id_card` (`id_card`),</span><br><span class="line">  KEY `name_age` (`name`,`age`)</span><br><span class="line">) ENGINE=InnoDB</span><br></pre></td></tr></table></figure><p>我们知道，身份证号是市民的唯一标识。也就是说，如果有根据身份证号查询市民信息的需求，我们只要在身份证号字段上建立索引就够了。而再建立一个（身份证号、姓名）的联合索引，是不是浪费空间？</p><p>如果现在有一个高频请求，要根据市民的身份证号查询他的姓名，这个联合索引就有意义了。它可以在这个高频请求上用到覆盖索引，不再需要回表查整行记录，减少语句的执行时间。</p><p>当然，索引字段的维护总是有代价的。因此，在建立冗余索引来支持覆盖索引时就需要权衡考虑了。这正是业务 DBA，或者称为业务数据架构师的工作。</p><p><a href="https://juejin.cn/post/6844903967365791752">https://juejin.cn/post/6844903967365791752</a></p><p><a href="https://segmentfault.com/a/1190000039131878">https://segmentfault.com/a/1190000039131878</a></p><h3 id="最左前缀原则"><a href="# 最左前缀原则" class="headerlink" title="最左前缀原则"></a>最左前缀原则 </h3><p> 看到这里你一定有一个疑问，如果为每一种查询都设计一个索引，索引是不是太多了。如果我现在要按照市民的身份证号去查他的家庭地址呢？虽然这个查询需求在业务中出现的概率不高，但总不能让它走全表扫描吧？反过来说，单独为一个不频繁的请求创建一个（身份证号，地址）的索引又感觉有点浪费。应该怎么做呢？</p><p>这里，我先和你说结论吧。<strong>B+ 树这种索引结构，可以利用索引的“最左前缀”，来定位记录。</strong></p><p>为了直观地说明这个概念，我们用（name，age）这个联合索引来分析。</p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404041022862.jpeg" alt="img" style="zoom:50%;" /><p>可以看到，索引项是按照索引定义里面出现的字段顺序排序的。</p><p>当你的逻辑需求是查到所有名字是“张三”的人时，可以快速定位到 ID4，然后向后遍历得到所有需要的结果。</p><p>如果你要查的是所有名字第一个字是“张”的人，你的 SQL 语句的条件是”where name like ‘张 %’”。这时，你也能够用上这个索引，查找到第一个符合条件的记录是 ID3，然后向后遍历，直到不满足条件为止。</p><p>可以看到，不只是索引的全部定义，<strong>只要满足最左前缀，就可以利用索引来加速检索。这个最左前缀可以是联合索引的最左 N 个字段，也可以是字符串索引的最左 M 个字符。</strong></p><p>基于上面对最左前缀索引的说明，我们来讨论一个问题：<strong>在建立联合索引的时候，如何安排索引内的字段顺序。</strong></p><p>这里我们的评估标准是，<strong>索引的复用能力。</strong>因为可以支持最左前缀，所以当已经有了 (a,b) 这个联合索引后，一般就不需要单独在 a 上建立索引了。因此，第一原则是，<strong>如果通过调整顺序，可以少维护一个索引，那么这个顺序往往就是需要优先考虑采用的。</strong></p><p>所以现在你知道了，这段开头的问题里，我们要为高频请求创建 (身份证号，姓名）这个联合索引，并用这个索引支持“根据身份证号查询地址”的需求。那么，<strong>如果既有联合查询，又有基于 a、b 各自的查询呢？查询条件里面只有 b 的语句，是无法使用 (a,b) 这个联合索引的，这时候你不得不维护另外一个索引，也就是说你需要同时维护 (a,b)、(b) 这两个索引。</strong></p><p><strong>这时候，我们要考虑的原则就是空间了。</strong>比如上面这个市民表的情况，name 字段是比 age 字段大的 ，那我就建议你创建一个（name,age) 的联合索引和一个 (age) 的单字段索引。</p><h3 id="索引下推"><a href="# 索引下推" class="headerlink" title="索引下推"></a>索引下推 </h3><p><strong> 文章解释的不是很清楚，见参考例文</strong></p><p><strong>索引下推条件：</strong></p><ul><li><strong>只能用于 <code>range</code>、 <code>ref</code>、 <code>eq_ref</code>、<code>ref_or_null</code> 访问方法；</strong></li><li><strong>只能用于 <code>InnoDB</code> 和 <code>MyISAM</code>存储引擎及其分区表；</strong></li><li><strong>对 <code>InnoDB</code> 存储引擎来说，索引下推只适用于二级索引（也叫辅助索引）;</strong></li></ul><p><strong>MySQL 服务层负责 SQL 语法解析、生成执行计划等，并调用存储引擎层去执行数据的存储和检索。</strong></p><p><strong><code>索引下推 </code> 的下推其实就是指将部分上层（服务层）负责的事情，交给了下层（引擎层）去处理。</strong></p><p><strong>我们来具体看一下，在没有使用 ICP 的情况下，MySQL 的查询：</strong></p><ul><li><strong>存储引擎读取索引记录；</strong></li><li><strong>根据索引中的主键值，定位并读取完整的行记录；</strong></li><li><strong>存储引擎把记录交给 <code>Server</code> 层去检测该记录是否满足 <code>WHERE</code> 条件。</strong></li></ul><p><strong>使用 ICP 的情况下，查询过程：</strong></p><ul><li><strong>存储引擎读取索引记录（不是完整的行记录）；</strong></li><li><strong>判断 <code>WHERE</code> 条件部分能否用索引中的列来做检查，条件不满足，则处理下一行索引记录；</strong></li><li><strong>条件满足，使用索引中的主键去定位并读取完整的行记录（就是所谓的回表）；</strong></li><li><strong>存储引擎把记录交给 <code>Server</code> 层，<code>Server</code>层检测该记录是否满足 <code>WHERE</code> 条件的其余部分。</strong></li></ul><p><strong>尽量减少回表次数</strong></p><p>上一段我们说到满足最左前缀原则的时候，最左前缀可以用于在索引中定位记录。这时，你可能要问，那些不符合最左前缀的部分，会怎么样呢？</p><p>我们还是以市民表的联合索引（name, age）为例。如果现在有一个需求：检索出表中“名字第一个字是张，而且年龄是 10 岁的所有男孩”。那么，SQL 语句是这么写的：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql&gt; select * from tuser where name like &#x27; 张 %&#x27; and age=10 and ismale=1;</span><br></pre></td></tr></table></figure><p>你已经知道了前缀索引规则，所以这个语句在搜索索引树的时候，只能用 “张”，找到第一个满足条件的记录 ID3。当然，这还不错，总比全表扫描要好。</p><p>然后呢？当然是判断其他条件是否满足。</p><p>在 MySQL 5.6 之前，只能从 ID3 开始一个个回表。到主键索引上找出数据行，再对比字段值。</p><p>而 MySQL 5.6 引入的索引下推优化（index condition pushdown)， 可以在索引遍历过程中，对索引中包含的字段先做判断，直接过滤掉不满足条件的记录，减少回表次数。图 3 和图 4，是这两个过程的执行流程图。</p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404041036685.jpeg" alt="img" style="zoom:50%;" /><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404041036427.jpeg" alt="img" style="zoom:50%;" /><p>在图 3 和 4 这两个图里面，每一个虚线箭头表示回表一次。图 3 中，在 (name,age) 索引里面我特意去掉了 age 的值，这个过程 InnoDB 并不会去看 age 的值，只是按顺序把“name 第一个字是’张’”的记录一条条取出来回表。因此，需要回表 4 次。</p><p>图 4 跟图 3 的区别是，InnoDB 在 (name,age) 索引内部就判断了 age 是否等于 10，对于不等于 10 的记录，直接判断并跳过。在我们的这个例子中，只需要对 ID4、ID5 这两条记录回表取数据判断，就只需要回表 2 次。</p><p>小结今天这篇文章，我和你继续讨论了数据库索引的概念，包括了 <strong> 覆盖索引、前缀索引、索引下推</strong>。你可以看到，在满足语句需求的情况下， 尽量少地访问资源是数据库设计的重要原则之一。我们在使用数据库的时候，尤其是在设计表结构时，也要以减少资源消耗作为目标。</p><p><a href="https://www.cnblogs.com/three-fighter/p/15246577.html">https://www.cnblogs.com/three-fighter/p/15246577.html</a></p><h2 id="06- 全局锁和表锁 -：给表加个字段怎么有这么多阻碍？"><a href="#06- 全局锁和表锁 -：给表加个字段怎么有这么多阻碍？" class="headerlink" title="06 | 全局锁和表锁 ：给表加个字段怎么有这么多阻碍？"></a>06 | 全局锁和表锁 ：给表加个字段怎么有这么多阻碍？</h2><p>MySQL 的锁。数据库锁设计的初衷是处理并发问题。作为多用户共享的资源，当出现并发访问的时候，数据库需要合理地控制资源的访问规则。而锁就是用来实现这些访问规则的重要数据结构。</p><p>根据加锁的范围，<strong>MySQL 里面的锁大致可以分成全局锁、表级锁和行锁三类。</strong></p><p>这两篇文章不会涉及锁的具体实现细节，主要介绍的是碰到锁时的现象和其背后的原理。</p><h3 id="全局锁"><a href="# 全局锁" class="headerlink" title="全局锁"></a>全局锁 </h3><p> 顾名思义，全局锁就是对整个数据库实例加锁。MySQL 提供了一个加全局读锁的方法，命令是 Flush tables with read lock (FTWRL)。当你需要让整个库处于只读状态的时候，可以使用这个命令，之后其他线程的以下语句会被阻塞：数据 <strong> 更新 </strong> 语句（数据的 <strong> 增删改 </strong>）、数据<strong> 定义 </strong> 语句（包括 <strong> 建表、修改表结构 </strong> 等）和 <strong> 更新类事务 </strong> 的提交语句。</p><p><strong>全局锁的典型使用场景是，做全库逻辑备份。</strong>也就是把整库每个表都 select 出来存成文本。</p><p>以前有一种做法，是通过 FTWRL 确保不会有其他线程对数据库做更新，然后对整个库做备份。注意，在备份过程中整个库完全处于只读状态。</p><p>但是让整库都只读，听上去就很危险：</p><p>如果你在主库上备份，那么在备份期间都不能执行更新，业务基本上就得停摆；</p><p>如果你在从库上备份，那么备份期间从库不能执行主库同步过来的 binlog，会导致主从延迟。</p><p><strong>看来加全局锁不太好。但是细想一下，备份为什么要加锁呢？我们来看一下不加锁会有什么问题。</strong></p><p>假设你现在要维护“极客时间”的购买系统，关注的是用户账户余额表和用户课程表。</p><p>现在发起一个逻辑备份。假设备份期间，有一个用户，他购买了一门课程，业务逻辑里就要扣掉他的余额，然后往已购课程里面加上一门课。</p><p>如果时间顺序上是先备份账户余额表 (u_account)，然后用户购买，然后备份用户课程表 (u_course)，会怎么样呢？你可以看一下这个图：</p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404060943989.png" alt="img" style="zoom:50%;" /><p>可以看到，这个备份结果里，用户 A 的数据状态是“账户余额没扣，但是用户课程表里面已经多了一门课”。如果后面用这个备份来恢复数据的话，用户 A 就发现，自己赚了。</p><p>作为用户可别觉得这样可真好啊，你可以试想一下：如果备份表的顺序反过来，先备份用户课程表再备份账户余额表，又可能会出现什么结果？</p><p>也就是说，不加锁的话，<strong>备份系统备份的得到的库不是一个逻辑时间点，这个视图是逻辑不一致的。</strong></p><p>说到视图你肯定想起来了，我们在前面讲事务隔离的时候，其实是有一个方法能够拿到一致性视图的，对吧？</p><p>是的，就是在可重复读隔离级别下开启一个事务。</p><p>官方自带的逻辑备份工具是 <strong>mysqldump</strong>。当 <strong>mysqldump 使用参数–single-transaction 的时候 </strong>，<strong> 导数据之前就会启动一个事务，来确保拿到一致性视图。而由于 MVCC 的支持，这个过程中数据是可以正常更新的。</strong></p><p>你一定在疑惑，有了这个功能，为什么还需要 FTWRL 呢？一致性读是好，但前提是引擎要支持这个隔离级别。比如 <strong>，对于 MyISAM 这种不支持事务的引擎，如果备份过程中有更新，总是只能取到最新的数据，那么就破坏了备份的一致性。</strong> 这时，我们就需要使用 FTWRL 命令了。</p><p>所以，single-transaction 方法只适用于所有的表使用事务引擎的库。如果有的表使用了不支持事务的引擎，那么备份就只能通过 FTWRL 方法。<strong>这往往是 DBA 要求业务开发人员使用 InnoDB 替代 MyISAM 的原因之一。</strong></p><p>你也许会问，<strong>既然要全库只读，为什么不使用 set global readonly&#x3D;true 的方式呢？确实 readonly 方式也可以让全库进入只读状态，但我还是会建议你用 FTWRL 方式，主要有两个原因：</strong></p><p>一是，在有些系统中，readonly 的值会被用来做其他逻辑，比如用来判断一个库是主库还是备库。因此，修改 global 变量的方式影响面更大，我不建议你使用。</p><p>二是，在异常处理机制上有差异。如果执行 FTWRL 命令之后由于客户端发生异常断开，那么 MySQL 会自动释放这个全局锁，整个库回到可以正常更新的状态。而将整个库设置为 readonly 之后，如果客户端发生异常，则数据库就会一直保持 readonly 状态，这样会导致整个库长时间处于不可写状态，风险较高。</p><p>业务的更新不只是增删改数据（DML)，还有可能是加字段等修改表结构的操作（DDL）。不论是哪种方法，一个库被全局锁上以后，你要对里面任何一个表做加字段操作，都是会被锁住的。</p><p>但是，即使没有被全局锁住，加字段也不是就能一帆风顺的，因为你还会碰到接下来我们要介绍的表级锁。</p><h3 id="表级锁"><a href="# 表级锁" class="headerlink" title="表级锁"></a>表级锁 </h3><p>MySQL 里面表级别的锁有两种：<strong> 一种是表锁，一种是元数据锁（meta data lock，MDL)。</strong></p><p><strong>表锁的语法是 lock tables … read&#x2F;write。与 FTWRL 类似，可以用 unlock tables 主动释放锁，</strong>也可以在客户端断开的时候自动释放。需要注意，<strong>lock tables 语法除了会限制别的线程的读写外，也限定了本线程接下来的操作对象。</strong></p><p>举个例子, 如果在某个线程 A 中执行 lock tables t1 read, t2 write; 这个语句，则其他线程写 t1、读写 t2 的语句都会被阻塞。同时，线程 A 在执行 unlock tables 之前，也只能执行读 t1、读写 t2 的操作。连写 t1 都不允许，自然也不能访问其他表。</p><p><strong>在还没有出现更细粒度的锁的时候，表锁是最常用的处理并发的方式。而对于 InnoDB 这种支持行锁的引擎，一般不使用 lock tables 命令来控制并发，毕竟锁住整个表的影响面还是太大。</strong></p><p><strong>另一类表级的锁是 MDL（metadata lock)。</strong>MDL 不需要显式使用，<strong>在访问一个表的时候会被自动加上。</strong>MDL 的作用是，保证读写的正确性。你可以想象一下，如果一个查询正在遍历一个表中的数据，而执行期间另一个线程对这个表结构做变更，删了一列，那么查询线程拿到的结果跟表结构对不上，肯定是不行的。</p><p>因此，在 MySQL 5.5 版本中引入了 MDL，<strong>当对一个表做增删改查操作的时候，加 MDL 读锁；当要对表做结构变更操作的时候，加 MDL 写锁。</strong></p><p><strong>读锁之间不互斥，因此你可以有多个线程同时对一张表增删改查。</strong></p><p><strong>读写锁之间、写锁之间是互斥的，用来保证变更表结构操作的安全性。因此，如果有两个线程要同时给一个表加字段，其中一个要等另一个执行完才能开始执行。</strong></p><p>虽然 MDL 锁是系统默认会加的，但却是你不能忽略的一个机制。比如下面这个例子，我经常看到有人掉到这个坑里：给一个小表加个字段，导致整个库挂了。</p><p>你肯定知道，给一个表加字段，或者修改字段，或者加索引，需要扫描全表的数据。在对大表操作的时候，你肯定会特别小心，以免对线上服务造成影响。而实际上，即使是小表，操作不慎也会出问题。我们来看一下下面的操作序列，假设表 t 是一个小表。</p><p>备注：这里的实验环境是 MySQL 5.6。</p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404060943203.jpeg" alt="img" style="zoom:50%;" /><p>我们可以看到 session A 先启动，这时候会对表 t 加一个 MDL 读锁。由于 session B 需要的也是 MDL 读锁，因此可以正常执行。</p><p>之后 session C 会被 blocked，是因为 session A 的 MDL 读锁还没有释放，而 session C 需要 MDL 写锁，因此只能被阻塞。</p><p>如果只有 session C 自己被阻塞还没什么关系，但是之后所有要在表 t 上新申请 MDL 读锁的请求也会被 session C 阻塞。前面我们说了，所有对表的增删改查操作都需要先申请 MDL 读锁，就都被锁住，等于这个表现在完全不可读写了。</p><p>如果某个表上的查询语句频繁，而且客户端有重试机制，也就是说超时后会再起一个新 session 再请求的话，这个库的线程很快就会爆满。</p><p>你现在应该知道了，事务中的 MDL 锁，在语句执行开始时申请，但是语句结束后并不会马上释放，而会等到整个事务提交后再释放。</p><p><strong>基于上面的分析，我们来讨论一个问题，如何安全地给小表加字段？</strong></p><p>首先我们要解决长事务，事务不提交，就会一直占着 MDL 锁。在 MySQL 的 information_schema 库的 innodb_trx 表中，你可以查到当前执行中的事务。如果你要做 DDL 变更的表刚好有长事务在执行，要考虑先暂停 DDL，或者 kill 掉这个长事务。</p><p>但考虑一下这个场景。如果你要变更的表是一个热点表，虽然数据量不大，但是上面的请求很频繁，而你不得不加个字段，你该怎么做呢？</p><p>这时候 kill 可能未必管用，因为新的请求马上就来了。比较理想的机制是，在 alter table 语句里面设定等待时间，如果在这个指定的等待时间里面能够拿到 MDL 写锁最好，拿不到也不要阻塞后面的业务语句，先放弃。之后开发人员或者 DBA 再通过重试命令重复这个过程。</p><p>MariaDB 已经合并了 AliSQL 的这个功能，所以这两个开源分支目前都支持 DDL NOWAIT&#x2F;WAIT n 这个语法。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ALTER TABLE tbl_name NOWAIT add column ...</span><br><span class="line">ALTER TABLE tbl_name WAIT N add column ... </span><br></pre></td></tr></table></figure><p>小结</p><p>今天，我跟你介绍了 MySQL 的全局锁和表级锁。全局锁主要用在逻辑备份过程中。对于全部是 InnoDB 引擎的库，我建议你选择使用–single-transaction 参数，对应用会更友好。</p><p>表锁一般是在数据库引擎不支持行锁的时候才会被用到的。如果你发现你的应用程序里有 lock tables 这样的语句，你需要追查一下，比较可能的情况是：</p><p>要么是你的系统现在还在用 MyISAM 这类不支持事务的引擎，那要安排升级换引擎；</p><p>要么是你的引擎升级了，但是代码还没升级。我见过这样的情况，最后业务开发就是把 lock tables 和 unlock tables 改成 begin 和 commit，问题就解决了。</p><p>MDL 会直到事务提交才释放，在做表结构变更的时候，<strong>你一定要小心不要导致锁住线上查询和更新。</strong></p><h2 id="07- 行锁功过：怎么减少行锁对性能的影响？"><a href="#07- 行锁功过：怎么减少行锁对性能的影响？" class="headerlink" title="07 | 行锁功过：怎么减少行锁对性能的影响？"></a>07 | 行锁功过：怎么减少行锁对性能的影响？</h2><p>在上一篇文章中，我跟你介绍了 MySQL 的全局锁和表级锁，今天我们就来讲讲 MySQL 的行锁。</p><p>MySQL 的行锁是在引擎层由各个引擎自己实现的。但并不是所有的引擎都支持行锁，比如 MyISAM 引擎就不支持行锁。不支持行锁意味着并发控制只能使用表锁，对于这种引擎的表，同一张表上任何时刻只能有一个更新在执行，这就会影响到业务并发度。InnoDB 是支持行锁的，这也是 MyISAM 被 InnoDB 替代的重要原因之一。</p><p>我们今天就主要来聊聊 InnoDB 的行锁，以及如何通过减少锁冲突来提升业务并发度。</p><p>顾名思义，行锁就是针对数据表中行记录的锁。这很好理解，比如事务 A 更新了一行，而这时候事务 B 也要更新同一行，则必须等事务 A 的操作完成后才能进行更新。</p><p>当然，数据库中还有一些没那么一目了然的概念和设计，这些概念如果理解和使用不当，容易导致程序出现非预期行为，比如两阶段锁。</p><h3 id="从两阶段锁说起"><a href="# 从两阶段锁说起" class="headerlink" title="从两阶段锁说起"></a>从两阶段锁说起 </h3><p> 我先给你举个例子。在下面的操作序列中，事务 B 的 update 语句执行时会是什么现象呢？假设字段 id 是表 t 的主键。</p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404060943319.jpeg" alt="img" style="zoom:50%;" /><p>这个问题的结论取决于事务 A 在执行完两条 update 语句后，持有哪些锁，以及在什么时候释放。你可以验证一下：实际上事务 B 的 update 语句会被阻塞，直到事务 A 执行 commit 之后，事务 B 才能继续执行。</p><p>知道了这个答案，你一定知道了事务 A 持有的两个记录的行锁，都是在 commit 的时候才释放的。</p><p><strong>也就是说，在 InnoDB 事务中，行锁是在需要的时候才加上的，但并不是不需要了就立刻释放，而是要等到事务结束时才释放。这个就是两阶段锁协议。</strong></p><p>知道了这个设定，对我们使用事务有什么帮助呢？<strong>那就是，如果你的事务中需要锁多个行，要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。</strong>我给你举个例子。</p><p>假设你负责实现一个电影票在线交易业务，顾客 A 要在影院 B 购买电影票。我们简化一点，这个业务需要涉及到以下操作：</p><ol><li>从顾客 A 账户余额中扣除电影票价；</li><li>给影院 B 的账户余额增加这张电影票价；</li><li>记录一条交易日志。</li></ol><p>也就是说，要完成这个交易，我们需要 update 两条记录，并 insert 一条记录。当然，为了保证交易的原子性，我们要把这三个操作放在一个事务中。那么，你会怎样安排这三个语句在事务中的顺序呢？</p><p>试想如果同时有另外一个顾客 C 要在影院 B 买票，那么这两个事务冲突的部分就是语句 2 了。因为它们要更新同一个影院账户的余额，需要修改同一行数据。</p><p>根据两阶段锁协议，不论你怎样安排语句顺序，所有的操作需要的行锁都是在事务提交的时候才释放的。所以，如果你把语句 2 安排在最后，比如按照 3、1、2 这样的顺序，那么影院账户余额这一行的锁时间就最少。这就最大程度地减少了事务之间的锁等待，提升了并发度。</p><p>好了，现在由于你的正确设计，影院余额这一行的行锁在一个事务中不会停留很长时间。但是，这并没有完全解决你的困扰。</p><p>如果这个影院做活动，可以低价预售一年内所有的电影票，而且这个活动只做一天。于是在活动时间开始的时候，你的 MySQL 就挂了。你登上服务器一看，CPU 消耗接近 100%，但整个数据库每秒就执行不到 100 个事务。这是什么原因呢？</p><p>这里，我就要说到死锁和死锁检测了。</p><h3 id="死锁和死锁检测"><a href="# 死锁和死锁检测" class="headerlink" title="死锁和死锁检测"></a>死锁和死锁检测 </h3><p> 当并发系统中不同线程出现循环资源依赖，涉及的线程都在等待别的线程释放资源时，就会导致这几个线程都进入无限等待的状态，称为死锁。这里我用数据库中的行锁举个例子。</p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404060943023.jpeg" alt="img" style="zoom:50%;" /><p>这时候，事务 A 在等待事务 B 释放 id&#x3D;2 的行锁，而事务 B 在等待事务 A 释放 id&#x3D;1 的行锁。 事务 A 和事务 B 在互相等待对方的资源释放，就是进入了死锁状态。当出现死锁以后，有两种策略：</p><p><strong>一种策略是，直接进入等待，直到超时。这个超时时间可以通过参数 innodb_lock_wait_timeout 来设置。</strong></p><p><strong>另一种策略是，发起死锁检测，发现死锁后，主动回滚死锁链条中的某一个事务，让其他事务得以继续执行。将参数 innodb_deadlock_detect 设置为 on，表示开启这个逻辑。</strong></p><p>在 InnoDB 中，innodb_lock_wait_timeout 的默认值是 50s，意味着如果采用第一个策略，当出现死锁以后，第一个被锁住的线程要过 50s 才会超时退出，然后其他线程才有可能继续执行。对于在线服务来说，这个等待时间往往是无法接受的。</p><p>但是，我们又不可能直接把这个时间设置成一个很小的值，比如 1s。这样当出现死锁的时候，确实很快就可以解开，但如果不是死锁，而是简单的锁等待呢？所以，<strong>超时时间设置太短的话，会出现很多误伤。</strong></p><p>所以，正常情况下我们还是要采用第二种策略，即：<strong>主动死锁检测，而且 innodb_deadlock_detect 的默认值本身就是 on。</strong>主动死锁检测在发生死锁的时候，是能够快速发现并进行处理的，但是它也是有额外负担的。</p><p>你可以想象一下这个过程：每当一个事务被锁的时候，就要看看它所依赖的线程有没有被别人锁住，如此循环，最后判断是否出现了循环等待，也就是死锁。</p><p>那如果是我们上面说到的所有事务都要更新同一行的场景呢？</p><p>每个新来的被堵住的线程，都要判断会不会由于自己的加入导致了死锁，这是一个时间复杂度是 O(n) 的操作。假设有 1000 个并发线程要同时更新同一行，那么死锁检测操作就是 100 万这个量级的。虽然最终检测的结果是没有死锁，但是这期间要 <strong> 消耗大量的 CPU 资源。</strong>因此，你就会看到 CPU 利用率很高，但是每秒却执行不了几个事务。</p><p>根据上面的分析，我们来讨论一下，怎么解决由这种热点行更新导致的性能问题呢？问题的症结在于，死锁检测要耗费大量的 CPU 资源。</p><p><strong>一种头痛医头的方法，就是如果你能确保这个业务一定不会出现死锁，可以临时把死锁检测关掉。</strong>但是这种操作本身带有一定的风险，因为业务设计的时候一般不会把死锁当做一个严重错误，毕竟出现死锁了，就回滚，然后通过业务重试一般就没问题了，这是业务无损的。而关掉死锁检测意味着可能会出现大量的超时，这是业务有损的。</p><p><strong>另一个思路是控制并发度。</strong>根据上面的分析，你会发现如果并发能够控制住，比如同一行同时最多只有 10 个线程在更新，那么死锁检测的成本很低，就不会出现这个问题。一个直接的想法就是，在客户端做并发控制。但是，你会很快发现这个方法不太可行，因为客户端很多。我见过一个应用，有 600 个客户端，这样即使每个客户端控制到只有 5 个并发线程，汇总到数据库服务端以后，峰值并发数也可能要达到 3000。</p><p><strong>因此，这个并发控制要做在数据库服务端。如果你有中间件，可以考虑在中间件实现；如果你的团队有能修改 MySQL 源码的人，也可以做在 MySQL 里面。基本思路就是，对于相同行的更新，在进入引擎之前排队。这样在 InnoDB 内部就不会有大量的死锁检测工作了。</strong></p><p>可能你会问，如果团队里暂时没有数据库方面的专家，不能实现这样的方案，能不能从设计上优化这个问题呢？</p><p>你可以考虑通过将一行改成逻辑上的多行来减少锁冲突。还是以影院账户为例，可以考虑放在多条记录上，比如 10 个记录，影院的账户总额等于这 10 个记录的值的总和。这样每次要给影院账户加金额的时候，随机选其中一条记录来加。这样每次冲突概率变成原来的 1&#x2F;10，可以减少锁等待个数，也就减少了死锁检测的 CPU 消耗。</p><p>这个方案看上去是无损的，但其实这类方案需要根据业务逻辑做详细设计。如果账户余额可能会减少，比如退票逻辑，那么这时候就需要考虑当一部分行记录变成 0 的时候，代码要有特殊处理。</p><p>小结</p><p>今天，我和你介绍了 MySQL 的行锁，涉及了两阶段锁协议、死锁和死锁检测这两大部分内容。</p><p>其中，我以两阶段协议为起点，和你一起讨论了在开发的时候如何安排正确的事务语句。这里的原则 &#x2F; 我给你的建议是：如果你的事务中需要锁多个行，要把最可能造成锁冲突、最可能影响并发度的锁的申请时机尽量往后放。</p><p>但是，调整语句顺序并不能完全避免死锁。所以我们引入了死锁和死锁检测的概念，以及提供了三个方案，来减少死锁对数据库的影响。减少死锁的主要方向，就是控制访问相同资源的并发事务量。</p><p>最后，我给你留下一个问题吧。如果你要删除一个表里面的前 10000 行数据，有以下三种方法可以做到：</p><p>第一种，直接执行 delete from T limit 10000;</p><p>第二种，在一个连接中循环执行 20 次 delete from T limit 500;</p><p>第三种，在 20 个连接中同时执行 delete from T limit 500。</p><p>你会选择哪一种方法呢？为什么呢？你可以把你的思考和观点写在留言区里，我会在下一篇文章的末尾和你讨论这个问题。感谢你的收听，也欢迎你把这篇文章分享给更多的朋友一起阅读。</p><h2 id="08- 事务到底是隔离的还是不隔离的？"><a href="#08- 事务到底是隔离的还是不隔离的？" class="headerlink" title="08 | 事务到底是隔离的还是不隔离的？"></a>08 | 事务到底是隔离的还是不隔离的？</h2><p>我在第 3 篇文章和你讲事务隔离级别的时候提到过，如果是可重复读隔离级别，事务 T 启动的时候会创建一个视图 read-view，之后事务 T 执行期间，即使有其他事务修改了数据，事务 T 看到的仍然跟在启动时看到的一样。也就是说，一个在可重复读隔离级别下执行的事务，好像与世无争，不受外界影响。</p><p>但是，我在上一篇文章中，和你分享行锁的时候又提到，一个事务要更新一行，如果刚好有另外一个事务拥有这一行的行锁，它又不能这么超然了，会被锁住，进入等待状态。问题是，既然进入了等待状态，那么等到这个事务自己获取到行锁要更新数据的时候，它读到的值又是什么呢？</p><p>我给你举一个例子吧。下面是一个只有两行的表的初始化语句。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">mysql&gt; CREATE TABLE `t` (</span><br><span class="line">  `id` int(11) NOT NULL,</span><br><span class="line">  `k` int(11) DEFAULT NULL,</span><br><span class="line">  PRIMARY KEY (`id`)</span><br><span class="line">) ENGINE=InnoDB;</span><br><span class="line">insert into t(id, k) values(1,1),(2,2);</span><br></pre></td></tr></table></figure><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404060942124.png" alt="img" style="zoom:50%;" /><p>这里，我们需要注意的是事务的启动时机。</p><p><strong>begin&#x2F;start transaction 命令并不是一个事务的起点，在执行到它们之后的第一个操作 InnoDB 表的语句，事务才真正启动。如果你想要马上启动一个事务，可以使用 start transaction with consistent snapshot 这个命令。</strong></p><p><strong>第一种启动方式，一致性视图是在执行第一个快照读语句时创建的；</strong></p><p><strong>第二种启动方式，一致性视图是在执行 start transaction with consistent snapshot 时创建的。</strong></p><p>还需要注意的是，在整个专栏里面，我们的例子中如果没有特别说明，都是 <strong> 默认 autocommit&#x3D;1。</strong></p><p>在这个例子中，事务 C 没有显式地使用 begin&#x2F;commit，表示这个 update 语句本身就是一个事务，语句完成的时候会自动提交。事务 B 在更新了行之后查询 ; 事务 A 在一个只读事务中查询，并且时间顺序上是在事务 B 的查询之后。</p><p>这时，如果我告诉你事务 B 查到的 k 的值是 3，而事务 A 查到的 k 的值是 1，你是不是感觉有点晕呢？</p><p>所以，今天这篇文章，我其实就是想和你说明白这个问题，希望借由把这个疑惑解开的过程，能够帮助你对 InnoDB 的事务和锁有更进一步的理解。</p><p><strong>在 MySQL 里，有两个“视图”的概念：</strong></p><p><strong>一个是 view。它是一个用查询语句定义的虚拟表，在调用的时候执行查询语句并生成结果。创建视图的语法是 create view … ，而它的查询方法与表一样。</strong></p><p><strong>另一个是 InnoDB 在实现 MVCC 时用到的一致性读视图，即 consistent read view，用于支持 RC（Read Committed，读提交）和 RR（Repeatable Read，可重复读）隔离级别的实现。</strong></p><p>它没有物理结构，作用是事务执行期间用来定义“我能看到什么数据”。</p><p>在第 3 篇文章《事务隔离：为什么你改了我还看不见？》中，我跟你解释过一遍 MVCC 的实现逻辑。今天为了说明查询和更新的区别，我换一个方式来说明，把 read view 拆开。你可以结合这两篇文章的说明来更深一步地理解 MVCC。</p><h3 id="“快照”在 -MVCC- 里是怎么工作的？"><a href="#“快照”在 -MVCC- 里是怎么工作的？" class="headerlink" title="“快照”在 MVCC 里是怎么工作的？"></a>“快照”在 MVCC 里是怎么工作的？</h3><p>在可重复读隔离级别下，事务在启动的时候就“拍了个快照”。</p><p>注意，这个快照是基于整库的。这时，你会说这看上去不太现实啊。如果一个库有 100G，那么我启动一个事务，MySQL 就要拷贝 100G 的数据出来，这个过程得多慢啊。可是，我平时的事务执行起来很快啊。</p><p>实际上，我们并不需要拷贝出这 100G 的数据。我们先来看看这个快照是怎么实现的。</p><p><strong>InnoDB 里面每个事务有一个唯一的事务 ID，叫作 transaction id。它是在事务开始的时候向 InnoDB 的事务系统申请的，是按申请顺序严格递增的。</strong></p><p><strong>而每行数据也都是有多个版本的。每次事务更新数据的时候，都会生成一个新的数据版本，并且把 transaction id 赋值给这个数据版本的事务 ID，记为 row trx_id。同时，旧的数据版本要保留，并且在新的数据版本中，能够有信息可以直接拿到它。</strong></p><p>也就是说，数据表中的一行记录，<strong>其实可能有多个版本 (row)，每个版本有自己的 row trx_id。</strong></p><p>如图 2 所示，就是一个记录被多个事务连续更新后的状态。</p><img src="https://static001.geekbang.org/resource/image/68/ed/68d08d277a6f7926a41cc5541d3dfced.png?wh=1142*856" alt="img" style="zoom:50%;" /><p>图中虚线框里是同一行数据的 4 个版本，当前最新版本是 V4，k 的值是 22，它是被 transaction id 为 25 的事务更新的，因此它的 row trx_id 也是 25。</p><p>你可能会问，前面的文章不是说，语句更新会生成 undo log（回滚日志）吗？那么，undo log 在哪呢？</p><p>实际上，图 2 中的三个虚线箭头，就是 undo log；而 V1、V2、V3 并不是物理上真实存在的，而是每次需要的时候根据当前版本和 undo log 计算出来的。比如，需要 V2 的时候，就是通过 V4 依次执行 U3、U2 算出来。</p><p>明白了多版本和 row trx_id 的概念后，我们再来想一下，InnoDB 是怎么定义那个“100G”的快照的。</p><p>按照可重复读的定义，一个事务启动的时候，能够看到所有已经提交的事务结果。但是之后，这个事务执行期间，其他事务的更新对它不可见。</p><p><strong>因此，一个事务只需要在启动的时候声明说，“以我启动的时刻为准，如果一个数据版本是在我启动之前生成的，就认；如果是我启动以后才生成的，我就不认，我必须要找到它的上一个版本”。</strong></p><p>当然，如果“上一个版本”也不可见，那就得继续往前找。还有，如果是这个事务自己更新的数据，它自己还是要认的。</p><p><strong>在实现上， InnoDB 为每个事务构造了一个数组，用来保存这个事务启动瞬间，当前正在“活跃”的所有事务 ID。“活跃”指的就是，启动了但还没提交。</strong></p><p>数组里面事务 ID 的最小值记为低水位，当前系统里面已经创建过的事务 ID 的最大值加 1 记为高水位。</p><p><strong>这个视图数组和高水位，就组成了当前事务的一致性视图（read-view）。</strong></p><p>而数据版本的可见性规则，就是基于数据的 row trx_id 和这个一致性视图的对比结果得到的。</p><p>这个视图数组把所有的 row trx_id 分成了几种不同的情况。</p><img src="https://static001.geekbang.org/resource/image/88/5e/882114aaf55861832b4270d44507695e.png?wh=1142*856" alt="img" style="zoom:50%;" /><p>这样，对于当前事务的启动瞬间来说，一个数据版本的 row trx_id，有以下几种可能：</p><p><strong>如果落在绿色部分，表示这个版本是已提交的事务或者是当前事务自己生成的，这个数据是可见的；</strong></p><p><strong>如果落在红色部分，表示这个版本是由将来启动的事务生成的，是肯定不可见的；</strong></p><p><strong>如果落在黄色部分，那就包括两种情况</strong></p><p><strong>a. 若 row trx_id 在数组中，表示这个版本是由还没提交的事务生成的，不可见；</strong></p><p><strong>b. 若 row trx_id 不在数组中，表示这个版本是已经提交了的事务生成的，可见。</strong></p><p>比如，对于图 2 中的数据来说，如果有一个事务，它的低水位是 18，那么当它访问这一行数据时，就会从 V4 通过 U3 计算出 V3，所以在它看来，这一行的值是 11。</p><p>你看，有了这个声明后，系统里面随后发生的更新，是不是就跟这个事务看到的内容无关了呢？因为之后的更新，生成的版本一定属于上面的 2 或者 3(a) 的情况，而对它来说，这些新的数据版本是不存在的，所以这个事务的快照，就是“静态”的了。</p><p>所以你现在知道了，InnoDB 利用了“所有数据都有多个版本”的这个特性，实现了“秒级创建快照”的能力。</p><p>接下来，我们继续看一下图 1 中的三个事务，分析下事务 A 的语句返回的结果，为什么是 k&#x3D;1。</p><p>这里，我们不妨做如下假设：</p><ol><li>事务 A 开始前，系统里面只有一个活跃事务 ID 是 99；</li><li>事务 A、B、C 的版本号分别是 100、101、102，且当前系统里只有这四个事务；</li><li>三个事务开始前，(1,1）这一行数据的 row trx_id 是 90。</li></ol><p>这样，事务 A 的视图数组就是[99,100], 事务 B 的视图数组是[99,100,101], 事务 C 的视图数组是[99,100,101,102]。</p><p>为了简化分析，我先把其他干扰语句去掉，只画出跟事务 A 查询逻辑有关的操作：</p><img src="https://static001.geekbang.org/resource/image/94/49/9416c310e406519b7460437cb0c5c149.png?wh=1142*856" alt="img" style="zoom:50%;" /><p>从图中可以看到，第一个有效更新是事务 C，把数据从 (1,1) 改成了 (1,2)。这时候，这个数据的最新版本的 row trx_id 是 102，而 90 这个版本已经成为了历史版本。</p><p>第二个有效更新是事务 B，把数据从 (1,2) 改成了 (1,3)。这时候，这个数据的最新版本（即 row trx_id）是 101，而 102 又成为了历史版本。</p><p>你可能注意到了，在事务 A 查询的时候，其实事务 B 还没有提交，但是它生成的 (1,3) 这个版本已经变成当前版本了。但这个版本对事务 A 必须是不可见的，否则就变成脏读了。</p><p>好，现在事务 A 要来读数据了，它的视图数组是[99,100]。当然了，读数据都是从当前版本读起的。所以，事务 A 查询语句的读数据流程是这样的：</p><p>找到 (1,3) 的时候，判断出 row trx_id&#x3D;101，比高水位大，处于红色区域，不可见；</p><p>接着，找到上一个历史版本，一看 row trx_id&#x3D;102，比高水位大，处于红色区域，不可见；</p><p>再往前找，终于找到了（1,1)，它的 row trx_id&#x3D;90，比低水位小，处于绿色区域，可见。</p><p>这样执行下来，虽然期间这一行数据被修改过，但是事务 A 不论在什么时候查询，看到这行数据的结果都是一致的，所以我们称之为一致性读。</p><p>这个判断规则是从代码逻辑直接转译过来的，但是正如你所见，用于人肉分析可见性很麻烦。</p><p>所以，我来给你翻译一下。一个数据版本，对于一个事务视图来说，除了自己的更新总是可见以外，有三种情况：</p><p>版本未提交，不可见；</p><p>版本已提交，但是是在视图创建后提交的，不可见；</p><p>版本已提交，而且是在视图创建前提交的，可见。</p><p>现在，我们用这个规则来判断图 4 中的查询结果，事务 A 的查询语句的视图数组是在事务 A 启动的时候生成的，这时候：</p><p>(1,3) 还没提交，属于情况 1，不可见；</p><p>(1,2) 虽然提交了，但是是在视图数组创建之后提交的，属于情况 2，不可见；</p><p>(1,1) 是在视图数组创建之前提交的，可见。</p><p>你看，去掉数字对比后，只用时间先后顺序来判断，分析起来是不是轻松多了。所以，后面我们就都用这个规则来分析。</p><h3 id="更新逻辑"><a href="# 更新逻辑" class="headerlink" title="更新逻辑"></a>更新逻辑 </h3><p> 细心的同学可能有疑问了：事务 B 的 update 语句，如果按照一致性读，好像结果不对哦？</p><p>你看图 5 中，事务 B 的视图数组是先生成的，之后事务 C 才提交，不是应该看不见 (1,2) 吗，怎么能算出 (1,3) 来？</p><img src="https://static001.geekbang.org/resource/image/86/9f/86ad7e8abe7bf16505b97718d8ac149f.png?wh=1142*856" alt="img" style="zoom:50%;" /><p>是的，如果事务 B 在更新之前查询一次数据，这个查询返回的 k 的值确实是 1。</p><p>但是，当它要去更新数据的时候，就不能再在历史版本上更新了，否则事务 C 的更新就丢失了。因此，事务 B 此时的 set k&#x3D;k+1 是在（1,2）的基础上进行的操作。</p><p>所以，这里就用到了这样一条规则：更新数据都是先读后写的，而这个读，只能读当前的值，称为“当前读”（current read）。</p><p>因此，在更新的时候，当前读拿到的数据是 (1,2)，更新后生成了新版本的数据 (1,3)，这个新版本的 row trx_id 是 101。</p><p>所以，在执行事务 B 查询语句的时候，一看自己的版本号是 101，最新数据的版本号也是 101，是自己的更新，可以直接使用，所以查询得到的 k 的值是 3。</p><p>这里我们提到了一个概念，叫作当前读。其实，除了 update 语句外，select 语句如果加锁，也是当前读。</p><p>所以，如果把事务 A 的查询语句 select * from t where id&#x3D;1 修改一下，加上 lock in share mode 或 for update，也都可以读到版本号是 101 的数据，返回的 k 的值是 3。下面这两个 select 语句，就是分别加了读锁（S 锁，共享锁）和写锁（X 锁，排他锁）。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mysql&gt; select k from t where id=1 lock in share mode;</span><br><span class="line">mysql&gt; select k from t where id=1 for update;</span><br></pre></td></tr></table></figure><p>再往前一步，假设事务 C 不是马上提交的，而是变成了下面的事务 C’，会怎么样呢？</p><img src="https://static001.geekbang.org/resource/image/cd/6e/cda2a0d7decb61e59dddc83ac51efb6e.png?wh=906*565" alt="img" style="zoom:50%;" /><p>事务 C’的不同是，更新后并没有马上提交，在它提交前，事务 B 的更新语句先发起了。前面说过了，虽然事务 C’还没提交，但是 (1,2) 这个版本也已经生成了，并且是当前的最新版本。那么，事务 B 的更新语句会怎么处理呢？</p><p>这时候，我们在上一篇文章中提到的“两阶段锁协议”就要上场了。事务 C’没提交，也就是说 (1,2) 这个版本上的写锁还没释放。而事务 B 是当前读，必须要读最新版本，而且必须加锁，因此就被锁住了，必须等到事务 C’释放这个锁，才能继续它的当前读。</p><img src="https://static001.geekbang.org/resource/image/54/92/540967ea905e8b63630e496786d84c92.png?wh=1142*856" alt="img" style="zoom:50%;" /><p>到这里，我们把一致性读、当前读和行锁就串起来了。</p><p>现在，我们再回到文章开头的问题：事务的可重复读的能力是怎么实现的？</p><p>可重复读的核心就是一致性读（consistent read）；而事务更新数据的时候，只能用当前读。如果当前的记录的行锁被其他事务占用的话，就需要进入锁等待。</p><p>而读提交的逻辑和可重复读的逻辑类似，它们最主要的区别是：</p><p>在可重复读隔离级别下，只需要在事务开始的时候创建一致性视图，之后事务里的其他查询都共用这个一致性视图；</p><p>在读提交隔离级别下，每一个语句执行前都会重新算出一个新的视图。</p><p>那么，我们再看一下，在读提交隔离级别下，事务 A 和事务 B 的查询语句查到的 k，分别应该是多少呢？</p><p>这里需要说明一下，“start transaction with consistent snapshot; ”的意思是从这个语句开始，创建一个持续整个事务的一致性快照。所以，在读提交隔离级别下，这个用法就没意义了，等效于普通的 start transaction。</p><p>下面是读提交时的状态图，可以看到这两个查询语句的创建视图数组的时机发生了变化，就是图中的 read view 框。（注意：这里，我们用的还是事务 C 的逻辑直接提交，而不是事务 C’）</p><img src="https://static001.geekbang.org/resource/image/18/be/18fd5179b38c8c3804b313c3582cd1be.jpg?wh=1142*856" alt="img" style="zoom:50%;" /><p>这时，事务 A 的查询语句的视图数组是在执行这个语句的时候创建的，时序上 (1,2)、(1,3) 的生成时间都在创建这个视图数组的时刻之前。但是，在这个时刻：</p><p>(1,3) 还没提交，属于情况 1，不可见；</p><p>(1,2) 提交了，属于情况 3，可见。</p><p>所以，这时候事务 A 查询语句返回的是 k&#x3D;2。显然地，事务 B 查询结果 k&#x3D;3。</p><p>小结</p><p>InnoDB 的行数据有多个版本，每个数据版本有自己的 row trx_id，每个事务或者语句有自己的一致性视图。普通查询语句是一致性读，一致性读会根据 row trx_id 和一致性视图确定数据版本的可见性。</p><p>对于可重复读，查询只承认在事务启动前就已经提交完成的数据；</p><p>对于读提交，查询只承认在语句启动前就已经提交完成的数据；</p><p>而当前读，总是读取已经提交完成的最新版本。</p><p>你也可以想一下，为什么表结构不支持“可重复读”？这是因为表结构没有对应的行数据，也没有 row trx_id，因此只能遵循当前读的逻辑。</p><p>当然，MySQL 8.0 已经可以把表结构放在 InnoDB 字典里了，也许以后会支持表结构的可重复读。</p><p>又到思考题时间了。我用下面的表结构和初始化语句作为试验环境，事务隔离级别是可重复读。现在，我要把所有“字段 c 和 id 值相等的行”的 c 值清零，但是却发现了一个“诡异”的、改不掉的情况。请你构造出这种情况，并说明其原理。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">mysql&gt; CREATE TABLE `t` (</span><br><span class="line">  `id` int(11) NOT NULL,</span><br><span class="line">  `c` int(11) DEFAULT NULL,</span><br><span class="line">  PRIMARY KEY (`id`)</span><br><span class="line">) ENGINE=InnoDB;</span><br><span class="line">insert into t(id, c) values(1,1),(2,2),(3,3),(4,4);</span><br></pre></td></tr></table></figure><img src="https://static001.geekbang.org/resource/image/9b/0b/9b8fe7cf88c9ba40dc12e93e36c3060b.png?wh=486*661" alt="img" style="zoom:50%;" /><h2 id="一文读懂，软件测试必会的方法和技术知识点！"><a href="# 一文读懂，软件测试必会的方法和技术知识点！" class="headerlink" title="一文读懂，软件测试必会的方法和技术知识点！"></a>一文读懂，软件测试必会的方法和技术知识点！</h2><p>软件测试是软件开发过程的重要组成部分，用来确认一个程序的品质或性能是否符合开发之前所提出的一些要求。软件测试人员要寻找 Bug，避免软件开发过程中的缺陷，衡量软件的品质，关注用户的需求，总的目标确保软件的质量。 <a href="https://cloud.tencent.com/developer/tools/blog-entry?target=http://mp.weixin.qq.com/s?__biz=Mzk0NzAzNTM0Mg==&mid=100001972&idx=1&sn=5b6c7eb0423ae6f0459e7a1986942a0f&chksm=437c4515740bcc03fc484c7911bc8385683056f0742664d572de2ff2df6c1b99a5e0abc4f25f&scene=18%23wechat_redirect&source=article&objectId=1864380">测试面试宝典</a></p><p><strong>一、按测试设计方法分类</strong></p><p><strong>1、黑盒测试</strong></p><p>黑盒测试是把测试对象看做一个黑盒子，利用黑盒测试法进行动态测试时，需要测试软件产品已经实现的功能是否符合功能设计要求，不需测试软件产品的内部结构和处理过程。</p><p>黑盒测试注重于测试软件的功能性需求，也即黑盒测试使软件工程师派生出执行程序所有功能需求的输入条件。黑盒测试并不是白盒测试的替代品，而是用于辅助白盒测试发现其他类型的错误。</p><p><strong>2、白盒测试</strong></p><p>设计者可以看到软件系统的内部结构，并使用软件的内部知识来指导测试数据及方法的选择。白盒测试通常被认为是单元测试与集成测试，期中有六种测试方法：语句覆盖、判定覆盖、条件覆盖、判定 &#x2F; 条件覆盖、条件组合覆盖。</p><p>111</p><p><strong>3、灰盒测试</strong></p><p>介于黑盒和白盒之间是一种综合测试的方法，将白盒测试和黑盒测试结合在一起，构成一种无缝测试技术。灰盒测试是基于程序运行时的外部表现又结合程序内部逻辑结构来设计测试用例，执行程序并采集程序路径执行信息和外部用户接口结果的测试技术。灰盒测试法旨在验证软件满足外部指标以及软件的所有通道或路径都进行了检验。</p><p>实际工作中，对系统的了解越多越好。目前大多数的测试人员都是做黑盒测试，很少有做白盒测试的。因为白盒测试对软件测试人员的要求非常高需要有很多编程经验。做.NET 程序的白盒测试你要能看得懂.NET 代码。做 JAVA 程序的测试需要你能看懂 JAVA 代码。</p><p><strong>二、按测试是手动还是自动上分类</strong></p><p><strong>1、手动测试</strong>　</p><p>测试人员用鼠标去手动测试，用鼠标各种点点点，手工测试更能容易发现软件的 Bug。</p><p><strong>2、自动化测试</strong></p><p>用程序测试程序，由测试人员根据手工测试的 Case 来决定自动化测试的 Case 再编写程序或者脚本来替代手工做自动化测试。对于项目来说，手动测试和自动化测试同等重要，都是保障软件质量的方法。目前大部分的项目组都是手动测试和自动化测试相结合。因为很多测试无法做成自动化，很多复杂的业务逻辑也很难自动化，自动化测试无法取代手动测试。手工测试胜在测试业务逻辑，而自动化测试胜在测试底层架构。如果被测试的程序可测试性比较好很有必要做成自动化测试。</p><p><a href="https://cloud.tencent.com/developer/article/1864380">https://cloud.tencent.com/developer/article/1864380</a></p><h2 id="产品规划蓝图：Roadmap 长什么样子？"><a href="# 产品规划蓝图：Roadmap 长什么样子？" class="headerlink" title="产品规划蓝图：Roadmap 长什么样子？"></a>产品规划蓝图：Roadmap 长什么样子？</h2><h3 id="一、什么是 Roadmap？"><a href="# 一、什么是 Roadmap？" class="headerlink" title="一、什么是 Roadmap？"></a>一、什么是 Roadmap？</h3><h4 id="Roadmap 的定义"><a href="#Roadmap 的定义" class="headerlink" title="Roadmap 的定义"></a>Roadmap 的定义</h4><p>Roadmap 用来指引人们到达某个地点，或说明从甲地到达乙地的方式。从一般意义上来说，路线图更多的被指代于地理上的图片说明，例如寻宝图、部分位置图、交通示意图等等。</p><p>在广义上，Roadmap 也可以是指引人们达到任何目标的说明性文档，甚至没有任何图片说明也可以被泛指为“Roadmap”。延伸到产品设计上，它是一种能快速表达出这款产品实现成功的过程和最终的结果。</p><h4 id="Roadmap 的特点"><a href="#Roadmap 的特点" class="headerlink" title="Roadmap 的特点"></a>Roadmap 的特点</h4><ul><li><strong>有起点有终点</strong></li></ul><p>与传统地图不一样的地方是，Roadmap 是有起点有终点。通常起点是 1 个，但是终点可能是 1 个或多个，因为产品发展的路径可能会从最开始的 1 个 idea 衍生成 1 个或多个产品解决方案。</p><ul><li><strong>有明确的路径</strong></li></ul><p>这点和地图软件的导航很类似，从起点到终点的线路，一定是有明确的路径。基于用户不同诉求，路径是有所差异的，比如从 A 点到 B 点，按地铁优先、步行少、换乘少、时间短等不同的诉求，导航软件推荐的路径是不同的。但是不管是哪种路径，用户都能在地图上得到明确的路径，一步步指引自己从 A 点到达 B 点。</p><ul><li><strong>简单易懂、易于阅读</strong></li></ul><p>Roadmap 一般是浅显易懂的，按用户体验场景的流程，通过简洁、形象化的文字描述，来表达出来的图形。步骤清晰，且承载的信息相对较少，从而简单易懂、易于阅读。</p><h3 id="二、为什么要做 Roadmap？"><a href="# 二、为什么要做 Roadmap？" class="headerlink" title="二、为什么要做 Roadmap？"></a>二、为什么要做 Roadmap？</h3><ul><li><strong>完整性</strong></li></ul><p>Roadmap 可以从用户体验场景的横向和纵向两个维度，让团队直观的看到这款产品的完整面貌。</p><ol><li>横向看，从用户开始接触体验这款产品，到体验完成离开这款产品，整个用户体验路径上的场景都能被 Roadmap 覆盖。</li><li>纵向看，在某一个用户体验场景上，比如从前期提供 10% 的该场景解决方案，到最终提供 100% 的该场景解决方案，都能在 Roadmap 上呈现出来。</li></ol><ul><li><strong>成功的样子</strong></li></ul><p>Roadmap 的价值是让团队清晰的知道这款产品成功是什么样子？以及实现成功的样子需要设定哪些目标？这些目标要达到怎样的标准？这些标准需要在什么时候提供怎样的解决方案。这样在产品初期规划的时候，需要产品经理既要考虑用户场景、又要基于企业现有能力，最终描绘出一幅“可落地可执行成功产品的蓝图”。</p><ul><li><strong>能力储备</strong></li></ul><p>一幅可落地可执行的 Roadmap，可以让团队提前进行相应的能力储备，以便完美实现 Roadmap 成功的样子。</p><p>比如需要提前储备用户深度调研、需求挖掘、产品设计等能力，来解决用户在不同场景的痛点；</p><p>比如需要提前储备运营支撑能力，产品经理提供了产品解决方案，运营则需要匹配上合适的运营推广方案，从而更好的解决用户痛点；</p><p>再比如要实现对应的产品解决方案和运营推广方案，技术团队需要建设哪些技术能力？要不要建设中台？以及建设哪些中台？</p><h3 id="三、Roadmap 长什么样子？"><a href="# 三、Roadmap 长什么样子？" class="headerlink" title="三、Roadmap 长什么样子？"></a>三、Roadmap 长什么样子？</h3><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404031030676.webp" alt="img"></p><p>Roadmap 不在乎用什么工具来描绘，可以用 PPT、Xmind 等工具，但是它脱离不了以下这些核心的要素，通过这些核心要素按一定逻辑组合起来，呈现出的就是 Roadmap 的样子。</p><h4 id="目标"><a href="# 目标" class="headerlink" title="目标"></a>目标 </h4><p> 给你这张蓝图定一个一句话的目标，这句目标能完美的概括出这张蓝图的重点。比如 C 端 O2O 产品目标叫“围绕多、快、好、省来打造极致的用户在线交易及服务体验”；再比如 B 端 CRM 产品目标叫“建设客户全生命周期移动化、数字化管理平台”。让别人首先看到这句目标，就能快速的了解到这张蓝图的核心宗旨和愿景。</p><h4 id="横轴 - 完整用户体验路径"><a href="# 横轴 - 完整用户体验路径" class="headerlink" title="横轴 - 完整用户体验路径"></a>横轴 - 完整用户体验路径</h4><blockquote><p>大多数 <strong>Roadmap 的横轴都是用时间轴来呈现，但是我更偏向于用用户体验路径来当横轴。</strong><br> 两者优劣点如下，大家可根据自己实际情况进行选择。</p></blockquote><p><strong>横轴 - 时间</strong></p><ul><li>优点：突出时间维度，能通盘清晰的看出每个时间段该做什么事</li><li>缺点：没有用户视角，缺乏横向逻辑性，比较难理解</li></ul><p><strong>横轴 - 用户体验路径</strong></p><ul><li>优点：站在用户视角，有横向逻辑性能串联整张<strong>Roadmap</strong></li><li>缺点：不能通盘看到各个时间段该做什么事</li></ul><p>将这款产品以用户体验路径拆解成几个阶段，再基于每个阶段识别出用户的核心动作，这样就形成横轴的用户体验路径。比如打车业务，可以分成上车前、车上、下车后 3 个阶段，每个阶段动作如下：</p><ul><li>上车前，提交行程、等待接单、等待司机到达</li><li>车上，乘车</li><li>下车后，支付、评价、开票、投诉</li></ul><p>将用户体验的关键阶段和动作识别出来，并基于此进行绘制每个阶段和动作场景下的 Roadmap，这样就是一幅完美的 Roadmap。</p><h4 id="纵轴 - 单个用户场景的蓝图"><a href="# 纵轴 - 单个用户场景的蓝图" class="headerlink" title="纵轴 - 单个用户场景的蓝图"></a>纵轴 - 单个用户场景的蓝图</h4><p><strong>1、用户行为</strong></p><p>用户行为主要是为了细化用户体验的关键阶段和动作。将动作拆解到具体的用户行为上。比如上车前的提交行程是一个动作，具体的用户行为是下载 &amp; 打开 App、注册 &amp; 登录、填写行程（上车点、终点、用车时间等），然后才是提交行程。将这个动作下的用户行为进行拆解，一方面可以更加清晰的了解完整的用户行为，另一方面 Roadmap 也能细化到每个用户行为上。</p><p>通常可以根据“影响转化率”这个维度来拆解动作下的用户行为，比如影响提交行程的转化率有以下用户行为：</p><p>下载 &amp; 打开滴滴出行 App&gt; 注册 &amp; 登录 &gt; 选择出行服务 &gt; 输入上车点 &gt; 输入终点 &gt; 确认用车时间 &gt; 选择车型，然后完成订单提交</p><p>再将相同节点完成的用户行为进行合并，最终提交行程下的用户行为就是：下载 &amp; 打开 App、注册 &amp; 登录、填写行程。</p><p><strong>2、接触点</strong></p><p>接触点主要指用户在上述动作过程中通过什么方式接触到什么样的人。这里的接触点可以分成 2 类：</p><ul><li>系统接触点：指用户在上述动作接触到哪些系统的哪些核心功能</li><li>人员接触点：指用户在上述动作接触到哪些人员</li></ul><p>比如等待司机这个动作下，</p><ul><li>系统接触点：等待司机页（查看司机预计达到时间、车牌号等信息）</li><li>人员接触点：司机联系我、我联系客服</li></ul><p>梳理关键阶段和动作下的接触点，是为了更好的了解到现有的功能支撑度和人员接触点。以系统和人员接触点为基础，构建对应动作下的 Roadmap，最终提高该动作下的用户体验和转化率等目标。</p><p><strong>3、用户蓝图</strong></p><p>用户蓝图这个环节是 Roadmap 的核心环节，应该要包含以下要素：</p><ul><li><strong>蓝图内容：</strong></li></ul><p>基于该动作下的用户痛点，输出对应的蓝图内容（即产品解决方案），可以是一条也可以是多条。输出的内容要能描述出该动作下“产品成功是长什么样的”。是站在用户视角下，该动作成功的样子。比如提交行程，对于用户来说，成功的样子就是要能快速提交行程，按用户行为可以拆解成 3 条蓝图内容：a、下载 &amp; 打开要快；b、注册 &amp; 登录要快；c、提交行程要快。</p><ul><li><strong>计划完成时间：</strong></li></ul><p>有了每条蓝图内容，就要明确好在什么时间点能够完成上线。因为 Roadmap 通常是按年输出，所以计划完成时间精确到月份即可。评估计划完成时间，需要考虑到蓝图内容难易程度、实现成本、难易程度、人力成本，以及过程中涉及到的产品调研、输出方案、开发测试等环节总耗时情况，最终输出对应的计划完成时间，而不是拍脑袋写个时间点。</p><ul><li><strong>重要程度：</strong></li></ul><p>将对应的蓝图内容按痛点程度进行拆解，通常越痛的重要程度越高。这就需要提前洞察用户痛点和识别痛点程度，基于此再进行重要程度标注。所以在描绘 Roadmap 之前，需先完成用户和业务调研，提前洞察用户所有痛点和痛点程度。</p><p><strong>4、衡量标准</strong></p><p>蓝图内容描绘的是“产品成功是长什么样的”，但是成没成功？成功到什么阶段？这些没法得知，所以需要一把”尺子“来衡量成功的标准。可以从定性和定量的两个维度，结合起来制定这把“尺子”。</p><ul><li>定性标准：指不能直接量化而需通过其他途径实现量化的评估指标。比如将实现过程进行初步分级。</li><li>定量标准：可以准确数量定义、精确衡量并能设定绩效目标的考核指标。定量也是针对过程，和定性的区别是要有明确的数值。</li></ul><p>比如转化率从 10%-&gt;30%，10% 指现状，30% 指成功的标准。所以制定定量标准的时候，需要先计算当前标准，并且基于现状 &amp; 未来蓝图，预测出成功的标准，这个预测标准要有依据，经得起推敲，而不是拍脑袋定的。</p><p><strong>5、业务支撑</strong></p><p>要完成蓝图内容，达到成功的样子，除了要有产品解决方案，还需要哪些业务支撑方案。即哪些业务部门需要参与哪些产品解决方案，便于更好的完成蓝图。不管是 C 端产品还是 B 端产品，要想实现蓝图内容，过程中都离不开业务部门进行支撑，比如前期一起制定业务规则、中期验收试点，后期上线推广，产品解决方案仅仅是蓝图的样子，如何将蓝图内容落地依赖业务支撑。</p><p><strong>6、系统支撑</strong></p><p>除了需要业务支撑，还少不了系统支撑。一个完整的 C 端 App 离开一套强大的后端系统支撑。B 端的系统同样需要相关领域的系统支撑。主要以业务场景相关的领域系统支撑为主，故障监控、数据分析等增值系统支撑为辅。</p><h3 id="四、设计 Roadmap 需要注意什么？"><a href="# 四、设计 Roadmap 需要注意什么？" class="headerlink" title="四、设计 Roadmap 需要注意什么？"></a>四、设计 Roadmap 需要注意什么？</h3><p>在设计和执行 Roadmap 过程中，应该关注以下 3 点：</p><h4 id="第 1 点：设定截止时间"><a href="# 第 1 点：设定截止时间" class="headerlink" title="第 1 点：设定截止时间"></a>第 1 点：设定截止时间 </h4><p> 这里的截止时间是指 Roadmap 是要在哪个时间点完成，是做 1 年的 Roadmap，还是 3 年的 Roadmap？1 年的 Roadmap 是产品 1 年后成功的样子，3 年的 Roadmap 是产品 3 年后成功的样子。不同的截止时间，Roadmap 内容丰富和完整度是不同的。</p><p>所以，第 1 步需要先设定截止时间。</p><h4 id="第 2 点：完成前置条件"><a href="# 第 2 点：完成前置条件" class="headerlink" title="第 2 点：完成前置条件"></a>第 2 点：完成前置条件 </h4><p> 怎么理解 Roadmap 的前置条件？其实可以拆解 Roadmap 目标“让用户未来能体验这款成功样子的产品！”这目标里包含 3 个关键信息，一个是用户，一个是未来，最后才是成功的样子。达到这个目标，开始设计 Roadmap 前，则需要完成以下 2 个前置条件：</p><ul><li><strong>用户调研</strong>：基于用户调研，内部了解现有业务场景，外部深度挖掘用户痛点和痒点，并按程度进行划分重要性。</li><li><strong>业务规划</strong>：培养业务敏感度，并提前了解中长期的业务规划内容，不贴合业务的 Roadmap，就是一张不能落地的图画，对后续产品工作毫无指导意义。</li></ul><h4 id="第 3 点：动态刷新"><a href="# 第 3 点：动态刷新" class="headerlink" title="第 3 点：动态刷新"></a>第 3 点：动态刷新</h4><p>Roadmap 不是一张静态图画，而是一张动态图画。随着时间推移，随着公司的战略变化，随着核心干系人变更等因素，都会影响到 Roadmap 内容。所以过程中遇到相关因素变化时，Roadmap 应该随着变化而变化，要及时动态的刷新，并同步给团队的每个成员，而不是一尘不变。</p><h3 id="五、总结"><a href="# 五、总结" class="headerlink" title="五、总结"></a>五、总结 </h3><p> 综上，一张 <strong>“好”</strong> 的 Roadmap 也需要遵循 SMART 原则。</p><blockquote><p><strong>SMART 原则：</strong><br>\1. 必须是具体的（Specific）<br>\2. 必须是可以衡量的（Measurable）<br>\3. 必须是可以达到的（Attainable）<br>\4. 要与其他目标具有一定的相关性(Relevant)<br>\5. 必须具有明确的截止期限（Time-bound）</p></blockquote><p>大家看完本篇文章，都可以尝试针对自己的产品设计一张 Roadmap。不用考虑自己有几年的产品经验？负责的产品规模多大？是不是负责核心模块？尝试设计一张 Roadmap 不仅是检验自己对产品的熟悉程度，也是培养自己用户思维和产品洞察力的过程。</p><h2 id="Nginx"><a href="#Nginx" class="headerlink" title="Nginx"></a>Nginx</h2><h3 id="一、Nginx 是什么？"><a href="# 一、Nginx 是什么？" class="headerlink" title="一、Nginx 是什么？"></a>一、Nginx 是什么？</h3><p>Nginx 是 lgor Sysoev 为 <strong> 俄罗斯访问量第二 </strong> 的 rambler.ru 站点设计开发的。从 2004 年发布至今，凭借开源的力量，已经接近成熟与完善。</p><p>Nginx 功能丰富，可作为<strong>HTTP 服务器，也可作为反向代理服务器</strong>，邮件服务器。支持 FastCGI、SSL、Virtual Host、URL Rewrite、Gzip 等功能。并且支持很多第三方的模块扩展。</p><p>Nginx 的稳定性、功能集、示例配置文件和低系统资源的消耗让他后来居上，在全球活跃的网站中有 12.18% 的使用比率，大约为 2220 万个网站。</p><p>Nginx (engine x) 是一个 <strong> 高性能的 HTTP 和反向代理 web 服务器</strong>，同时也提供了<strong>IMAP&#x2F;POP3&#x2F;SMTP 服务</strong>。Nginx 是由伊戈尔·赛索耶夫为俄罗斯访问量第二的 Rambler.ru 站点（俄文：Рамблер）开发的，第一个公开版本 0.1.0 发布于 2004 年 10 月 4 日。其将源代码以类 BSD 许可证的形式发布，因它的稳定性、丰富的功能集、简单的配置文件和低系统资源的消耗而闻名。2011 年 6 月 1 日，nginx 1.0.4 发布。<br>Nginx 是一款轻量级的 Web 服务器 &#x2F; 反向代理服务器及电子邮件（IMAP&#x2F;POP3）代理服务器，在 BSD-like 协议下发行。其特点是占有内存少，并发能力强，事实上 nginx 的并发能力在同类型的网页服务器中表现较好，中国大陆使用 nginx 网站用户有：百度、京东、新浪、网易、腾讯、淘宝等。<br>Nginx 是高性能的 HTTP 和反向代理的 web 服务器，处理高并发能力是十分强大的，能经受高负 载的考验, 有报告表明能支持高达 50,000 个并发连接数。<br>Nginx 支持热部署，启动简单，可以做到 7*24 不间断运行。几个月都不需要重新启动。</p><h3 id="二、Nginx 的反向代理（扩展：正向代理）"><a href="# 二、Nginx 的反向代理（扩展：正向代理）" class="headerlink" title="二、Nginx 的反向代理（扩展：正向代理）"></a>二、Nginx 的反向代理（扩展：正向代理）</h3><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404031058050.png" alt="img"></p><p>正向代理： 我们平时需要访问国外的浏览器是不是很慢，比如我们要看推特，看 GitHub 等等。我们直接用国内的服务器无法访问国外的服务器，或者是访问很慢。所以我们需要在本地搭建一个服务器来帮助我们去访问。那这种就是正向代理。（浏览器中配置代理服务器）</p><p>反向代理： 那什么是反向代理呢。比如：我们访问淘宝的时候，淘宝内部肯定不是只有一台服务器，它的内部有很多台服务器，那我们进行访问的时候，因为服务器中间 session 不共享，那我们是不是在服务器之间访问需要频繁登录，那这个时候淘宝搭建一个过渡服务器，对我们是没有任何影响的，我们是登录一次，但是访问所有，这种情况就是 反向代理。对我们来说，客户端对代理是无感知的，客户端不需要任何配置就可以访问，我们只需要把请求发送给反向代理服务器，由反向代理服务器去选择目标服务器获取数据后，再返回给客户端，此时反向代理服务器和目标服务器对外就是一个服务器，暴露的是代理服务器地址，隐藏了真实服务器的地址。（在服务器中配置代理服务器）</p><h3 id="三、Nginx 的负载均衡"><a href="# 三、Nginx 的负载均衡" class="headerlink" title="三、Nginx 的负载均衡"></a>三、Nginx 的负载均衡 </h3><p> 负载均衡建立在现有网络结构之上，它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。<br>负载均衡（Load Balance）其意思就是分摊到多个操作单元上进行执行，例如 Web 服务器、FTP 服务器、企业关键应用服务器和其它关键任务服务器等，从而共同完成工作任务。</p><p>简单来说就是：现有的请求使服务器压力太大无法承受，所有我们需要搭建一个服务器集群，去分担原先一个服务器所承受的压力，那现在我们有 ABCD 等等多台服务器，我们需要把请求分给这些服务器，但是服务器可能大小也有自己的不同，所以怎么分？如何分配更好？又是一个问题。</p><p>Nginx 给出来三种关于负载均衡的方式：</p><p><strong>轮询法（默认方法）</strong>：<br>每个请求按时间顺序逐一分配到不同的后端服务器，如果后端服务器宕掉，能自动剔除。<br>适合服务器配置相当，无状态且短平快的服务使用。也适用于图片服务器集群和纯静态页面服务器集群。<br><strong>weight 权重模式（加权轮询）</strong>：<br>指定轮询几率，weight 和访问比率成正比，用于后端服务器性能不均的情况。<br>这种方式比较灵活，当后端服务器性能存在差异的时候，通过配置权重，可以让服务器的性能得到充分发挥，有效利用资源。weight 和访问比率成正比，用于后端服务器性能不均的情况。权重越高，在被访问的概率越大 <br><strong>ip_hash</strong>：<br> 上述方式存在一个问题就是说，在负载均衡系统中，假如用户在某台服务器上登录了，那么该用户第二次请求的时候，因为我们是负载均衡系统，每次请求都会重新定位到服务器集群中的某一个，那么已经登录某一个服务器的用户再重新定位到另一个服务器，其登录信息将会丢失，这样显然是不妥的。<br>我们可以采用 ip_hash 指令解决这个问题，如果客户已经访问了某个服务器，当用户再次访问时，会将该请求通过哈希算法，自动定位到该服务器。每个请求按访问 ip 的 hash 结果分配，这样每个访客固定访问一个后端服务器，可以解决 session 的问题。</p><p>原文链接：<a href="https://blog.csdn.net/hyfsbxg/article/details/122322125">https://blog.csdn.net/hyfsbxg/article/details/122322125</a></p><p><a href="https://www.runoob.com/w3cnote/nginx-setup-intro.html">Nginx 配置详解 | 菜鸟教程 (runoob.com)</a></p><h2 id="CAD 算法"><a href="#CAD 算法" class="headerlink" title="CAD 算法"></a>CAD 算法</h2><p><a href="https://www.bilibili.com/video/BV1dh411C7Pf">https://www.bilibili.com/video/BV1dh411C7Pf</a></p><p>CAD（Computer-Aided Design，计算机辅助设计）是指利用计算机技术对产品进行设计、绘制、分析和优化的过程。CAD 模型则是 CAD 软件生成的用于表示产品、零件或构件的三维模型。这些模型通常由各种几何形状、曲线、表面和体积组成，以精确地描述设计的对象。</p><p>CAD 模型在工程设计、制造、建筑和其他领域中被广泛使用。它们可以用于创建产品的原型、进行工程分析、进行数字化加工和打印等。CAD 模型可以通过 CAD 软件创建，如 AutoCAD、SolidWorks、CATIA、Pro&#x2F;ENGINEER 等。</p><p>在 CAD 模型中，设计师可以添加尺寸、约束、材料属性和其他特性，以使模型更具实用性和可操作性。这些模型还可以与其他工程软件集成，以便进行进一步的分析、仿真和生产准备工作。</p><p>总的来说，CAD 模型是一种重要的工具，它在现代工程设计和制造中起着至关重要的作用，为设计师提供了精确、可视化和易于操作的设计工具。</p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404031111729.png" alt="image-20240403111126651"></p><p><img src="https://raw.githubusercontent.com/AngelYang23/Picture/master/Pic/202404031116664.png" alt="image-20240403111655587"></p><h2 id="数值分析"><a href="# 数值分析" class="headerlink" title="数值分析"></a>数值分析</h2><p><a href="https://www.bilibili.com/video/BV1sh41127RZ">https://www.bilibili.com/video/BV1sh41127RZ</a></p><p><a href="https://www.bilibili.com/video/BV1iJ411473n">https://www.bilibili.com/video/BV1iJ411473n</a></p><p>当涉及到数值计算方法时，这些算法是解决工程和科学领域中各种数学问题的常用工具。下面我将简要解释这些算法的基本原理：</p><ol><li><strong>有限差分法（Finite Difference Method）</strong>：<ul><li>有限差分法是一种数值计算方法，用于求解微分方程或积分方程的数值解。它通过将函数在空间上进行离散化，并将微分方程中的导数用差分来近似，从而将微分方程转化为代数方程组，进而求解。</li><li>基本思想是将求解域划分为离散网格，并在每个网格点上近似原方程，然后通过差分近似导数，得到一个离散的代数方程系统，最终通过迭代或其他数值方法求解得到数值解。</li></ul></li><li><strong>有限元法（Finite Element Method）</strong>：<ul><li>有限元法是一种数值计算方法，用于求解偏微分方程的近似解。它将求解域划分为有限数量的简单几何形状单元，如三角形、四边形或六面体等，并在每个单元上近似原偏微分方程。</li><li>基本思想是通过在每个单元上选择适当的试验函数来近似原方程，然后将所有单元的方程组合成一个整体方程组，通过求解这个方程组来得到数值解。</li></ul></li><li><strong>线性方程组求解算法</strong>：<ul><li>线性方程组求解算法是一种用于解决线性方程组的数值方法。常用的算法包括高斯消元法、LU 分解、迭代法（如雅可比迭代法、高斯 - 赛德尔迭代法等）以及共轭梯度法等。</li><li>这些算法旨在有效地求解形如 Ax&#x3D;b 的线性方程组，其中 A 是一个已知的系数矩阵，b 是一个已知的向量，而 x 是待求解的未知向量。</li></ul></li><li><strong>矩阵分解算法</strong>：<ul><li>矩阵分解算法是将一个矩阵分解为多个简单矩阵的方法，常用的分解包括 LU 分解、QR 分解、奇异值分解（SVD）以及特征值分解等。</li><li>这些分解可以帮助简化矩阵的运算，降低计算复杂度，同时在数值计算中有广泛的应用，如求解线性方程组、矩阵求逆、最小二乘拟合等。</li></ul></li><li><strong>并行计算算法</strong>：<ul><li>并行计算算法是一种利用多个计算资源同时工作来加速计算过程的方法。常用的并行计算技术包括并行编程模型（如 MPI、OpenMP）、并行算法（如并行矩阵乘法、并行排序等）以及分布式计算等。</li><li>这些算法和技术可用于加速大规模数据处理、复杂模拟和仿真等计算密集型任务，提高计算效率和性能。</li></ul></li></ol><p>这些算法都是数值计算领域中的基础工具，对于解决各种实际问题具有重要的作用。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;本人很懒，不多介绍！&lt;/p&gt;</summary>
    
    
    
    <category term="Study" scheme="http://example.com/categories/Study/"/>
    
    
    <category term="blog" scheme="http://example.com/tags/blog/"/>
    
    <category term="[object Object]" scheme="http://example.com/tags/object-Object/"/>
    
  </entry>
  
</feed>
