<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    <title>範例｜林鼎淵 Dean Lin</title>
    <link>https://deanlin.net/tags/%E7%AF%84%E4%BE%8B/</link>
    <image><url>https://deanlin.net/images/author_hu_aa256fc934e9a932.jpg</url><title>範例｜林鼎淵 Dean Lin</title><link>https://deanlin.net/tags/%E7%AF%84%E4%BE%8B/</link><width>144</width><height>144</height></image>
    <description>林鼎淵（Dean Lin）的部落格：生成式 AI 企業內訓講師、外商資安公司軟體專家、7 本書作者。400 多篇文章用白話分享生成式 AI 實戰、Claude Code 與 Vibe Coding 教學、團隊合作與職場成長。</description>
    <generator>Hugo</generator>
    <language>zh-tw</language>
    <copyright>© 2020–2026 林鼎淵 Dean Lin</copyright>
    <lastBuildDate>Fri, 12 Mar 2021 18:15:06 +0800</lastBuildDate>
    <atom:link href="https://deanlin.net/tags/%E7%AF%84%E4%BE%8B/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>理解資料庫『悲觀鎖』和『樂觀鎖』的觀念</title>
      <link>https://deanlin.net/blog/202103/pessimistic-vs-optimistic-locking/</link>
      <pubDate>Fri, 12 Mar 2021 18:15:06 +0800</pubDate>
      <guid>https://deanlin.net/blog/202103/pessimistic-vs-optimistic-locking/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>技術教學</category>
      <description>沒有經過實際操作的理論都只是空談，這篇文章我會附上自己的MySQL 語法 方便大家在自己的環境中驗證這個資料庫的觀念，讓日後處理併發問題時有更完整的思路。</description>
      <media:content url="https://deanlin.net/blog/202103/pessimistic-vs-optimistic-locking/images/pessimistic-vs-optimistic-locking-og_hu_8e7dc770a70e0cb.jpg" medium="image" type="image/jpeg" width="1200" height="675" />
      <content:encoded><![CDATA[<p>沒有經過實際操作的理論都只是空談，這篇文章我會附上自己的MySQL 語法方便大家在自己的環境中驗證這個資料庫的觀念，讓日後處理併發問題時有更完整的思路。</p>
<pre tabindex="0"><code>一、為什麼要了解他們 🔐？
二、從字面上了解悲觀鎖、樂觀鎖
三、在 MySQL DB 實作悲觀鎖
四、在 MySQL DB 實作樂觀鎖
五、悲觀鎖、樂觀鎖優缺點
</code></pre><p><img src="https://deanlin.net/blog/202103/pessimistic-vs-optimistic-locking/images/pessimistic-vs-optimistic-locking-01.webp" width="1400" height="787" alt="理解資料庫『悲觀鎖』和『樂觀鎖』的觀念（圖 1）" fetchpriority="high" decoding="async"></p>
<h2 id="一為什麼要了解他們-">一、為什麼要了解他們 🔐？<a class="h-anchor" href="#%e4%b8%80%e7%82%ba%e4%bb%80%e9%ba%bc%e8%a6%81%e4%ba%86%e8%a7%a3%e4%bb%96%e5%80%91-" aria-label="這個段落的連結"></a></h2>
<p>網路商城開特賣會的時候常常會推出一件商品只限 10 人搶購，在搶購的過程除了會產生高併發的問題外，同時也需要考慮到『商品會不會超賣』，在現實生活中聽起來很像不可思議，但在網路的世界裡如果沒做好資料庫的防護真的可能發生明明只限 10 人搶購卻有 30 個人搶到商品的超賣事件。</p>
<h3 class="h-nomark" id="-今天想要解決的問題">❓ 今天想要解決的問題：<a class="h-anchor" href="#-%e4%bb%8a%e5%a4%a9%e6%83%b3%e8%a6%81%e8%a7%a3%e6%b1%ba%e7%9a%84%e5%95%8f%e9%a1%8c" aria-label="這個段落的連結"></a></h3>
<p>假設 A 跟 B 都想要買 iphone 手機，但商城的 iphone 庫存只剩下一隻，在不加鎖的狀況下同時下單會導致庫存變成負號；實作上要如何解決這個問題呢？</p>
<h2 id="二從字面上了解悲觀鎖樂觀鎖">二、從字面上了解悲觀鎖、樂觀鎖<a class="h-anchor" href="#%e4%ba%8c%e5%be%9e%e5%ad%97%e9%9d%a2%e4%b8%8a%e4%ba%86%e8%a7%a3%e6%82%b2%e8%a7%80%e9%8e%96%e6%a8%82%e8%a7%80%e9%8e%96" aria-label="這個段落的連結"></a></h2>
<h3 class="h-nomark" id="-悲觀鎖-pessimistic-lock">😭 悲觀鎖 —Pessimistic Lock<a class="h-anchor" href="#-%e6%82%b2%e8%a7%80%e9%8e%96-pessimistic-lock" aria-label="這個段落的連結"></a></h3>
<p>就跟字面上的意思一樣，非常的悲觀；他認為 table 裡面的 data 非常的不安全，無時無刻都在變動，當一個SQL command(可以理解為搶購的用戶)獲得悲觀鎖後，其他的 SQL command 無法對這個 data 進行修改，直到悲觀鎖被釋放後才能執行。</p>
<blockquote>
<p>資料表中用 syncronized 實現的鎖均為悲觀鎖(ex：行鎖，表鎖，讀鎖，寫鎖)</p>
</blockquote>
<h3 class="h-nomark" id="-樂觀鎖--optimistic-lock">😃 樂觀鎖 — Optimistic Lock<a class="h-anchor" href="#-%e6%a8%82%e8%a7%80%e9%8e%96--optimistic-lock" aria-label="這個段落的連結"></a></h3>
<p>相比悲觀鎖，他認為 table 裡面的 data 變動頻率不會太頻繁，因此他會允許多個 SQL command 來操作 table；但樂觀並不代表不負責，通常會在 table 中增加一個 version 的欄位來做更新的確認。因此當 SQL command 想要變更欄位 data 時會先把之前取出 version 跟 table 現在的 version 做對比，如果相同就代表這段期間沒人修改可以執行；如果不同就會禁止這次的操作。</p>
<h2 id="三在-mysql-db-實作悲觀鎖">三、在 MySQL DB 實作悲觀鎖<a class="h-anchor" href="#%e4%b8%89%e5%9c%a8-mysql-db-%e5%af%a6%e4%bd%9c%e6%82%b2%e8%a7%80%e9%8e%96" aria-label="這個段落的連結"></a></h2>
<h3 id="a-建立模擬資料">A. 建立模擬資料：<a class="h-anchor" href="#a-%e5%bb%ba%e7%ab%8b%e6%a8%a1%e6%93%ac%e8%b3%87%e6%96%99" aria-label="這個段落的連結"></a></h3>
<p>先用 SQL command 建立一個簡單的 table 並插入 data</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#ff7b72">CREATE</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">TABLE</span><span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">`</span>your_DB<span style="color:#ff7b72;font-weight:bold">`</span>.<span style="color:#ff7b72;font-weight:bold">`</span>items<span style="color:#ff7b72;font-weight:bold">`</span><span style="color:#6e7681"> </span>(<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">  </span><span style="color:#ff7b72;font-weight:bold">`</span>id<span style="color:#ff7b72;font-weight:bold">`</span><span style="color:#6e7681"> </span>INT<span style="color:#6e7681"> </span><span style="color:#ff7b72">NOT</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">NULL</span><span style="color:#6e7681"> </span>AUTO_INCREMENT,<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">  </span><span style="color:#ff7b72;font-weight:bold">`</span>name<span style="color:#ff7b72;font-weight:bold">`</span><span style="color:#6e7681"> </span>VARCHAR(<span style="color:#a5d6ff">45</span>)<span style="color:#6e7681"> </span><span style="color:#ff7b72">NOT</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">NULL</span>,<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">  </span><span style="color:#ff7b72;font-weight:bold">`</span>num<span style="color:#ff7b72;font-weight:bold">`</span><span style="color:#6e7681"> </span>INT<span style="color:#6e7681"> </span><span style="color:#ff7b72">NOT</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">NULL</span>,<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">  </span><span style="color:#ff7b72">PRIMARY</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">KEY</span><span style="color:#6e7681"> </span>(<span style="color:#ff7b72;font-weight:bold">`</span>id<span style="color:#ff7b72;font-weight:bold">`</span>));<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#ff7b72">INSERT</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">INTO</span><span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">`</span>your_DB<span style="color:#ff7b72;font-weight:bold">`</span>.<span style="color:#ff7b72;font-weight:bold">`</span>items<span style="color:#ff7b72;font-weight:bold">`</span><span style="color:#6e7681"> </span>(<span style="color:#ff7b72;font-weight:bold">`</span>name<span style="color:#ff7b72;font-weight:bold">`</span>,<span style="color:#ff7b72;font-weight:bold">`</span>num<span style="color:#ff7b72;font-weight:bold">`</span>)<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#ff7b72">VALUES</span><span style="color:#6e7681"> </span>(<span style="color:#a5d6ff">&#34;iphone&#34;</span>,<span style="color:#a5d6ff">1</span>);<span style="color:#6e7681">
</span></span></span></code></pre></div><p class="code-source">原始碼：<a href="https://gist.github.com/dean9703111/334f6b3cd81452fc56491e7360fd9265" rel="noopener">create_mock_item_table.sql</a>（GitHub Gist）</p>
<figure class="figure"><img src="https://deanlin.net/blog/202103/pessimistic-vs-optimistic-locking/images/pessimistic-vs-optimistic-locking-02.webp" width="585" height="221" alt="直接進去 MySQL command line 模式貼上去就好嚕" loading="lazy" decoding="async">
  <figcaption>直接進去 MySQL command line 模式貼上去就好嚕</figcaption>
</figure>

<figure class="figure"><img src="https://deanlin.net/blog/202103/pessimistic-vs-optimistic-locking/images/pessimistic-vs-optimistic-locking-03.webp" width="404" height="158" alt="用 SELECT * FROM `your_DB`.`items`; 確認一下資料是否建立成功" loading="lazy" decoding="async">
  <figcaption>用 <strong>SELECT * FROM `your_DB`.`items`;</strong> 確認一下資料是否建立成功</figcaption>
</figure>

<h3 id="b-用悲觀鎖解決-iphone-購買問題">B. 用悲觀鎖解決 iphone 購買問題<a class="h-anchor" href="#b-%e7%94%a8%e6%82%b2%e8%a7%80%e9%8e%96%e8%a7%a3%e6%b1%ba-iphone-%e8%b3%bc%e8%b2%b7%e5%95%8f%e9%a1%8c" aria-label="這個段落的連結"></a></h3>
<p><strong>STEP 1</strong>：開一個視窗模擬 A 的行為，我們先在 A 購買前先將 <code>id=1</code> 的 data 加上悲觀鎖，此時這行 data 只有 A 可以操作</p>
<figure class="figure"><img src="https://deanlin.net/blog/202103/pessimistic-vs-optimistic-locking/images/pessimistic-vs-optimistic-locking-04.webp" width="353" height="56" alt="Transaction 的開始要用 begin;，不然 MySQL 會自動提交" loading="lazy" decoding="async">
  <figcaption>Transaction 的開始要用 <strong>begin;</strong>，不然 MySQL 會自動提交</figcaption>
</figure>

<figure class="figure"><img src="https://deanlin.net/blog/202103/pessimistic-vs-optimistic-locking/images/pessimistic-vs-optimistic-locking-05.webp" width="603" height="148" alt="接著用 select num from `your_DB`.`items` where id = 1 for update; 將 id = 1 的 data 加上悲觀鎖" loading="lazy" decoding="async">
  <figcaption>接著用 <strong>select num from `your_DB`.`items` where id = 1 for update; </strong>將 id = 1 的 data 加上悲觀鎖</figcaption>
</figure>

<p><strong>STEP 2</strong>：此時開另一個視窗模擬 B 的行為，一樣將 <code>id=1</code> 的 data 加上悲觀鎖</p>
<figure class="figure"><img src="https://deanlin.net/blog/202103/pessimistic-vs-optimistic-locking/images/pessimistic-vs-optimistic-locking-06.webp" width="618" height="99" alt="你會發現會進入等待的模式，要等 A 執行 commit 完成交易或是指令逾時才能繼續" loading="lazy" decoding="async">
  <figcaption>你會發現會進入等待的模式，要等 A 執行 commit 完成交易或是指令逾時才能繼續</figcaption>
</figure>

<p><strong>STEP 3</strong>：回到 A 的視窗，接著我們讓 A 執行購買的動作將 data 的 num 減一，然後檢視修改後的 data 是否符合預期，最後下 commit 結束這次交易</p>
<figure class="figure"><img src="https://deanlin.net/blog/202103/pessimistic-vs-optimistic-locking/images/pessimistic-vs-optimistic-locking-07.webp" width="585" height="281" alt="購買： update `your_DB`.`items` set num = num -1 where id = 1; ，檢視修改：select num from `your_DB`.`items` where id = 1; ，結束交易：commit;" loading="lazy" decoding="async">
  <figcaption>購買： <strong>update `your_DB`.`items` set num = num -1 where id = 1;</strong> ，檢視修改：<strong>select num from `your_DB`.`items` where id = 1; </strong>，結束交易：<strong>commit;</strong></figcaption>
</figure>

<p><strong>STEP 4</strong>：當 A 完成下單後回到 B 的視窗，你會發現因為 A 釋放了悲觀鎖，所以 B 結束等待並且獲得鎖，但 data 的 num 已經變成了 0 只能放棄購買</p>
<figure class="figure"><img src="https://deanlin.net/blog/202103/pessimistic-vs-optimistic-locking/images/pessimistic-vs-optimistic-locking-08.webp" width="585" height="143" alt="7.89 秒是等待獲得鎖的時間" loading="lazy" decoding="async">
  <figcaption>7.89 秒是等待獲得鎖的時間</figcaption>
</figure>

<h2 id="四在-mysql-db-實作樂觀鎖">四、在 MySQL DB 實作樂觀鎖<a class="h-anchor" href="#%e5%9b%9b%e5%9c%a8-mysql-db-%e5%af%a6%e4%bd%9c%e6%a8%82%e8%a7%80%e9%8e%96" aria-label="這個段落的連結"></a></h2>
<h3 id="a-建立模擬資料-1">A. 建立模擬資料：<a class="h-anchor" href="#a-%e5%bb%ba%e7%ab%8b%e6%a8%a1%e6%93%ac%e8%b3%87%e6%96%99-1" aria-label="這個段落的連結"></a></h3>
<p>先用 SQL command 建立一個簡單的 table 並插入 data，比起悲觀鎖的 table，我們多了一個 version 的欄位</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#ff7b72">CREATE</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">TABLE</span><span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">`</span>your_DB<span style="color:#ff7b72;font-weight:bold">`</span>.<span style="color:#ff7b72;font-weight:bold">`</span>happy_items<span style="color:#ff7b72;font-weight:bold">`</span><span style="color:#6e7681"> </span>(<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">  </span><span style="color:#ff7b72;font-weight:bold">`</span>id<span style="color:#ff7b72;font-weight:bold">`</span><span style="color:#6e7681"> </span>INT<span style="color:#6e7681"> </span><span style="color:#ff7b72">NOT</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">NULL</span><span style="color:#6e7681"> </span>AUTO_INCREMENT,<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">  </span><span style="color:#ff7b72;font-weight:bold">`</span>name<span style="color:#ff7b72;font-weight:bold">`</span><span style="color:#6e7681"> </span>VARCHAR(<span style="color:#a5d6ff">45</span>)<span style="color:#6e7681"> </span><span style="color:#ff7b72">NOT</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">NULL</span>,<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">  </span><span style="color:#ff7b72;font-weight:bold">`</span>num<span style="color:#ff7b72;font-weight:bold">`</span><span style="color:#6e7681"> </span>INT<span style="color:#6e7681"> </span><span style="color:#ff7b72">NOT</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">NULL</span>,<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">  </span><span style="color:#ff7b72;font-weight:bold">`</span><span style="color:#ff7b72">version</span><span style="color:#ff7b72;font-weight:bold">`</span><span style="color:#6e7681"> </span>INT<span style="color:#6e7681"> </span><span style="color:#ff7b72">NOT</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">NULL</span>,<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">  </span><span style="color:#ff7b72">PRIMARY</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">KEY</span><span style="color:#6e7681"> </span>(<span style="color:#ff7b72;font-weight:bold">`</span>id<span style="color:#ff7b72;font-weight:bold">`</span>));<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#ff7b72">INSERT</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">INTO</span><span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">`</span>your_DB<span style="color:#ff7b72;font-weight:bold">`</span>.<span style="color:#ff7b72;font-weight:bold">`</span>happy_items<span style="color:#ff7b72;font-weight:bold">`</span><span style="color:#6e7681"> </span>(<span style="color:#ff7b72;font-weight:bold">`</span>name<span style="color:#ff7b72;font-weight:bold">`</span>,<span style="color:#ff7b72;font-weight:bold">`</span>num<span style="color:#ff7b72;font-weight:bold">`</span>,<span style="color:#ff7b72;font-weight:bold">`</span><span style="color:#ff7b72">version</span><span style="color:#ff7b72;font-weight:bold">`</span>)<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#ff7b72">VALUES</span><span style="color:#6e7681"> </span>(<span style="color:#a5d6ff">&#34;iphone&#34;</span>,<span style="color:#a5d6ff">1</span>,<span style="color:#a5d6ff">0</span>);<span style="color:#6e7681">
</span></span></span></code></pre></div><p class="code-source">原始碼：<a href="https://gist.github.com/dean9703111/4a8469117f075b3db7194106417c6765" rel="noopener">create_mock_happy_item_table.sql</a>（GitHub Gist）</p>
<figure class="figure"><img src="https://deanlin.net/blog/202103/pessimistic-vs-optimistic-locking/images/pessimistic-vs-optimistic-locking-09.webp" width="624" height="218" alt="直接進去 MySQL command line 模式貼上去就好嚕" loading="lazy" decoding="async">
  <figcaption>直接進去 MySQL command line 模式貼上去就好嚕</figcaption>
</figure>

<figure class="figure"><img src="https://deanlin.net/blog/202103/pessimistic-vs-optimistic-locking/images/pessimistic-vs-optimistic-locking-10.webp" width="427" height="143" alt="用 SELECT * FROM `your_DB`.`happy_items`; 確認一下資料是否建立成功" loading="lazy" decoding="async">
  <figcaption>用 <strong>SELECT * FROM `your_DB`.`happy_items`; </strong>確認一下資料是否建立成功</figcaption>
</figure>

<h3 id="b-用樂觀鎖解決-iphone-購買問題">B. 用樂觀鎖解決 iphone 購買問題<a class="h-anchor" href="#b-%e7%94%a8%e6%a8%82%e8%a7%80%e9%8e%96%e8%a7%a3%e6%b1%ba-iphone-%e8%b3%bc%e8%b2%b7%e5%95%8f%e9%a1%8c" aria-label="這個段落的連結"></a></h3>
<p><strong>思路</strong>：A 跟 B 在下單前會先將 <code>id=1</code> 的 data 找出來，然後 A 先買，此時會以 table 的 <code>id=1 和 version=0</code> 作為條件來更新 data，更新後 num 減一、version 加一變成 <code>id=1、num=0、version=1</code>；此時 B 購買時會因為用 <code>id=1 和 version=0</code>找不到 data 而無法更新。</p>
<p><strong>STEP 1</strong>：A 及 B 執行查詢的 SQL command 會取得相同的 iphone 庫存資訊</p>
<figure class="figure"><img src="https://deanlin.net/blog/202103/pessimistic-vs-optimistic-locking/images/pessimistic-vs-optimistic-locking-11.webp" width="621" height="143" alt="用 SELECT num,version FROM `your_DB`.`happy_items` where id = 1; 找出 iphone 庫存資訊" loading="lazy" decoding="async">
  <figcaption>用 <strong>SELECT num,version FROM `your_DB`.`happy_items` where id = 1;</strong> 找出 iphone 庫存資訊</figcaption>
</figure>

<p><strong>STEP 2</strong>：A 先購買了 iphone 來更新 data，然後檢視修改後的 data 是否符合預期</p>
<figure class="figure"><img src="https://deanlin.net/blog/202103/pessimistic-vs-optimistic-locking/images/pessimistic-vs-optimistic-locking-12.webp" width="978" height="370" alt="購買：update `your_DB`.`happy_items` set num = num -1 , version = version &#43; 1 where id = 1 and version = 0; ，檢視修改：SELECT num,version FROM `your_DB`.`happy_items` where id = 1;" loading="lazy" decoding="async">
  <figcaption>購買：<strong>update `your_DB`.`happy_items` set num = num -1 , version = version + 1 where id = 1 and version = 0; </strong>，檢視修改：<strong>SELECT num,version FROM `your_DB`.`happy_items` where id = 1;</strong></figcaption>
</figure>

<p><strong>STEP 3</strong>：此時 B 想要購買時就會無法更新 data，執行購買的 SQL command後你會發現沒有 Row 被更新</p>
<figure class="figure"><img src="https://deanlin.net/blog/202103/pessimistic-vs-optimistic-locking/images/pessimistic-vs-optimistic-locking-13.webp" width="978" height="75" alt="購買：update `your_DB`.`happy_items` set num = num -1 , version = version &#43; 1 where id = 1 and version = 0;" loading="lazy" decoding="async">
  <figcaption>購買：<strong>update `your_DB`.`happy_items` set num = num -1 , version = version + 1 where id = 1 and version = 0;</strong></figcaption>
</figure>

<h2 id="五悲觀鎖樂觀鎖優缺點">五、悲觀鎖、樂觀鎖優缺點<a class="h-anchor" href="#%e4%ba%94%e6%82%b2%e8%a7%80%e9%8e%96%e6%a8%82%e8%a7%80%e9%8e%96%e5%84%aa%e7%bc%ba%e9%bb%9e" aria-label="這個段落的連結"></a></h2>
<h3 class="h-nomark" id="-悲觀鎖--pessimistic-lock">😭 悲觀鎖 — Pessimistic Lock<a class="h-anchor" href="#-%e6%82%b2%e8%a7%80%e9%8e%96--pessimistic-lock" aria-label="這個段落的連結"></a></h3>
<p><strong>優點</strong>：使用資料庫 Transaction 的機制來強迫執行的順序</p>
<p><strong>缺點</strong>：一但加入 Transaction 的機制會導致其他的 SQL command 針對這個 data 除了查詢功能外全部卡死，如果這段 Transaction 執行時間較長會給使用者不良的體驗並造成系統吞吐量下降</p>
<h3 class="h-nomark" id="-樂觀鎖--optimistic-lock-1">😃 樂觀鎖 — Optimistic Lock<a class="h-anchor" href="#-%e6%a8%82%e8%a7%80%e9%8e%96--optimistic-lock-1" aria-label="這個段落的連結"></a></h3>
<p><strong>優點</strong>：因為沒有在資料庫加鎖，所以 SQL command 都會購對 data 進行操作，只有在更新 data 時才會做驗證；這樣就避免悲觀鎖導致的吞吐量下降的問題</p>
<p><strong>缺點</strong>：因為樂觀鎖是我們人為實現的，所以如果換一個業務場景可能會不適用，甚至可能因為其他的 SQL command 導致錯誤。</p>
<hr>
<p>參考資源：<a href="https://kknews.cc/zh-tw/news/z9aqnva.html">關於悲觀鎖和樂觀鎖的個人圖解</a>、<a href="https://www.jianshu.com/p/aaa12e90e9b9">商品秒殺問題</a></p>
]]></content:encoded>
    </item>
  </channel>
</rss>
