關系型數據庫rdbms的一個主要特征即多表,外鍵關聯或/並加以約束。關系型數據庫的優點,顧名思義,能夠通過數據庫本身的操作來建立、保持並維護關系,由此在集中的數據存儲中,可以提供很多便利。
不過,rdbms因為將關系納入數據存儲中,反而給自己造成了很多麻煩。數據建模可以很程式化的進行,這就是雙刃劍,一些ORM工具很形象的將對象與表對應,而將引用與關系對應,看起來似乎徹底的解決了rdbms非對象化的問題,但實際上是繞了很大的一個圈。
關系型數據庫最常見的一個用法,即通過關聯查詢獲取分散於各個表中的記錄。一個問題是,什么信息需要如此大動干戈,從多張表中獲取?下面以常見用戶/權限系統中的模型為例,解決這個問題!
-
用戶,用戶自身包括用戶名/密碼、用戶資料
-
組織結構,自身包括組織資料
-
權限,權限實際上只有一個名字,在具體體現到功能前,這個東西毫無意義
-
用戶間,沒有任何關系
-
組織間,存在一個上下級的聯系
-
權限間,有些系統會將權限分組,但那只是一個打包的快捷方式,權限組完全可以理解為是權限以外的東西
-
用戶與組織,用戶有一個或者多個組織,這在以前的系統中用rdbms實現無比麻煩,有些系統甚至只能做到一個用戶同時只屬於一個組織
-
用戶與權限,用戶同時具備多個權限,問題同上,權限組的加入讓問題更加復雜化
-
組織與權限,有些系統甚至將組織和權限關聯,因此不得不做出一些約定,否則其實現沒有確定性
我們現在從系統功能出發來分解這些要素:
-
用戶登錄,用戶名/密碼就足夠了,所以基本用戶表就應該只有用戶名/密碼
-
用戶資料維護,只需要用戶資料,與用戶名關聯。用戶資料的修改以前也會用表來完成,實際上,你只需要一個文件或一個字段來存儲用戶所有的資料,因為所有修改每次完全提交所有資料字段都不為過。很容易理解,你絕對不會將員工word格式的簡歷存儲在數據庫中,那么又何必把他的電話號碼家庭住址也存儲起來?
-
組織結構調整。實際上只是上下級關系的調整,只需要記錄每個組織的上級部門的名字即可,當然專門弄一個關系表也ok。
-
權限列表和權限組維護。權限組單獨一張表記錄包含的權限名,權限自身是名字的平面表,之間都沒有任何關系。具體的原因自己想去。
-
用戶和組織關系維護。建立一張關系表,慢慢維護去吧。一般來說,從組織來維護用戶比較合理,因為人事變更是組織自身的周期性行為,而不是個人的突發性行為。
-
用戶和權限關系維護。維護一張關系表,事實上,這張表就足以應付所有的權限校驗,因此從優化角度來說,將權限的命名變得有意義相當重要:根據當前或選定用戶,獲取他所有的權限,並且通過權限的名字就能夠了解具體的權限定義做出判斷。
-
組織和權限關系維護。請不要實現為關系表,寧可將此實現為組織-用戶和用戶-權限的兩次查詢在前端做組合。例如某個需求是,A部門下所有員工都能夠獲得訪問a1系統的首頁權限,完全可以實現為:管理員查詢A部門下所有員工,選中他們,查找所有權限中是否有“訪問a1系統的首頁權限”,有的話,賦予當前選擇的用戶,沒有的話新建這么一個名字的權限並賦予當前選擇的用戶,並在完成后通知a1系統的開發人員,將這個名字加入到校驗邏輯中去。
這樣一來,我們有了:
-
用戶密碼表,用戶名/密碼2個字段
-
用戶資料文件夾,文件按用戶名取名。
-
組織結構表,只存名字和上級組織名字,2個字段
-
權限表,權限的名字1個字段
-
權限組表,權限組的名字和所含權限以分隔符分割的聯合,2個字段
-
用戶和組織關系,用戶名和組織名2個字段
-
用戶和權限關系,用戶名和權限名2個字段
進一步的優化是:
-
組織以域名寫法來規范,例如XX公司XX部XX2科,那就是XX2科.XX部.XX公司,這是ldap/x.500的標准寫法(我更傾向於從大到小的中國式寫法,這樣通過自然排序就能夠獲得樹狀結構)。如此命名,連上級組織字段都不用寫了。如果用戶只有一個組織,那么用戶和組織關系表也不用寫了。
-
用戶的所有權限存為一個字段,以分隔符分割(可選的)。一般來說,用戶權限也就幾十個,全部取出沒有任何問題,校驗方可以很方便的做判斷。一個做法是,用戶A有權限a1,a2,a3,那么權限字段就是|a1|a2|a3|,a3校驗時,只需要做indexOf('|a3|')即可。另一個優化方案是保證權限名自然有序,這樣校驗時就可以用2分法加速。
優化結果是:
-
用戶密碼表,2字段
-
用戶資料文件夾
-
組織結構表,1字段
-
權限表,1字段
-
權限組表,2字段
-
用戶和組織關系,2字段,1對1(或1對多,1用戶多組織時)
-
用戶和權限關系,2字段,1對1(或1對多,方案2)
我們看一下優化后的好處:
-
用戶密碼表很重要,可以單獨用加密性強的庫或者表存它
-
用戶資料文件夾可以很方便的做備份,離職員工也能夠做資料存檔。如果使用json或者xml格式存儲的話,瀏覽器直接解析,對於接口調用來說太方便了。並且,文件系統可以利用操作系統級別的ACL來管理,安全性細度更高
-
與當前用戶相關的東西,除用戶資料外,在用戶登錄后都可以一次取出,然后塞到session中去。例如他的組織,他的權限列表。由於這些信息非常細碎,而且只在登錄后做一次,沒必要通過文件緩存。
-
權限、組織結構,都可以一次取出並用json文件緩存供瀏覽器使用,用戶與組織關系可按組織分文件緩存。由於每個表字段少或者關系清楚,用文件緩存就很容易確定緩存刷新的時機。
