關係型數據庫表結構的兩個設計技巧

關係型數據庫表結構的設計,有下面兩個設計技巧:sql

物理主鍵做爲關聯的外鍵

關係型數據庫,由多個數據表構成。每個數據表的結構是相同的,不一樣表之間可能存在關聯關係。表之間的關聯關係,正是關係型數據庫得名的緣由。數據庫

一個表由多個字段構成。其中可能有多個字段適合做爲主鍵。主鍵字段,就是表中每一行都不會有重複數據的字段。
主鍵,能夠分爲兩種:物理主鍵和邏輯主鍵。
每一張數據庫的表,都使用自增加的id字段做爲物理主鍵。
多表之間的外鍵關聯,都關聯其餘表的物理主鍵,也就是關聯其餘表的id字段。併發

邏輯主鍵,就是除了id字段外的不重複的字段。咱們設計數據庫的外鍵關聯時,不使用邏輯主鍵,而是使用物理主鍵。性能

這是由於,物理主鍵確定是主鍵,由於它是自增的。(對於不支持自增字段的關係數據庫,可使用uuid保證物理主鍵的惟一性)ui

而邏輯主鍵,則可能隨着業務的發展,成爲可重複的字段。一旦這種狀況發生,關係數據庫的外鍵關係就被破壞了。如,可能你以爲姓名是邏輯主鍵,但可能後面發現有人重名,那麼這個字段就再也不是主鍵了。而若是以前使用這個字段做爲外鍵,那麼查詢返回的數據就不是一一對應的了。spa

這就是爲何要使用物理主鍵,以及用物理主鍵做爲關聯外鍵的緣由。設計

使用樂觀鎖更新依賴以前狀態的記錄

考慮這樣一種數據庫的應用場景:code

任務單的接管:多個操做人員從一個任務池中接管一個任務。只有第一個獲取任務的操做人員才能成功接管該任務,後續操做人員的接管操做都必須失敗。事務

這時,就須要一種數據庫記錄的鎖定機制。只有第一個事務才能更新記錄。ci

數據庫可使用悲觀鎖和樂觀鎖來鎖定數據庫記錄。

悲觀鎖是以下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字段的檢測和更新。

相關文章
相關標籤/搜索