自增 id 對內、ULID 對外、可讀單號給顧客。三個各司其職。


一張訂單,我給它三個識別碼:

id            1024                  自增,資料庫內部用
public_id     01J8K2M...(ULID)    網址與連結用
order_number  EL2609020001927       顧客與客服用

看起來很多餘?三個都有它非存在不可的理由。

id:給資料庫用

外鍵、join、排序、索引。整數最快、最省空間,關聯表全部指向它。

但它絕對不能出現在網址上。

因為它會洩漏商業資訊。競業只要在月初跟月底各下一張單,把兩個 id 相減,就知道你這個月做了幾張單。這是免費送給對手的情報。

而且它可以被猜。/orders/1024 改成 /orders/1025,就是別人的訂單——你的權限檢查最好一次都不要漏。

public_id:給網址用

所以對外一律用 ULID:

static::creating(function (self $order) {
    $order->public_id ??= (string) Str::ulid();
    $order->order_number ??= DocumentNumber::forOrder();
});

ULID 猜不到、也推算不出數量。訂單頁的網址、通知信裡的連結,用的都是它。

為什麼選 ULID 而不是 UUID? 因為 ULID 有時間排序性(開頭是時間戳),當索引時效能比較好,而且字串比較短、沒有難看的連字號。

order_number:給人用

EL2609020001927。前綴 + 日期 + 當日流水 + 亂數。

這是客戶在電話裡會念出來的東西,也是客服在後台搜尋的東西。ULID 太長、沒有意義、念到一半會念錯;自增 id 又太容易打錯(少一位數就是別人的單)。

單號的工作是「被人類講出來」,所以它要短、要有結構、要看得出日期。

為什麼不能合併

每次有人想砍掉其中一個,都是因為只想到自己的使用情境:

  • 用單號當主鍵?格式哪天要改(換前綴、改日期格式),你就得動全部的外鍵。
  • 用 ULID 當主鍵?索引變大、join 變慢,而且客服要在電話裡念它。
  • 只用自增 id?前面說過了,等於公開你的營運數字。

它們是三種不同的需求:機器的效率、對外的不可預測、人類的可讀性。 一個欄位滿足不了三件事。

搭配使用

通知信裡的訂單連結,我是這樣發的:

URL::signedRoute('account.orders.show', ['order' => $order->public_id]);

ULID 負責「猜不到」,簽章負責「證明這個連結是我發的」。兩層一起用,訪客不用登入也能安全地看自己的訂單。

識別碼不是愈少愈好,是各有各的工作。


⭐️ Shopify 網站開發服務(給品牌)
https://job.turn.tw/shopify-services

⭐️ 川川電商事務所(全客製電商開發服務)
https://chuanchuan.tw

⭐️ 台灣 Shopify 商家交流 LINE 群(非官方)
https://line.me/ti/g2/PZ_1LILWVWWuzZQ50HNpYA-A3k6QXWF6znqoBQ

⭐️ 台灣 Shopify 開發者 LINE 群(非官方)
https://line.me/ti/g2/YUasX5K3CJ4QdIx76zppjHlh3-q8w-xkSyK1LA

共有 0 則留言


⭐️ Shopify 網站開發服務(給品牌)
https://job.turn.tw/shopify-services

⭐️ 川川電商事務所(全客製電商開發服務)
https://chuanchuan.tw

⭐️ 台灣 Shopify 商家交流 LINE 群(非官方)
https://line.me/ti/g2/PZ_1LILWVWWuzZQ50HNpYA-A3k6QXWF6znqoBQ

⭐️ 台灣 Shopify 開發者 LINE 群(非官方)
https://line.me/ti/g2/YUasX5K3CJ4QdIx76zppjHlh3-q8w-xkSyK1LA
🏆 本月排行榜
🥇
站長阿川
📝45   💬1  
643
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次