diff options
Diffstat (limited to 'search.xml')
| -rw-r--r-- | search.xml | 319 |
1 files changed, 179 insertions, 140 deletions
@@ -845,7 +845,7 @@ </ol> <p>Prisma ORM 在设计上就考虑了 N+1 问题,并提供了一种既方便开发者又高效的解决方案。当使用 Prisma Client 查询数据并需要包含关联模型时,Prisma 会自动优化查询,<strong>避免产生 N+1 查询</strong>,主要通过<strong>关系查询(Relation Queries)</strong>中的 <code>include</code> 选项或嵌套读取(nested reads)来实现这一点:</p> <p>假设想获取所有用户及其发布的帖子,使用 Prisma Client,可以这样写:</p> -<figure class="highlight typescript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> { <span class="title class_">PrismaClient</span> } <span class="keyword">from</span> <span class="string">'@prisma/client'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> prisma = <span class="keyword">new</span> <span class="title class_">PrismaClient</span>()</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">getUsersWithPosts</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">const</span> usersWithPosts = <span class="keyword">await</span> prisma.<span class="property">user</span>.<span class="title function_">findMany</span>({</span><br><span class="line"> <span class="attr">include</span>: {</span><br><span class="line"> <span class="attr">posts</span>: <span class="literal">true</span>, <span class="comment">// 指示 Prisma 加载关联的 posts</span></span><br><span class="line"> },</span><br><span class="line"> })</span><br><span class="line"> <span class="comment">// usersWithPosts 包含了用户列表,每个用户对象中都有一个 posts 数组</span></span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(usersWithPosts)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="title function_">getUsersWithPosts</span>()</span><br><span class="line"> .<span class="title function_">catch</span>(<span class="function">(<span class="params">e</span>) =></span> {</span><br><span class="line"> <span class="keyword">throw</span> e</span><br><span class="line"> })</span><br><span class="line"> .<span class="title function_">finally</span>(<span class="keyword">async</span> () => {</span><br><span class="line"> <span class="keyword">await</span> prisma.$disconnect()</span><br><span class="line"> })</span><br></pre></td></tr></table></figure> +<figure class="highlight typescript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> { <span class="title class_">PrismaClient</span> } <span class="keyword">from</span> <span class="string">'@prisma/client'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> prisma = <span class="keyword">new</span> <span class="title class_">PrismaClient</span>()</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">getUsersWithPosts</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">const</span> usersWithPosts = <span class="keyword">await</span> prisma.<span class="property">user</span>.<span class="title function_">findMany</span>({</span><br><span class="line"> <span class="attr">include</span>: {</span><br><span class="line"> <span class="attr">posts</span>: <span class="literal">true</span>, <span class="comment">// 指示 Prisma 加载关联的 posts</span></span><br><span class="line"> },</span><br><span class="line"> })</span><br><span class="line"> <span class="comment">// usersWithPosts 包含了用户列表,每个用户对象中都有一个 posts 数组</span></span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(usersWithPosts)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="title function_">getUsersWithPosts</span>()</span><br><span class="line"> .<span class="title function_">catch</span>(<span class="function">(<span class="params">e</span>) =></span> {</span><br><span class="line"> <span class="keyword">throw</span> e</span><br><span class="line"> })</span><br><span class="line"> .<span class="title function_">finally</span>(<span class="title function_">async</span> () => {</span><br><span class="line"> <span class="keyword">await</span> prisma.$disconnect()</span><br><span class="line"> })</span><br></pre></td></tr></table></figure> <p>当执行上述查询时,Prisma <strong>不会</strong> 生成 N+1 个 SQL 查询。而是首先会分析请求,并将其转化为数量非常有限的高效 SQL 查询。对于上面这个一对多关系的 <code>include</code> 查询,Prisma 通常会执行以下<strong>两步</strong>(类似于批量加载策略):</p> <ol> @@ -1139,67 +1139,6 @@ </tags> </entry> <entry> - <title>OCaml News 2024-5</title> - <url>/2024/06/27/OCaml-News-2024-5/</url> - <content><![CDATA[<h2 id="语言的发展"><a href="#语言的发展" class="headerlink" title="语言的发展"></a>语言的发展</h2><ul> -<li><a href="https://link.zhihu.com/?target=https://github.com/ocaml/ocaml/pull/13097">Immutable arrays #13097: This PR proposes to add immutable arrays to OCaml.</a></li> -<li><a href="https://link.zhihu.com/?target=https://github.com/ocaml/ocaml/pull/13199">Support running native debuggers in ocamltest #13199</a>.</li> -<li><a href="https://link.zhihu.com/?target=https://github.com/ocaml/ocaml/pull/13152">The Pattern-Matching Bug: fix totality information by gasche · Pull Request #13152 · ocaml/ocaml</a>.</li> -<li><a href="https://link.zhihu.com/?target=https://github.com/ocaml/ocaml/pull/11974%23discussion_r1621832545">Add loongarch architecture support #11974</a>.</li> -<li><a href="https://link.zhihu.com/?target=https://github.com/ocaml/ocaml/pull/13101">Add Stdlib.todo #13101</a>.</li> -<li><a href="https://link.zhihu.com/?target=https://tarides.com/blog/2024-06-26-enhancing-the-ocaml-org-community-page-boosting-ux-and-ui-based-on-user-research/">Enhancing the OCaml.org Community Page: Boosting UX and UI Based on User Research.</a></li> -<li><a href="https://link.zhihu.com/?target=https://tarides.com/blog/2024-05-22-launching-the-first-class-windows-project/">Launching the First-Class Windows Project</a>.</li> -</ul> -<h2 id="新消息"><a href="#新消息" class="headerlink" title="新消息"></a>新消息</h2><ul> -<li><p><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/ann-project-wide-occurrences-in-merlin-and-lsp/14847">[ANN] Project wide occurrences in Merlin and LSP</a>.</p> -</li> -<li><p><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/ann-opam-2-2-0-rc1-release/14842">[ANN] opam 2.2.0 rc1 release</a>.</p> -</li> -<li><p><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/ann-first-release-of-baby/14840">[ANN] First release of baby</a>.</p> -</li> -<li><p><a href="https://link.zhihu.com/?target=https://github.com/fpottier/baby">baby</a> is an OCaml library that offers several implementations of balanced binary search trees.</p> -</li> -<li><p><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/ann-preview-of-stripe-client-and-mock-server-dkstdrestapis/14841">[ANN] Preview of Stripe client and mock server - DkStdRestApis</a>.</p> -</li> -<li><p><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/ann-caisar-release-2-0-a-platform-for-characterizing-ai-safety-and-robustness/14831">[ANN] CAISAR release 2.0, a platform for characterizing AI safety and robustness</a>.</p> -</li> -<li><p><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/ann-forester-4-1/14800">[ANN] Forester 4.1</a>.</p> -</li> -<li><p><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/ann-dream-html-pure-html-3-5-2/14808">[ANN] dream-html & pure-html 3.5.2</a></p> -</li> -</ul> -<h2 id="有价值的文章"><a href="#有价值的文章" class="headerlink" title="有价值的文章"></a>有价值的文章</h2><ul> -<li><a href="https://link.zhihu.com/?target=https://tarides.com/blog/2024-06-19-keeping-up-with-the-compiler-how-we-help-maintain-the-ocaml-language/">Keeping Up With the Compiler: How we Help Maintain the OCaml Language</a></li> -<li><a href="https://link.zhihu.com/?target=https://github.com/ocaml/ocaml/pull/10995">Explain mapping between OCaml memory model and C.</a></li> -<li><a href="https://link.zhihu.com/?target=https://xavierleroy.org/CdF/2023-2024/index.html">Control structures – Xavier Leroy</a>.</li> -<li><a href="https://link.zhihu.com/?target=https://dev.to/chshersh/8-months-of-ocaml-after-8-years-of-haskell-in-production-h96">8 months of OCaml after 8 years of Haskell in production</a>.</li> -<li><a href="https://link.zhihu.com/?target=https://hypirion.com/musings/getting-ocaml-through-the-eye-of-a-needle">Getting OCaml Through the Eye of a Needle</a>.</li> -<li><a href="https://link.zhihu.com/?target=https://tarides.com/blog/2024-06-05-secure-from-the-ground-up-introducing-the-fides-project-combining-risc-v-and-mirageos/">Secure From the Ground Up: Introducing the FIDES Project Combining RISC-V and MirageOS.</a></li> -<li><a href="https://link.zhihu.com/?target=https://tarides.com/blog/2024-05-29-effective-ml-through-merlin-s-destruct-command/">Effective ML Through Merlin’s Destruct Command.</a></li> -<li><a href="https://link.zhihu.com/?target=https://blog.osau.re/articles/reproducible.html">Dinosaure’s website - Reproducibility!</a></li> -<li><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/experiments-in-jitting/14853">Experiments in JITting</a>.</li> -<li><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/how-to-write-an-efficient-cp-r-clone-with-eio/14848">How to write an efficient ‘cp -R’ clone with Eio?</a></li> -<li><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/generating-infix-extension-nodes-with-ppxlib/14833">Generating infix extension nodes with Ppxlib</a>.</li> -<li><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/this-made-my-day-float-to-string-and-string-of-float-without-loss-of-precision/14825">This made my day (float to string and string of float without loss of precision)</a>.</li> -<li><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/help-with-cryptic-dependency-cycle-compile-errors-using-dune-build/14864">Help with cryptic dependency cycle compile errors using <code>dune build</code></a>.</li> -<li><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/why-does-relaxed-value-restriction-treat-function-types-differently/14802">Why does relaxed value restriction treat function types differently?</a></li> -<li><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/binding-existentials-in-a-non-uniform-gadt/14809">Binding existentials in a non-uniform GADT</a>.</li> -</ul> -<h2 id="有趣的项目"><a href="#有趣的项目" class="headerlink" title="有趣的项目"></a>有趣的项目</h2><ul> -<li><a href="https://link.zhihu.com/?target=https://ocaml.org/p/ocaml-index/latest">ocaml-index 1.0 (latest) · OCaml Package: A tool that indexes value usages from cmt files</a>.</li> -<li><a href="https://link.zhihu.com/?target=https://ocaml.org/p/fileutils/latest">fileutils 0.6.4 (latest) · OCaml Package: API to manipulate files (POSIX like) and filenames.</a></li> -<li><a href="https://link.zhihu.com/?target=https://ocaml.org/p/pure-html/latest">pure-html 3.5.2 (latest) · OCaml Package</a></li> -<li><a href="https://link.zhihu.com/?target=https://github.com/fpottier/baby">GitHub - fpottier/baby: A balanced binary search tree library for OCaml</a>.</li> -<li><a href="https://link.zhihu.com/?target=https://github.com/akabe/ocaml-jupyter">GitHub - akabe/ocaml-jupyter: An OCaml kernel for Jupyter (IPython) notebook</a>.</li> -<li><a href="https://link.zhihu.com/?target=https://github.com/robur-coop/orb">Github - robur-coop/orb: check opam package reproductibility.</a></li> -<li><a href="https://link.zhihu.com/?target=https://github.com/ocaml-multicore/dscheck%23motivation">Github - ocaml-multicore/dscheck: Experimental model checker for testing concurrent algorithms.</a></li> -</ul> -]]></content> - <tags> - <tag>Technique</tag> - </tags> - </entry> - <entry> <title>OCaml News 2024-4</title> <url>/2024/07/01/OCaml-News-2024-4/</url> <content><![CDATA[<h2 id="那么接下来"><a href="#那么接下来" class="headerlink" title="那么接下来"></a>那么接下来</h2><ul> @@ -1319,6 +1258,67 @@ </tags> </entry> <entry> + <title>OCaml News 2024-5</title> + <url>/2024/06/27/OCaml-News-2024-5/</url> + <content><![CDATA[<h2 id="语言的发展"><a href="#语言的发展" class="headerlink" title="语言的发展"></a>语言的发展</h2><ul> +<li><a href="https://link.zhihu.com/?target=https://github.com/ocaml/ocaml/pull/13097">Immutable arrays #13097: This PR proposes to add immutable arrays to OCaml.</a></li> +<li><a href="https://link.zhihu.com/?target=https://github.com/ocaml/ocaml/pull/13199">Support running native debuggers in ocamltest #13199</a>.</li> +<li><a href="https://link.zhihu.com/?target=https://github.com/ocaml/ocaml/pull/13152">The Pattern-Matching Bug: fix totality information by gasche · Pull Request #13152 · ocaml/ocaml</a>.</li> +<li><a href="https://link.zhihu.com/?target=https://github.com/ocaml/ocaml/pull/11974%23discussion_r1621832545">Add loongarch architecture support #11974</a>.</li> +<li><a href="https://link.zhihu.com/?target=https://github.com/ocaml/ocaml/pull/13101">Add Stdlib.todo #13101</a>.</li> +<li><a href="https://link.zhihu.com/?target=https://tarides.com/blog/2024-06-26-enhancing-the-ocaml-org-community-page-boosting-ux-and-ui-based-on-user-research/">Enhancing the OCaml.org Community Page: Boosting UX and UI Based on User Research.</a></li> +<li><a href="https://link.zhihu.com/?target=https://tarides.com/blog/2024-05-22-launching-the-first-class-windows-project/">Launching the First-Class Windows Project</a>.</li> +</ul> +<h2 id="新消息"><a href="#新消息" class="headerlink" title="新消息"></a>新消息</h2><ul> +<li><p><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/ann-project-wide-occurrences-in-merlin-and-lsp/14847">[ANN] Project wide occurrences in Merlin and LSP</a>.</p> +</li> +<li><p><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/ann-opam-2-2-0-rc1-release/14842">[ANN] opam 2.2.0 rc1 release</a>.</p> +</li> +<li><p><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/ann-first-release-of-baby/14840">[ANN] First release of baby</a>.</p> +</li> +<li><p><a href="https://link.zhihu.com/?target=https://github.com/fpottier/baby">baby</a> is an OCaml library that offers several implementations of balanced binary search trees.</p> +</li> +<li><p><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/ann-preview-of-stripe-client-and-mock-server-dkstdrestapis/14841">[ANN] Preview of Stripe client and mock server - DkStdRestApis</a>.</p> +</li> +<li><p><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/ann-caisar-release-2-0-a-platform-for-characterizing-ai-safety-and-robustness/14831">[ANN] CAISAR release 2.0, a platform for characterizing AI safety and robustness</a>.</p> +</li> +<li><p><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/ann-forester-4-1/14800">[ANN] Forester 4.1</a>.</p> +</li> +<li><p><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/ann-dream-html-pure-html-3-5-2/14808">[ANN] dream-html & pure-html 3.5.2</a></p> +</li> +</ul> +<h2 id="有价值的文章"><a href="#有价值的文章" class="headerlink" title="有价值的文章"></a>有价值的文章</h2><ul> +<li><a href="https://link.zhihu.com/?target=https://tarides.com/blog/2024-06-19-keeping-up-with-the-compiler-how-we-help-maintain-the-ocaml-language/">Keeping Up With the Compiler: How we Help Maintain the OCaml Language</a></li> +<li><a href="https://link.zhihu.com/?target=https://github.com/ocaml/ocaml/pull/10995">Explain mapping between OCaml memory model and C.</a></li> +<li><a href="https://link.zhihu.com/?target=https://xavierleroy.org/CdF/2023-2024/index.html">Control structures – Xavier Leroy</a>.</li> +<li><a href="https://link.zhihu.com/?target=https://dev.to/chshersh/8-months-of-ocaml-after-8-years-of-haskell-in-production-h96">8 months of OCaml after 8 years of Haskell in production</a>.</li> +<li><a href="https://link.zhihu.com/?target=https://hypirion.com/musings/getting-ocaml-through-the-eye-of-a-needle">Getting OCaml Through the Eye of a Needle</a>.</li> +<li><a href="https://link.zhihu.com/?target=https://tarides.com/blog/2024-06-05-secure-from-the-ground-up-introducing-the-fides-project-combining-risc-v-and-mirageos/">Secure From the Ground Up: Introducing the FIDES Project Combining RISC-V and MirageOS.</a></li> +<li><a href="https://link.zhihu.com/?target=https://tarides.com/blog/2024-05-29-effective-ml-through-merlin-s-destruct-command/">Effective ML Through Merlin’s Destruct Command.</a></li> +<li><a href="https://link.zhihu.com/?target=https://blog.osau.re/articles/reproducible.html">Dinosaure’s website - Reproducibility!</a></li> +<li><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/experiments-in-jitting/14853">Experiments in JITting</a>.</li> +<li><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/how-to-write-an-efficient-cp-r-clone-with-eio/14848">How to write an efficient ‘cp -R’ clone with Eio?</a></li> +<li><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/generating-infix-extension-nodes-with-ppxlib/14833">Generating infix extension nodes with Ppxlib</a>.</li> +<li><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/this-made-my-day-float-to-string-and-string-of-float-without-loss-of-precision/14825">This made my day (float to string and string of float without loss of precision)</a>.</li> +<li><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/help-with-cryptic-dependency-cycle-compile-errors-using-dune-build/14864">Help with cryptic dependency cycle compile errors using <code>dune build</code></a>.</li> +<li><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/why-does-relaxed-value-restriction-treat-function-types-differently/14802">Why does relaxed value restriction treat function types differently?</a></li> +<li><a href="https://link.zhihu.com/?target=https://discuss.ocaml.org/t/binding-existentials-in-a-non-uniform-gadt/14809">Binding existentials in a non-uniform GADT</a>.</li> +</ul> +<h2 id="有趣的项目"><a href="#有趣的项目" class="headerlink" title="有趣的项目"></a>有趣的项目</h2><ul> +<li><a href="https://link.zhihu.com/?target=https://ocaml.org/p/ocaml-index/latest">ocaml-index 1.0 (latest) · OCaml Package: A tool that indexes value usages from cmt files</a>.</li> +<li><a href="https://link.zhihu.com/?target=https://ocaml.org/p/fileutils/latest">fileutils 0.6.4 (latest) · OCaml Package: API to manipulate files (POSIX like) and filenames.</a></li> +<li><a href="https://link.zhihu.com/?target=https://ocaml.org/p/pure-html/latest">pure-html 3.5.2 (latest) · OCaml Package</a></li> +<li><a href="https://link.zhihu.com/?target=https://github.com/fpottier/baby">GitHub - fpottier/baby: A balanced binary search tree library for OCaml</a>.</li> +<li><a href="https://link.zhihu.com/?target=https://github.com/akabe/ocaml-jupyter">GitHub - akabe/ocaml-jupyter: An OCaml kernel for Jupyter (IPython) notebook</a>.</li> +<li><a href="https://link.zhihu.com/?target=https://github.com/robur-coop/orb">Github - robur-coop/orb: check opam package reproductibility.</a></li> +<li><a href="https://link.zhihu.com/?target=https://github.com/ocaml-multicore/dscheck%23motivation">Github - ocaml-multicore/dscheck: Experimental model checker for testing concurrent algorithms.</a></li> +</ul> +]]></content> + <tags> + <tag>Technique</tag> + </tags> + </entry> + <entry> <title>OCaml News 2024-6</title> <url>/2024/07/23/OCaml-News-2024-6/</url> <content><![CDATA[<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line"> ^o3</span><br><span class="line">~/\_/\_|)</span><br><span class="line">|/=_=\|</span><br><span class="line">" "</span><br></pre></td></tr></table></figure> @@ -1618,7 +1618,7 @@ <p>一对一的 self-relation 需要两个端点,即使这两个端点是同一条数据。</p> </blockquote> <p>而在关系型数据库中,一对一的 self-relation 可以用如下 SQL 描述:</p> -<figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> "User" (</span><br><span class="line"> id SERIAL <span class="keyword">PRIMARY</span> KEY,</span><br><span class="line"> "name" TEXT,</span><br><span class="line"> "successorId" <span class="type">INTEGER</span></span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="keyword">ALTER</span> <span class="keyword">TABLE</span> "User" <span class="keyword">ADD</span> <span class="keyword">CONSTRAINT</span> fk_successor_user <span class="keyword">FOREIGN</span> KEY ("successorId") <span class="keyword">REFERENCES</span> "User" (id);</span><br><span class="line"></span><br><span class="line"><span class="keyword">ALTER</span> <span class="keyword">TABLE</span> "User" <span class="keyword">ADD</span> <span class="keyword">CONSTRAINT</span> successor_unique <span class="keyword">UNIQUE</span> ("successorId");</span><br></pre></td></tr></table></figure> +<figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">CREATE TABLE</span> "User" (</span><br><span class="line"> id SERIAL <span class="keyword">PRIMARY KEY</span>,</span><br><span class="line"> "name" TEXT,</span><br><span class="line"> "successorId" <span class="type">INTEGER</span></span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="keyword">ALTER TABLE</span> "User" <span class="keyword">ADD CONSTRAINT</span> fk_successor_user <span class="keyword">FOREIGN KEY</span> ("successorId") <span class="keyword">REFERENCES</span> "User" (id);</span><br><span class="line"></span><br><span class="line"><span class="keyword">ALTER TABLE</span> "User" <span class="keyword">ADD CONSTRAINT</span> successor_unique <span class="keyword">UNIQUE</span> ("successorId");</span><br></pre></td></tr></table></figure> <h2 id="一对多"><a href="#一对多" class="headerlink" title="一对多"></a>一对多</h2><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">model User {</span><br><span class="line"> id Int @id @default(autoincrement())</span><br><span class="line"> name String?</span><br><span class="line"> teacherId Int?</span><br><span class="line"> teacher User? @relation("TeacherStudents", fields: [teacherId], references: [id])</span><br><span class="line"> students User[] @relation("TeacherStudents")</span><br><span class="line">}</span><br></pre></td></tr></table></figure> @@ -1631,7 +1631,7 @@ <p>可以通过将 <code>teacher</code> 字段设<a href="https://www.prisma.io/docs/orm/prisma-schema/data-model/models#optional-and-mandatory-fields">为 required</a> 来要求每个 User 都有一名 teacher。</p> </blockquote> <p>用 SQL 描述 User model:</p> -<figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> "User" (</span><br><span class="line"> id SERIAL <span class="keyword">PRIMARY</span> KEY,</span><br><span class="line"> "name" TEXT,</span><br><span class="line"> "teacherId" <span class="type">INTEGER</span></span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="keyword">ALTER</span> <span class="keyword">TABLE</span> "User" <span class="keyword">ADD</span> <span class="keyword">CONSTRAINT</span> fk_teacherid_user <span class="keyword">FOREIGN</span> KEY ("teacherId") <span class="keyword">REFERENCES</span> "User" (id);</span><br></pre></td></tr></table></figure> +<figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">CREATE TABLE</span> "User" (</span><br><span class="line"> id SERIAL <span class="keyword">PRIMARY KEY</span>,</span><br><span class="line"> "name" TEXT,</span><br><span class="line"> "teacherId" <span class="type">INTEGER</span></span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="keyword">ALTER TABLE</span> "User" <span class="keyword">ADD CONSTRAINT</span> fk_teacherid_user <span class="keyword">FOREIGN KEY</span> ("teacherId") <span class="keyword">REFERENCES</span> "User" (id);</span><br></pre></td></tr></table></figure> <p><code>teacherId</code> 没有使用 <code>UNIQUE</code> 约束,这代表着多个 students 可以有同一个 teacher</p> <h2 id="多对多"><a href="#多对多" class="headerlink" title="多对多"></a>多对多</h2><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">model User {</span><br><span class="line"> id Int @id @default(autoincrement())</span><br><span class="line"> name String?</span><br><span class="line"> followedBy User[] @relation("UserFollows")</span><br><span class="line"> following User[] @relation("UserFollows")</span><br><span class="line">}</span><br></pre></td></tr></table></figure> @@ -1648,7 +1648,7 @@ <figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">model User {</span><br><span class="line"> id Int @id @default(autoincrement())</span><br><span class="line"> name String?</span><br><span class="line"> followedBy Follows[] @relation("followedBy")</span><br><span class="line"> following Follows[] @relation("following")</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">model Follows {</span><br><span class="line"> followedBy User @relation("followedBy", fields: [followedById], references: [id])</span><br><span class="line"> followedById Int</span><br><span class="line"> following User @relation("following", fields: [followingId], references: [id])</span><br><span class="line"> followingId Int</span><br><span class="line"></span><br><span class="line"> @@id([followingId, followedById])</span><br><span class="line">}</span><br></pre></td></tr></table></figure> <p>在关系型数据库中,可以用如下 SQL 描述:</p> -<figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> "User" (</span><br><span class="line"> id <span class="type">integer</span> <span class="keyword">DEFAULT</span> nextval(<span class="string">'"User_id_seq"'</span>::regclass) <span class="keyword">PRIMARY</span> KEY,</span><br><span class="line"> name text</span><br><span class="line">);</span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> "_UserFollows" (</span><br><span class="line"> "A" <span class="type">integer</span> <span class="keyword">NOT</span> <span class="keyword">NULL</span> <span class="keyword">REFERENCES</span> "User"(id) <span class="keyword">ON</span> <span class="keyword">DELETE</span> CASCADE <span class="keyword">ON</span> <span class="keyword">UPDATE</span> CASCADE,</span><br><span class="line"> "B" <span class="type">integer</span> <span class="keyword">NOT</span> <span class="keyword">NULL</span> <span class="keyword">REFERENCES</span> "User"(id) <span class="keyword">ON</span> <span class="keyword">DELETE</span> CASCADE <span class="keyword">ON</span> <span class="keyword">UPDATE</span> CASCADE</span><br><span class="line">);</span><br></pre></td></tr></table></figure> +<figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">CREATE TABLE</span> "User" (</span><br><span class="line"> id <span class="type">integer</span> <span class="keyword">DEFAULT</span> nextval(<span class="string">'"User_id_seq"'</span>::regclass) <span class="keyword">PRIMARY KEY</span>,</span><br><span class="line"> name text</span><br><span class="line">);</span><br><span class="line"><span class="keyword">CREATE TABLE</span> "_UserFollows" (</span><br><span class="line"> "A" <span class="type">integer</span> <span class="keyword">NOT NULL</span> <span class="keyword">REFERENCES</span> "User"(id) <span class="keyword">ON</span> <span class="keyword">DELETE</span> CASCADE <span class="keyword">ON</span> <span class="keyword">UPDATE</span> CASCADE,</span><br><span class="line"> "B" <span class="type">integer</span> <span class="keyword">NOT NULL</span> <span class="keyword">REFERENCES</span> "User"(id) <span class="keyword">ON</span> <span class="keyword">DELETE</span> CASCADE <span class="keyword">ON</span> <span class="keyword">UPDATE</span> CASCADE</span><br><span class="line">);</span><br></pre></td></tr></table></figure> <h2 id="在同一模型上建立多个-self-relations"><a href="#在同一模型上建立多个-self-relations" class="headerlink" title="在同一模型上建立多个 self-relations"></a>在同一模型上建立多个 self-relations</h2><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">model User {</span><br><span class="line"> id Int @id @default(autoincrement())</span><br><span class="line"> name String?</span><br><span class="line"> teacherId Int?</span><br><span class="line"> teacher User? @relation("TeacherStudents", fields: [teacherId], references: [id])</span><br><span class="line"> students User[] @relation("TeacherStudents")</span><br><span class="line"> followedBy User[] @relation("UserFollows")</span><br><span class="line"> following User[] @relation("UserFollows")</span><br><span class="line">}</span><br></pre></td></tr></table></figure> @@ -1713,10 +1713,10 @@ <li><code>IGenericRepository</code> 中定义的函数是每个 <em>Repository</em> 公开的通用存储函数。</li> </ul> <p>以上这些就是对业务中的实体的 <em>Repository</em> 抽象,这样就隔离开了业务和存储逻辑,例如使用 MongoDB,可以实现一个 <code>MongoGenericRepository</code>:</p> -<figure class="highlight typescript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> { <span class="title class_">Model</span> } <span class="keyword">from</span> <span class="string">'mongoose'</span>;</span><br><span class="line"><span class="keyword">import</span> { <span class="title class_">IGenericRepository</span> } <span class="keyword">from</span> <span class="string">'../../../core'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">MongoGenericRepository</span><T> <span class="keyword">implements</span> <span class="title class_">IGenericRepository</span><T> {</span><br><span class="line"> <span class="keyword">private</span> <span class="attr">_repository</span>: <span class="title class_">Model</span><T>;</span><br><span class="line"> <span class="keyword">private</span> <span class="attr">_populateOnFind</span>: <span class="built_in">string</span>[];</span><br><span class="line"></span><br><span class="line"> <span class="title function_">constructor</span>(<span class="params">repository: Model<T>, populateOnFind: <span class="built_in">string</span>[] = []</span>) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">_repository</span> = repository;</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">_populateOnFind</span> = populateOnFind;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="title function_">getAll</span>(): <span class="title class_">Promise</span><T[]> {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_repository</span>.<span class="title function_">find</span>().<span class="title function_">populate</span>(<span class="variable language_">this</span>.<span class="property">_populateOnFind</span>).<span class="title function_">exec</span>();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="title function_">get</span>(<span class="attr">id</span>: <span class="built_in">any</span>): <span class="title class_">Promise</span><T> {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_repository</span>.<span class="title function_">findById</span>(id).<span class="title function_">populate</span>(<span class="variable language_">this</span>.<span class="property">_populateOnFind</span>).<span class="title function_">exec</span>();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="title function_">create</span>(<span class="attr">item</span>: T): <span class="title class_">Promise</span><T> {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_repository</span>.<span class="title function_">create</span>(item);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="title function_">update</span>(<span class="params">id: <span class="built_in">string</span>, item: T</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_repository</span>.<span class="title function_">findByIdAndUpdate</span>(id, item);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure> +<figure class="highlight typescript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> { <span class="title class_">Model</span> } <span class="keyword">from</span> <span class="string">'mongoose'</span>;</span><br><span class="line"><span class="keyword">import</span> { <span class="title class_">IGenericRepository</span> } <span class="keyword">from</span> <span class="string">'../../../core'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">MongoGenericRepository</span><T> <span class="keyword">implements</span> <span class="title class_">IGenericRepository</span><T> {</span><br><span class="line"> <span class="keyword">private</span> <span class="attr">_repository</span>: <span class="title class_">Model</span><T>;</span><br><span class="line"> <span class="keyword">private</span> <span class="attr">_populateOnFind</span>: <span class="built_in">string</span>[];</span><br><span class="line"></span><br><span class="line"> <span class="title function_">constructor</span>(<span class="params"><span class="attr">repository</span>: <span class="title class_">Model</span><T>, <span class="attr">populateOnFind</span>: <span class="built_in">string</span>[] = []</span>) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">_repository</span> = repository;</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">_populateOnFind</span> = populateOnFind;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="title function_">getAll</span>(): <span class="title class_">Promise</span><T[]> {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_repository</span>.<span class="title function_">find</span>().<span class="title function_">populate</span>(<span class="variable language_">this</span>.<span class="property">_populateOnFind</span>).<span class="title function_">exec</span>();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="title function_">get</span>(<span class="attr">id</span>: <span class="built_in">any</span>): <span class="title class_">Promise</span><T> {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_repository</span>.<span class="title function_">findById</span>(id).<span class="title function_">populate</span>(<span class="variable language_">this</span>.<span class="property">_populateOnFind</span>).<span class="title function_">exec</span>();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="title function_">create</span>(<span class="attr">item</span>: T): <span class="title class_">Promise</span><T> {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_repository</span>.<span class="title function_">create</span>(item);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="title function_">update</span>(<span class="params"><span class="attr">id</span>: <span class="built_in">string</span>, <span class="attr">item</span>: T</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_repository</span>.<span class="title function_">findByIdAndUpdate</span>(id, item);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure> <p>然后实现一个 <code>MongoDataServices</code>:</p> -<figure class="highlight typescript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> { <span class="title class_">Injectable</span>, <span class="title class_">OnApplicationBootstrap</span> } <span class="keyword">from</span> <span class="string">'@nestjs/common'</span>;</span><br><span class="line"><span class="keyword">import</span> { <span class="title class_">InjectModel</span> } <span class="keyword">from</span> <span class="string">'@nestjs/mongoose'</span>;</span><br><span class="line"><span class="keyword">import</span> { <span class="title class_">Model</span> } <span class="keyword">from</span> <span class="string">'mongoose'</span>;</span><br><span class="line"><span class="keyword">import</span> { <span class="title class_">IDataServices</span> } <span class="keyword">from</span> <span class="string">'../../../core'</span>;</span><br><span class="line"><span class="keyword">import</span> { <span class="title class_">MongoGenericRepository</span> } <span class="keyword">from</span> <span class="string">'./mongo-generic-repository'</span>;</span><br><span class="line"><span class="keyword">import</span> {</span><br><span class="line"> <span class="title class_">Author</span>,</span><br><span class="line"> <span class="title class_">AuthorDocument</span>,</span><br><span class="line"> <span class="title class_">Book</span>,</span><br><span class="line"> <span class="title class_">BookDocument</span>,</span><br><span class="line"> <span class="title class_">Genre</span>,</span><br><span class="line"> <span class="title class_">GenreDocument</span>,</span><br><span class="line">} <span class="keyword">from</span> <span class="string">'./model'</span>;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Injectable</span>()</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">MongoDataServices</span></span><br><span class="line"> <span class="keyword">implements</span> <span class="title class_">IDataServices</span>, <span class="title class_">OnApplicationBootstrap</span></span><br><span class="line">{</span><br><span class="line"> <span class="attr">authors</span>: <span class="title class_">MongoGenericRepository</span><<span class="title class_">Author</span>>;</span><br><span class="line"> <span class="attr">books</span>: <span class="title class_">MongoGenericRepository</span><<span class="title class_">Book</span>>;</span><br><span class="line"> <span class="attr">genres</span>: <span class="title class_">MongoGenericRepository</span><<span class="title class_">Genre</span>>;</span><br><span class="line"></span><br><span class="line"> <span class="title function_">constructor</span>(<span class="params"></span></span><br><span class="line"><span class="params"> <span class="meta">@InjectModel</span>(Author.name)</span></span><br><span class="line"><span class="params"> <span class="keyword">private</span> AuthorRepository: Model<AuthorDocument>,</span></span><br><span class="line"><span class="params"> <span class="meta">@InjectModel</span>(Book.name)</span></span><br><span class="line"><span class="params"> <span class="keyword">private</span> BookRepository: Model<BookDocument>,</span></span><br><span class="line"><span class="params"> <span class="meta">@InjectModel</span>(Genre.name)</span></span><br><span class="line"><span class="params"> <span class="keyword">private</span> GenreRepository: Model<GenreDocument>,</span></span><br><span class="line"><span class="params"> </span>) {}</span><br><span class="line"></span><br><span class="line"> <span class="title function_">onApplicationBootstrap</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">authors</span> = <span class="keyword">new</span> <span class="title class_">MongoGenericRepository</span><<span class="title class_">Author</span>>(<span class="variable language_">this</span>.<span class="property">AuthorRepository</span>);</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">books</span> = <span class="keyword">new</span> <span class="title class_">MongoGenericRepository</span><<span class="title class_">Book</span>>(<span class="variable language_">this</span>.<span class="property">BookRepository</span>, [</span><br><span class="line"> <span class="string">'author'</span>,</span><br><span class="line"> <span class="string">'genre'</span>,</span><br><span class="line"> ]);</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">genres</span> = <span class="keyword">new</span> <span class="title class_">MongoGenericRepository</span><<span class="title class_">Genre</span>>(<span class="variable language_">this</span>.<span class="property">GenreRepository</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure> +<figure class="highlight typescript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">import</span> { <span class="title class_">Injectable</span>, <span class="title class_">OnApplicationBootstrap</span> } <span class="keyword">from</span> <span class="string">'@nestjs/common'</span>;</span><br><span class="line"><span class="keyword">import</span> { <span class="title class_">InjectModel</span> } <span class="keyword">from</span> <span class="string">'@nestjs/mongoose'</span>;</span><br><span class="line"><span class="keyword">import</span> { <span class="title class_">Model</span> } <span class="keyword">from</span> <span class="string">'mongoose'</span>;</span><br><span class="line"><span class="keyword">import</span> { <span class="title class_">IDataServices</span> } <span class="keyword">from</span> <span class="string">'../../../core'</span>;</span><br><span class="line"><span class="keyword">import</span> { <span class="title class_">MongoGenericRepository</span> } <span class="keyword">from</span> <span class="string">'./mongo-generic-repository'</span>;</span><br><span class="line"><span class="keyword">import</span> {</span><br><span class="line"> <span class="title class_">Author</span>,</span><br><span class="line"> <span class="title class_">AuthorDocument</span>,</span><br><span class="line"> <span class="title class_">Book</span>,</span><br><span class="line"> <span class="title class_">BookDocument</span>,</span><br><span class="line"> <span class="title class_">Genre</span>,</span><br><span class="line"> <span class="title class_">GenreDocument</span>,</span><br><span class="line">} <span class="keyword">from</span> <span class="string">'./model'</span>;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Injectable</span>()</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">MongoDataServices</span></span><br><span class="line"> <span class="keyword">implements</span> <span class="title class_">IDataServices</span>, <span class="title class_">OnApplicationBootstrap</span></span><br><span class="line">{</span><br><span class="line"> <span class="attr">authors</span>: <span class="title class_">MongoGenericRepository</span><<span class="title class_">Author</span>>;</span><br><span class="line"> <span class="attr">books</span>: <span class="title class_">MongoGenericRepository</span><<span class="title class_">Book</span>>;</span><br><span class="line"> <span class="attr">genres</span>: <span class="title class_">MongoGenericRepository</span><<span class="title class_">Genre</span>>;</span><br><span class="line"></span><br><span class="line"> <span class="title function_">constructor</span>(<span class="params"></span></span><br><span class="line"><span class="params"> <span class="meta">@InjectModel</span>(Author.name)</span></span><br><span class="line"><span class="params"> <span class="keyword">private</span> <span class="title class_">AuthorRepository</span>: <span class="title class_">Model</span><<span class="title class_">AuthorDocument</span>>,</span></span><br><span class="line"><span class="params"> <span class="meta">@InjectModel</span>(Book.name)</span></span><br><span class="line"><span class="params"> <span class="keyword">private</span> <span class="title class_">BookRepository</span>: <span class="title class_">Model</span><<span class="title class_">BookDocument</span>>,</span></span><br><span class="line"><span class="params"> <span class="meta">@InjectModel</span>(Genre.name)</span></span><br><span class="line"><span class="params"> <span class="keyword">private</span> <span class="title class_">GenreRepository</span>: <span class="title class_">Model</span><<span class="title class_">GenreDocument</span>>,</span></span><br><span class="line"><span class="params"> </span>) {}</span><br><span class="line"></span><br><span class="line"> <span class="title function_">onApplicationBootstrap</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">authors</span> = <span class="keyword">new</span> <span class="title class_">MongoGenericRepository</span><<span class="title class_">Author</span>>(<span class="variable language_">this</span>.<span class="property">AuthorRepository</span>);</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">books</span> = <span class="keyword">new</span> <span class="title class_">MongoGenericRepository</span><<span class="title class_">Book</span>>(<span class="variable language_">this</span>.<span class="property">BookRepository</span>, [</span><br><span class="line"> <span class="string">'author'</span>,</span><br><span class="line"> <span class="string">'genre'</span>,</span><br><span class="line"> ]);</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">genres</span> = <span class="keyword">new</span> <span class="title class_">MongoGenericRepository</span><<span class="title class_">Genre</span>>(<span class="variable language_">this</span>.<span class="property">GenreRepository</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure> <hr> <p>Sunday, March 30, 2025 7:58 PM:</p> @@ -2091,49 +2091,6 @@ </tags> </entry> <entry> - <title>TypeScript With Rust Errors, No Try Catch, Heresy</title> - <url>/2023/04/30/TypeScript-With-Rust-Errors-No-Try-Catch-Heresy/</url> - <content><![CDATA[<blockquote> -<p>It’s hard to miss things when you don’t know different things exist</p> -</blockquote> -<p>The first problem is, and personally, I believe it’s the biggest JavaScript problem ever: we don’t know what can throw an error. From a JavaScript error perspective, it’s the same as the following:</p> -<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">let</span> data = “<span class="title class_">Hello</span>”;</span><br><span class="line">} <span class="keyword">catch</span> (err) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">error</span>(err);</span><br><span class="line">}</span><br></pre></td></tr></table></figure> - -<p>JavaScript doesn’t know; JavaScript doesn’t care. You should know.</p> -<p>Second thing, this is perfectly viable code:</p> -<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> request = { <span class="attr">name</span>: “test”, <span class="attr">value</span>: <span class="number">2n</span> };</span><br><span class="line"><span class="keyword">const</span> body = <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(request);</span><br><span class="line"><span class="keyword">const</span> response = <span class="keyword">await</span> <span class="title function_">fetch</span>(<span class="string">"https://example.com"</span>, {</span><br><span class="line"> <span class="attr">method</span>: “<span class="variable constant_">POST</span>”,</span><br><span class="line"> body,</span><br><span class="line">});</span><br><span class="line"><span class="keyword">if</span> (!response.<span class="property">ok</span>) {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure> - -<p>No errors, no linters, even though this can break your app.</p> -<p>Right now, in my head, I can hear, “What’s the problem, just use try/catch everywhere.” Here comes the third problem: we don’t know which one is thrown. Of course, we can somehow guess by the error message, but what about bigger services/functions with many places where errors can happen? Are you sure you are handling all of them properly with one try/catch?</p> -<hr> -<figure class="highlight rust"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="variable">greeting_file_result</span> = File::<span class="title function_ invoke__">open</span>(“hello.txt”); </span><br><span class="line"><span class="keyword">let</span> <span class="variable">greeting_file</span> = <span class="keyword">match</span> greeting_file_result { </span><br><span class="line"> <span class="title function_ invoke__">Ok</span>(file) => file, </span><br><span class="line"> <span class="title function_ invoke__">Err</span>(error) => <span class="built_in">panic!</span>(<span class="string">"Problem opening the file: {:?}"</span>, error), </span><br><span class="line">};</span><br></pre></td></tr></table></figure> - -<p>The most verbose of the three shown here and, ironically, the best one. So, first of all, Rust handles the errors using its amazing enums (they are not the same as TypeScript enums!). Without going into detail, what is important here is that it uses an enum called <code>Result</code> with two variants: <code>Ok</code> and <code>Err</code>. As you might guess, <code>Ok</code> holds a value and <code>Err</code> holds…surprise, an error :D.</p> -<p>The summary here is that Rust always know where there might be an error. And it force you to deal with it right where it appears (mostly). No hidden ones, no guessing, no breaking app with a surprise face.</p> -<p>And this approach is just better. By A MILE.</p> -<p>We cannot make TypeScript errors work like the Rust. The limiting factor here is the language itself; it doesn’t have the proper tools to do that.</p> -<p>But what we can do is try to make it similar. And make it simple:</p> -<figure class="highlight typescript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">type</span> <span class="title class_">Safe</span><T> = </span><br><span class="line"> | { </span><br><span class="line"> <span class="attr">success</span>: <span class="literal">true</span>; </span><br><span class="line"> <span class="attr">data</span>: T; </span><br><span class="line"> } </span><br><span class="line"> | { </span><br><span class="line"> <span class="attr">success</span>: <span class="literal">false</span>; </span><br><span class="line"> <span class="attr">error</span>: <span class="built_in">string</span>; </span><br><span class="line"> };</span><br></pre></td></tr></table></figure> - -<p>we do need a few try/catches. The good thing is we only need about two, not 100,000:</p> -<figure class="highlight typescript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> safe<T>(<span class="attr">promise</span>: <span class="title class_">Promise</span><T>, err?: <span class="built_in">string</span>): <span class="title class_">Promise</span><<span class="title class_">Safe</span><T>>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> safe<T>(<span class="attr">func</span>: <span class="function">() =></span> T, err?: <span class="built_in">string</span>): <span class="title class_">Safe</span><T>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> safe<T>(</span><br><span class="line"> <span class="attr">promiseOrFunc</span>: <span class="title class_">Promise</span><T> | (<span class="function">() =></span> T),</span><br><span class="line"> err?: <span class="built_in">string</span>,</span><br><span class="line">): <span class="title class_">Promise</span><<span class="title class_">Safe</span><T>> | <span class="title class_">Safe</span><T> {</span><br><span class="line"> <span class="keyword">if</span> (promiseOrFunc <span class="keyword">instanceof</span> <span class="title class_">Promise</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">safeAsync</span>(promiseOrFunc, err);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">safeSync</span>(promiseOrFunc, err);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> safeAsync<T>(</span><br><span class="line"> <span class="attr">promise</span>: <span class="title class_">Promise</span><T>, </span><br><span class="line"> err?: <span class="built_in">string</span></span><br><span class="line">): <span class="title class_">Promise</span><<span class="title class_">Safe</span><T>> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">const</span> data = <span class="keyword">await</span> promise;</span><br><span class="line"> <span class="keyword">return</span> { data, <span class="attr">success</span>: <span class="literal">true</span> };</span><br><span class="line"> } <span class="keyword">catch</span> (e) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">error</span>(e);</span><br><span class="line"> <span class="keyword">if</span> (err !== <span class="literal">undefined</span>) {</span><br><span class="line"> <span class="keyword">return</span> { <span class="attr">success</span>: <span class="literal">false</span>, <span class="attr">error</span>: err };</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (e <span class="keyword">instanceof</span> <span class="title class_">Error</span>) {</span><br><span class="line"> <span class="keyword">return</span> { <span class="attr">success</span>: <span class="literal">false</span>, <span class="attr">error</span>: e.<span class="property">message</span> };</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> { <span class="attr">success</span>: <span class="literal">false</span>, <span class="attr">error</span>: <span class="string">"Something went wrong"</span> };</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> safeSync<T>(</span><br><span class="line"> <span class="attr">func</span>: <span class="function">() =></span> T, </span><br><span class="line"> err?: <span class="built_in">string</span></span><br><span class="line">): <span class="title class_">Safe</span><T> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">const</span> data = <span class="title function_">func</span>();</span><br><span class="line"> <span class="keyword">return</span> { data, <span class="attr">success</span>: <span class="literal">true</span> };</span><br><span class="line"> } <span class="keyword">catch</span> (e) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">error</span>(e);</span><br><span class="line"> <span class="keyword">if</span> (err !== <span class="literal">undefined</span>) {</span><br><span class="line"> <span class="keyword">return</span> { <span class="attr">success</span>: <span class="literal">false</span>, <span class="attr">error</span>: err };</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (e <span class="keyword">instanceof</span> <span class="title class_">Error</span>) {</span><br><span class="line"> <span class="keyword">return</span> { <span class="attr">success</span>: <span class="literal">false</span>, <span class="attr">error</span>: e.<span class="property">message</span> };</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> { <span class="attr">success</span>: <span class="literal">false</span>, <span class="attr">error</span>: <span class="string">"Something went wrong"</span> };</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure> - -<p>This is just a wrapper with our <code>Safe</code> type as the return one. But sometimes simple things are all you need. Let’s combine them with the example from above.</p> -<figure class="highlight typescript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> request = { <span class="attr">name</span>: “test”, <span class="attr">value</span>: <span class="number">2n</span> }; </span><br><span class="line"><span class="keyword">const</span> body = <span class="title function_">safe</span>( </span><br><span class="line"> <span class="function">() =></span> <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(request), </span><br><span class="line"> “<span class="title class_">Failed</span> to serialize request”, </span><br><span class="line">); </span><br><span class="line"><span class="keyword">if</span> (!body.<span class="property">success</span>) { </span><br><span class="line"> <span class="comment">// handle error (body.error) </span></span><br><span class="line"> <span class="keyword">return</span>; </span><br><span class="line">} </span><br><span class="line"><span class="keyword">const</span> response = <span class="keyword">await</span> <span class="title function_">safe</span>( </span><br><span class="line"> <span class="title function_">fetch</span>(<span class="string">"https://example.com"</span>, { </span><br><span class="line"> <span class="attr">method</span>: “<span class="variable constant_">POST</span>”, </span><br><span class="line"> <span class="attr">body</span>: body.<span class="property">data</span>, </span><br><span class="line"> }), </span><br><span class="line">); </span><br><span class="line"><span class="keyword">if</span> (!response.<span class="property">success</span>) { </span><br><span class="line"> <span class="comment">// handle error (response.error) </span></span><br><span class="line"> <span class="keyword">return</span>; </span><br><span class="line">} </span><br><span class="line"><span class="keyword">if</span> (!response.<span class="property">data</span>.<span class="property">ok</span>) { </span><br><span class="line"> <span class="comment">// handle network error </span></span><br><span class="line"> <span class="keyword">return</span>; </span><br><span class="line">} </span><br><span class="line"><span class="comment">// handle response (body.data)</span></span><br></pre></td></tr></table></figure> - -<p>New solution is longer, but it performs better because of the following reasons:</p> -<ul> -<li>no try/catch</li> -<li>we handle each error where it occurs</li> -<li>we can specify an error message for a specific function</li> -<li>we have a nice top-to-bottom logic, all errors on top, then only the response at the bottom</li> -</ul> -]]></content> - <tags> - <tag>Technique</tag> - </tags> - </entry> - <entry> <title>Turborepo 简述</title> <url>/2024/09/27/Turborepo-%E7%AE%80%E8%BF%B0/</url> <content><![CDATA[<h2 id="Turborepo-简介"><a href="#Turborepo-简介" class="headerlink" title="Turborepo 简介"></a>Turborepo 简介</h2><p>Monorepos 有很多优势,但它们难以扩展。每个工作区都有自己的测试套件、自己的 linting 和构建过程。单个 monorepo 可能有数千个任务要执行。</p> @@ -2353,6 +2310,49 @@ </tags> </entry> <entry> + <title>TypeScript With Rust Errors, No Try Catch, Heresy</title> + <url>/2023/04/30/TypeScript-With-Rust-Errors-No-Try-Catch-Heresy/</url> + <content><![CDATA[<blockquote> +<p>It’s hard to miss things when you don’t know different things exist</p> +</blockquote> +<p>The first problem is, and personally, I believe it’s the biggest JavaScript problem ever: we don’t know what can throw an error. From a JavaScript error perspective, it’s the same as the following:</p> +<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">let</span> data = “<span class="title class_">Hello</span>”;</span><br><span class="line">} <span class="keyword">catch</span> (err) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">error</span>(err);</span><br><span class="line">}</span><br></pre></td></tr></table></figure> + +<p>JavaScript doesn’t know; JavaScript doesn’t care. You should know.</p> +<p>Second thing, this is perfectly viable code:</p> +<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> request = { <span class="attr">name</span>: “test”, <span class="attr">value</span>: <span class="number">2n</span> };</span><br><span class="line"><span class="keyword">const</span> body = <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(request);</span><br><span class="line"><span class="keyword">const</span> response = <span class="keyword">await</span> <span class="title function_">fetch</span>(<span class="string">"https://example.com"</span>, {</span><br><span class="line"> <span class="attr">method</span>: “<span class="variable constant_">POST</span>”,</span><br><span class="line"> body,</span><br><span class="line">});</span><br><span class="line"><span class="keyword">if</span> (!response.<span class="property">ok</span>) {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure> + +<p>No errors, no linters, even though this can break your app.</p> +<p>Right now, in my head, I can hear, “What’s the problem, just use try/catch everywhere.” Here comes the third problem: we don’t know which one is thrown. Of course, we can somehow guess by the error message, but what about bigger services/functions with many places where errors can happen? Are you sure you are handling all of them properly with one try/catch?</p> +<hr> +<figure class="highlight rust"><table><tr><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="variable">greeting_file_result</span> = File::<span class="title function_ invoke__">open</span>(“hello.txt”); </span><br><span class="line"><span class="keyword">let</span> <span class="variable">greeting_file</span> = <span class="keyword">match</span> greeting_file_result { </span><br><span class="line"> <span class="title function_ invoke__">Ok</span>(file) => file, </span><br><span class="line"> <span class="title function_ invoke__">Err</span>(error) => <span class="built_in">panic!</span>(<span class="string">"Problem opening the file: {:?}"</span>, error), </span><br><span class="line">};</span><br></pre></td></tr></table></figure> + +<p>The most verbose of the three shown here and, ironically, the best one. So, first of all, Rust handles the errors using its amazing enums (they are not the same as TypeScript enums!). Without going into detail, what is important here is that it uses an enum called <code>Result</code> with two variants: <code>Ok</code> and <code>Err</code>. As you might guess, <code>Ok</code> holds a value and <code>Err</code> holds…surprise, an error :D.</p> +<p>The summary here is that Rust always know where there might be an error. And it force you to deal with it right where it appears (mostly). No hidden ones, no guessing, no breaking app with a surprise face.</p> +<p>And this approach is just better. By A MILE.</p> +<p>We cannot make TypeScript errors work like the Rust. The limiting factor here is the language itself; it doesn’t have the proper tools to do that.</p> +<p>But what we can do is try to make it similar. And make it simple:</p> +<figure class="highlight typescript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">type</span> <span class="title class_">Safe</span><T> = </span><br><span class="line"> | { </span><br><span class="line"> <span class="attr">success</span>: <span class="literal">true</span>; </span><br><span class="line"> <span class="attr">data</span>: T; </span><br><span class="line"> } </span><br><span class="line"> | { </span><br><span class="line"> <span class="attr">success</span>: <span class="literal">false</span>; </span><br><span class="line"> <span class="attr">error</span>: <span class="built_in">string</span>; </span><br><span class="line"> };</span><br></pre></td></tr></table></figure> + +<p>we do need a few try/catches. The good thing is we only need about two, not 100,000:</p> +<figure class="highlight typescript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> safe<T>(<span class="attr">promise</span>: <span class="title class_">Promise</span><T>, <span class="attr">err</span>?: <span class="built_in">string</span>): <span class="title class_">Promise</span><<span class="title class_">Safe</span><T>>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> safe<T>(<span class="attr">func</span>: <span class="function">() =></span> T, <span class="attr">err</span>?: <span class="built_in">string</span>): <span class="title class_">Safe</span><T>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> safe<T>(</span><br><span class="line"> <span class="attr">promiseOrFunc</span>: <span class="title class_">Promise</span><T> | (<span class="function">() =></span> T),</span><br><span class="line"> <span class="attr">err</span>?: <span class="built_in">string</span>,</span><br><span class="line">): <span class="title class_">Promise</span><<span class="title class_">Safe</span><T>> | <span class="title class_">Safe</span><T> {</span><br><span class="line"> <span class="keyword">if</span> (promiseOrFunc <span class="keyword">instanceof</span> <span class="title class_">Promise</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">safeAsync</span>(promiseOrFunc, err);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">safeSync</span>(promiseOrFunc, err);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> safeAsync<T>(</span><br><span class="line"> <span class="attr">promise</span>: <span class="title class_">Promise</span><T>, </span><br><span class="line"> <span class="attr">err</span>?: <span class="built_in">string</span></span><br><span class="line">): <span class="title class_">Promise</span><<span class="title class_">Safe</span><T>> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">const</span> data = <span class="keyword">await</span> promise;</span><br><span class="line"> <span class="keyword">return</span> { data, <span class="attr">success</span>: <span class="literal">true</span> };</span><br><span class="line"> } <span class="keyword">catch</span> (e) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">error</span>(e);</span><br><span class="line"> <span class="keyword">if</span> (err !== <span class="literal">undefined</span>) {</span><br><span class="line"> <span class="keyword">return</span> { <span class="attr">success</span>: <span class="literal">false</span>, <span class="attr">error</span>: err };</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (e <span class="keyword">instanceof</span> <span class="title class_">Error</span>) {</span><br><span class="line"> <span class="keyword">return</span> { <span class="attr">success</span>: <span class="literal">false</span>, <span class="attr">error</span>: e.<span class="property">message</span> };</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> { <span class="attr">success</span>: <span class="literal">false</span>, <span class="attr">error</span>: <span class="string">"Something went wrong"</span> };</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> safeSync<T>(</span><br><span class="line"> <span class="attr">func</span>: <span class="function">() =></span> T, </span><br><span class="line"> <span class="attr">err</span>?: <span class="built_in">string</span></span><br><span class="line">): <span class="title class_">Safe</span><T> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">const</span> data = <span class="title function_">func</span>();</span><br><span class="line"> <span class="keyword">return</span> { data, <span class="attr">success</span>: <span class="literal">true</span> };</span><br><span class="line"> } <span class="keyword">catch</span> (e) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">error</span>(e);</span><br><span class="line"> <span class="keyword">if</span> (err !== <span class="literal">undefined</span>) {</span><br><span class="line"> <span class="keyword">return</span> { <span class="attr">success</span>: <span class="literal">false</span>, <span class="attr">error</span>: err };</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (e <span class="keyword">instanceof</span> <span class="title class_">Error</span>) {</span><br><span class="line"> <span class="keyword">return</span> { <span class="attr">success</span>: <span class="literal">false</span>, <span class="attr">error</span>: e.<span class="property">message</span> };</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> { <span class="attr">success</span>: <span class="literal">false</span>, <span class="attr">error</span>: <span class="string">"Something went wrong"</span> };</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure> + +<p>This is just a wrapper with our <code>Safe</code> type as the return one. But sometimes simple things are all you need. Let’s combine them with the example from above.</p> +<figure class="highlight typescript"><table><tr><td class="code"><pre><span class="line"><span class="keyword">const</span> request = { <span class="attr">name</span>: “test”, <span class="attr">value</span>: <span class="number">2n</span> }; </span><br><span class="line"><span class="keyword">const</span> body = <span class="title function_">safe</span>( </span><br><span class="line"> <span class="function">() =></span> <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(request), </span><br><span class="line"> “<span class="title class_">Failed</span> to serialize request”, </span><br><span class="line">); </span><br><span class="line"><span class="keyword">if</span> (!body.<span class="property">success</span>) { </span><br><span class="line"> <span class="comment">// handle error (body.error) </span></span><br><span class="line"> <span class="keyword">return</span>; </span><br><span class="line">} </span><br><span class="line"><span class="keyword">const</span> response = <span class="keyword">await</span> <span class="title function_">safe</span>( </span><br><span class="line"> <span class="title function_">fetch</span>(<span class="string">"https://example.com"</span>, { </span><br><span class="line"> <span class="attr">method</span>: “<span class="variable constant_">POST</span>”, </span><br><span class="line"> <span class="attr">body</span>: body.<span class="property">data</span>, </span><br><span class="line"> }), </span><br><span class="line">); </span><br><span class="line"><span class="keyword">if</span> (!response.<span class="property">success</span>) { </span><br><span class="line"> <span class="comment">// handle error (response.error) </span></span><br><span class="line"> <span class="keyword">return</span>; </span><br><span class="line">} </span><br><span class="line"><span class="keyword">if</span> (!response.<span class="property">data</span>.<span class="property">ok</span>) { </span><br><span class="line"> <span class="comment">// handle network error </span></span><br><span class="line"> <span class="keyword">return</span>; </span><br><span class="line">} </span><br><span class="line"><span class="comment">// handle response (body.data)</span></span><br></pre></td></tr></table></figure> + +<p>New solution is longer, but it performs better because of the following reasons:</p> +<ul> +<li>no try/catch</li> +<li>we handle each error where it occurs</li> +<li>we can specify an error message for a specific function</li> +<li>we have a nice top-to-bottom logic, all errors on top, then only the response at the bottom</li> +</ul> +]]></content> + <tags> + <tag>Technique</tag> + </tags> + </entry> + <entry> <title>WiscKey: Separating Keys from Values in SSD-conscious Storage</title> <url>/2023/07/21/WiscKey-Separating-Keys-from-Values-in-SSD-conscious-Storage/</url> <content><![CDATA[<p>We present WiscKey, a persistent LSM-tree-based key-value store with a performance-oriented data layoutthat separates keys from values to minimize I/O amplifi-cation. The design of WiscKey is highly SSD optimized, leveraging both the sequential and random performance characteristics of the device.</p> @@ -2415,6 +2415,19 @@ </tags> </entry> <entry> + <title>Linux 下 AMD 显卡屏幕画面闪烁问题修复方案</title> + <url>/2025/04/20/linux-amd-screen-boom/</url> + <content><![CDATA[<p>不知道我们所说的闪烁是不是一个东西,在我的笔记本上,闪烁是指偶发的屏幕中出现部分彩色雪花。</p> +<p>我使用 Pop!_OS,此发行版使用 EFI 启动,故而可以在 <code>/boot/efi/loader/loader.conf</code> 中加上:</p> +<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">options quiet splash amdgpu.dcdebugmask=0x10 amdgpu.sg_display=0</span><br></pre></td></tr></table></figure> + +<p>对于其他使用 EFI 或 GRUB 启动的发行版也可以添加类似的参数尝试尝试。</p> +]]></content> + <tags> + <tag>Technique</tag> + </tags> + </entry> + <entry> <title>使用 [@poll error] 实现线程安全的数据结构</title> <url>/2023/08/15/poll-error-attribute-in-OCaml/</url> <content><![CDATA[<p>OCaml的标准库提供了许多mutable的数据结构,比如Hashtbl, Queue, Stack之类的,但是这些数据结构都不是线程安全的。在 OCaml 4 和 OCaml 5 中,单个Domain中一次只能运行一个线程。换句话说,单个Domain中的线程仍然不会并行运行,除非在不同所的Domain中。</p> @@ -2453,6 +2466,32 @@ </tags> </entry> <entry> + <title>UUID v7 是如何加快 RDBMS 索引速度的</title> + <url>/2025/04/13/uuidv7-rdbms/</url> + <content><![CDATA[<p>UUID v7 之所以能显著提升关系型数据库(尤其是采用聚集索引的 MySQL InnoDB)在插入和查询速度,主要归功于它在 ID 中引入了“可排序的时间戳前缀”,从而大幅减少了 B-Tree 索引页分裂(page split)和数据碎片化。这里分几点来说:</p> +<p>一、 聚集索引(Clustered Index)的插入机制 </p> +<p>在 InnoDB 中,聚集索引的叶子节点同时存储了行数据,且按照索引键(主键)顺序物理排序。</p> +<p>当新记录的主键完全随机(如 UUID v4)时,每次插入都会随机落在 B-Tree 的不同叶子页,导致频繁的页分裂和指针重排,而页分裂和随机 I/O 会带来大量的磁盘写放大和缓存抖动(cache churn),削弱吞吐并拉高延迟。</p> +<p>二、UUID v7 的时间排序特性 </p> +<p>UUID v7 在高位(前 48 位)嵌入了以毫秒级精度的 Unix 时间戳,剩下的位用于随机数或序列号,这样生成的 ID 保持全局唯一性的同时,随着时间自然递增(即“近似单调递增”),新插入的记录几乎总是追加到 B-Tree 的最右端叶子节点。 </p> +<p>参见 dbaplus.cn 的分析: </p> +<blockquote> +<p>“UUID v7 的创新之处在于其时间排序特性,它在前 48 位中嵌入了以毫秒为单位的 Unix 时间戳……可能在插入和查询操作上提供更好的性能”【1】。</p> +</blockquote> +<p>三、降低页分裂与碎片化 </p> +<p>顺序或近似顺序的主键能使叶子节点连续增长,极少触发页分裂,并且更少的页分裂意味着更低的写放大(write amplification)和更稳定的插入延迟,同时,减少了空洞和链表重排,提高了磁盘和内存缓存的命中率。</p> +<p>四、提升查询局部性与缓存命中 </p> +<p>因为数据物理上是按时间顺序紧凑写入,时间范围查询(如 “最近 1 小时的日志”)可以快速定位连续的叶子页,I/O 更聚集,内存缓冲池(buffer pool)或操作系统页缓存能更有效地缓存最近热数据,进一步加速查询。</p> +<hr> +<p>Rimon Tawadrous 在其 GitHub repo 中的测试,对比 100 万条逐条插入实验,UUID v7 相较 UUID v4 在单线程插入上速度快约 3.24%,多线程下更可观【1】。 </p> +<hr> +<p><strong>参考链接</strong><br>[1] “为什么 UUID 7 比 UUID 4 更适合作为 RDBMS 的聚集索引?” dbaplus.cn<br> <a href="https://dbaplus.cn/news-160-6313-1.html">https://dbaplus.cn/news-160-6313-1.html</a><br>[2] “PostgreSQL and UUID as primary key” maciejwalkowiak<br> <a href="https://maciejwalkowiak.com/blog/postgres-uuid-primary-key/">https://maciejwalkowiak.com/blog/postgres-uuid-primary-key/</a><br>[3] “Optimised UUIDs in mysql” stitcher<br> <a href="https://stitcher.io/blog/optimised-uuids-in-mysql">https://stitcher.io/blog/optimised-uuids-in-mysql</a><br>[3] “Storing UUID Values in MySQL” percona<br> <a href="https://www.percona.com/blog/store-uuid-optimized-way/">https://www.percona.com/blog/store-uuid-optimized-way/</a></p> +]]></content> + <tags> + <tag>Technique</tag> + </tags> + </entry> + <entry> <title>v8中的Number.toString()</title> <url>/2023/10/05/v8%E4%B8%AD%E7%9A%84Number-toString/</url> <content><![CDATA[<p>这里讲一下JavaScript中<code>Number.toString()</code>的实现, 以V8为例。</p> @@ -2542,36 +2581,6 @@ </categories> </entry> <entry> - <title>二〇二三年十二月二日</title> - <url>/2023/12/02/%E4%BA%8C%E3%80%87%E4%BA%8C%E4%B8%89%E5%B9%B4%E5%8D%81%E4%BA%8C%E6%9C%88%E4%BA%8C%E6%97%A5/</url> - <content><![CDATA[<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> -]]></content> - <categories> - <category>gallery</category> - </categories> - </entry> - <entry> <title>二〇二三年十二月一日</title> <url>/2023/12/01/%E4%BA%8C%E3%80%87%E4%BA%8C%E4%B8%89%E5%B9%B4%E5%8D%81%E4%BA%8C%E6%9C%88%E4%B8%80%E6%97%A5/</url> <content><![CDATA[<p>他说:“路挺远的,你慢走啊。”</p> @@ -2623,6 +2632,36 @@ </categories> </entry> <entry> + <title>二〇二三年十二月二日</title> + <url>/2023/12/02/%E4%BA%8C%E3%80%87%E4%BA%8C%E4%B8%89%E5%B9%B4%E5%8D%81%E4%BA%8C%E6%9C%88%E4%BA%8C%E6%97%A5/</url> + <content><![CDATA[<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> +]]></content> + <categories> + <category>gallery</category> + </categories> + </entry> + <entry> <title>二〇二五年三月十七日</title> <url>/2025/03/17/%E4%BA%8C%E3%80%87%E4%BA%8C%E4%BA%94%E5%B9%B4%E4%B8%89%E6%9C%88%E5%8D%81%E4%B8%83%E6%97%A5/</url> <content><