關(guān)系型數(shù)據(jù)庫表結(jié)構(gòu)的設(shè)計(jì),有下面兩個(gè)設(shè)計(jì)技巧:
物理主鍵作為關(guān)聯(lián)的外鍵關(guān)系型數(shù)據(jù)庫,由多個(gè)數(shù)據(jù)表構(gòu)成。每一個(gè)數(shù)據(jù)表的結(jié)構(gòu)是相同的,不同表之間可能存在關(guān)聯(lián)關(guān)系。表之間的關(guān)聯(lián)關(guān)系,正是關(guān)系型數(shù)據(jù)庫得名的原因。一個(gè)表由多個(gè)字段構(gòu)成。其中可能有多個(gè)字段適合作為主鍵。主鍵字段,就是表中每一行都不會(huì)有重復(fù)數(shù)據(jù)的字段。
主鍵,可以分為兩種:物理主鍵和邏輯主鍵。每一張數(shù)據(jù)庫的表,都使用自增長(zhǎng)的id字段作為物理主鍵。多表之間的外鍵關(guān)聯(lián),都關(guān)聯(lián)其他表的物理主鍵,也就是關(guān)聯(lián)其他表的id字段。邏輯主鍵,就是除了id字段外的不重復(fù)的字段。我們?cè)O(shè)計(jì)數(shù)據(jù)庫的外鍵關(guān)聯(lián)時(shí),不使用邏輯主鍵,而是使用物理主鍵。這是因?yàn),物理主鍵肯定是主鍵,因?yàn)樗亲栽龅摹?對(duì)于不支持自增字段的關(guān)系數(shù)據(jù)庫,可以使用uuid保證物理主鍵的唯一性)而邏輯主鍵,則可能隨著業(yè)務(wù)的發(fā)展,成為可重復(fù)的字段。一旦這種情況發(fā)生,關(guān)系數(shù)據(jù)庫的外鍵關(guān)系就被破壞了。如,可能你覺得姓名是邏輯主鍵,但可能后面發(fā)現(xiàn)有人重名,那么這個(gè)字段就不再是主鍵了。而如果之前使用這個(gè)字段作為外鍵,那么查詢返回的數(shù)據(jù)就不是一一對(duì)應(yīng)的了。這就是為什么要使用物理主鍵,以及用物理主鍵作為關(guān)聯(lián)外鍵的原因。使用樂觀鎖更新依賴之前狀態(tài)的記錄
考慮這樣一種數(shù)據(jù)庫的應(yīng)用場(chǎng)景:任務(wù)單的接管:多個(gè)操作人員從一個(gè)任務(wù)池中接管一個(gè)任務(wù)。只有第一個(gè)獲取任務(wù)的操作人員才能成功接管該任務(wù),后續(xù)操作人員的接管操作都必須失敗。這時(shí),就需要一種數(shù)據(jù)庫記錄的鎖定機(jī)制。只有第一個(gè)事務(wù)才能更新記錄。數(shù)據(jù)庫可以使用悲觀鎖和樂觀鎖來鎖定數(shù)據(jù)庫記錄。悲觀鎖是如下sql語句實(shí)現(xiàn)的:SELECT * FROM t FOR UPDATE,這條語句會(huì)在其他修改內(nèi)容的事務(wù)提交后返回最新的數(shù)據(jù)。一旦執(zhí)行這條語句,這些記錄就被鎖住了,不能被其他sql事務(wù)修改。直到本事務(wù)提交。
樂觀鎖,是應(yīng)用程序?qū)崿F(xiàn)的,不是數(shù)據(jù)庫實(shí)現(xiàn)的機(jī)制。樂觀鎖,對(duì)于數(shù)據(jù)庫來說,就是沒有上鎖。事務(wù)可以select其他事務(wù)已經(jīng)提交的數(shù)據(jù)。更新數(shù)據(jù)時(shí),數(shù)據(jù)庫保證多個(gè)事務(wù)的更新是原子的。悲觀鎖,會(huì)導(dǎo)致事務(wù)等待其他事務(wù)完成。樂觀鎖,只會(huì)等待其他事務(wù)的更新語句的完成,不會(huì)等待整個(gè)事務(wù)完成,因此效率較高。
實(shí)現(xiàn)樂觀鎖的方法:
給數(shù)據(jù)庫表添加一個(gè)version字段。version是一個(gè)數(shù)字類型的字段,每次更新都加1。每次更新時(shí)都要檢測(cè)version字段是否和當(dāng)前事務(wù)的值相同。如果version字段不同,那么就表明在查詢數(shù)據(jù)之后,有其他事務(wù)已經(jīng)更新了該記錄,就會(huì)導(dǎo)致此次更新失敗。應(yīng)用必須重新載入最新的數(shù)據(jù),然后重新更新數(shù)據(jù)。如果使用樂觀鎖,那么如果數(shù)據(jù)庫中version和應(yīng)用中version相同,則用version+1的版本值更新version字段。
SQL語句如下:update studentVersion set ver=?, name=? where id=? and ver=?不使用鎖更新獨(dú)立狀態(tài)的記錄考慮這樣一種數(shù)據(jù)庫的應(yīng)用場(chǎng)景:需要更新虛擬機(jī)的狀態(tài)。多個(gè)事務(wù)可能會(huì)同時(shí)更新虛擬機(jī)的狀態(tài)為start或者stop。這種狀態(tài)的更新和前一個(gè)階段的狀態(tài)是無關(guān)的,因此不需要鎖定記錄。直接更新即可。此時(shí)不需要使用悲觀鎖或者樂觀鎖。如果這個(gè)表添加了version字段,直接忽略對(duì)version字段的比較和更新即可。
SQL語句如下:update studentVersion set name=? where id=?
總結(jié)
設(shè)計(jì)關(guān)系型數(shù)據(jù)庫的表時(shí),需要給表添加一個(gè)ID字段(自增字段,或者uuid字段)和一個(gè)version字段(數(shù)值類型)。ID字段作為物理主鍵,用于保證記錄的不可重復(fù)性和用作外鍵關(guān)聯(lián)。version字段用于實(shí)現(xiàn)樂觀鎖,提供比悲觀鎖更好的性能。特別是對(duì)于UI顯示并可能出現(xiàn)并發(fā)更新的數(shù)據(jù),更需要使用樂觀鎖來提升數(shù)據(jù)庫訪問性能。對(duì)于后臺(tái)自動(dòng)更新的任務(wù),可以使用樂觀鎖實(shí)現(xiàn)。但需要在沖突發(fā)生時(shí)實(shí)現(xiàn)自動(dòng)退讓。也可以使用悲觀鎖在數(shù)據(jù)庫上對(duì)事務(wù)進(jìn)行排隊(duì)來解決更新沖突問題。對(duì)于不關(guān)心記錄的狀態(tài)之間關(guān)系的場(chǎng)景,可以直接更新記錄,忽略掉version字段的檢測(cè)和更新。
以上內(nèi)容是關(guān)于關(guān)系型數(shù)據(jù)庫表結(jié)構(gòu)的兩個(gè)設(shè)計(jì)技巧的介紹,要想了解更多相關(guān)信息、教育培訓(xùn)請(qǐng)隨時(shí)關(guān)注唯學(xué)網(wǎng),小編會(huì)第一時(shí)間為大家更新、跟進(jìn)最新信息。