关系型数据库表结构的两个设计技巧
關系型數據庫表結構的設計,有下面兩個設計技巧:
物理主鍵作為關聯的外鍵
關系型數據庫,由多個數據表構成。每一個數據表的結構是相同的,不同表之間可能存在關聯關系。表之間的關聯關系,正是關系型數據庫得名的原因。
一個表由多個字段構成。其中可能有多個字段適合作為主鍵。主鍵字段,就是表中每一行都不會有重復數據的字段。
主鍵,可以分為兩種:物理主鍵和邏輯主鍵。
每一張數據庫的表,都使用自增長的id字段作為物理主鍵。
多表之間的外鍵關聯,都關聯其他表的物理主鍵,也就是關聯其他表的id字段。
邏輯主鍵,就是除了id字段外的不重復的字段。我們設計數據庫的外鍵關聯時,不使用邏輯主鍵,而是使用物理主鍵。
這是因為,物理主鍵肯定是主鍵,因為它是自增的。(對于不支持自增字段的關系數據庫,可以使用uuid保證物理主鍵的唯一性)
而邏輯主鍵,則可能隨著業務的發展,成為可重復的字段。一旦這種情況發生,關系數據庫的外鍵關系就被破壞了。如,可能你覺得姓名是邏輯主鍵,但可能后面發現有人重名,那么這個字段就不再是主鍵了。而如果之前使用這個字段作為外鍵,那么查詢返回的數據就不是一一對應的了。
這就是為什么要使用物理主鍵,以及用物理主鍵作為關聯外鍵的原因。
使用樂觀鎖更新依賴之前狀態的記錄
考慮這樣一種數據庫的應用場景:
任務單的接管:多個操作人員從一個任務池中接管一個任務。只有第一個獲取任務的操作人員才能成功接管該任務,后續操作人員的接管操作都必須失敗。
這時,就需要一種數據庫記錄的鎖定機制。只有第一個事務才能更新記錄。
數據庫可以使用悲觀鎖和樂觀鎖來鎖定數據庫記錄。
悲觀鎖是如下sql語句實現的:
| 1 | SELECT * FROM t FOR UPDATE |
這條語句會在其他修改內容的事務提交后返回最新的數據。
一旦執行這條語句,這些記錄就被鎖住了,不能被其他sql事務修改。直到本事務提交。
樂觀鎖,是應用程序實現的,不是數據庫實現的機制。樂觀鎖,對于數據庫來說,就是沒有上鎖。事務可以select其他事務已經提交的數據。更新數據時,數據庫保證多個事務的更新是原子的。
悲觀鎖,會導致事務等待其他事務完成。樂觀鎖,只會等待其他事務的更新語句的完成,不會等待整個事務完成,因此效率較高。
實現樂觀鎖的方法:
給數據庫表添加一個version字段。version是一個數字類型的字段,每次更新都加1。每次更新時都要檢測version字段是否和當前事務的值相同。如果version字段不同,那么就表明在查詢數據之后,有其他事務已經更新了該記錄,就會導致此次更新失敗。應用必須重新載入最新的數據,然后重新更新數據。
如果使用樂觀鎖,那么如果數據庫中version和應用中version相同,則用version+1的版本值更新version字段。
SQL語句如下:
| 1 | update studentVersion set ver=?, name=? where id=? and ver=? |
?? 不使用鎖更新獨立狀態的記錄
考慮這樣一種數據庫的應用場景:
需要更新虛擬機的狀態。多個事務可能會同時更新虛擬機的狀態為start或者stop。這種狀態的更新和前一個階段的狀態是無關的,因此不需要鎖定記錄。直接更新即可。此時不需要使用悲觀鎖或者樂觀鎖。
如果這個表添加了version字段,直接忽略對version字段的比較和更新即可。
SQL語句如下:
| 1 | update studentVersion set?? name=? where id=? |
總結
設計關系型數據庫的表時,需要給表添加一個ID字段(自增字段,或者uuid字段)和一個version字段(數值類型)。ID字段作為物理主鍵,用于保證記錄的不可重復性和用作外鍵關聯。
version字段用于實現樂觀鎖,提供比悲觀鎖更好的性能。特別是對于UI顯示并可能出現并發更新的數據,更需要使用樂觀鎖來提升數據庫訪問性能。
對于后臺自動更新的任務,可以使用樂觀鎖實現。但需要在沖突發生時實現自動退讓。也可以使用悲觀鎖在數據庫上對事務進行排隊來解決更新沖突問題。
對于不關心記錄的狀態之間關系的場景,可以直接更新記錄,忽略掉version字段的檢測和更新。
from:http://blog.jobbole.com/100060/
伯樂在線?-?良少?
總結
以上是生活随笔為你收集整理的关系型数据库表结构的两个设计技巧的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 31 天重构学习笔记索引
- 下一篇: 淘宝分布式调度框架TBSchedule