作為一名使用 Oracle 的開發人員,在寫這個系列博文之前,我原打算僅對常用 DDL 和 DML 做一個總結就算了。但在本人閱讀《劍破冰山——Oracle開發藝術》第一章——《大話數據庫編程規范》時,對書中內容產生了強烈的共鳴,因此決定先寫 數據庫編程規范。本文核心內容來自該書第一章,有刪改,且增加了一些本人對書中內容的理解和實際開發中的經驗之談。
1、書寫規范
良好的書寫規范給人以享受和藝術的體驗,而糟糕的書寫不僅可讀性差,還給人敬而遠之的感覺。數據庫編程作為應用程序開發的一部分,也應當要有相應的書寫規范。
1.1、大小寫風格
- 所有數據庫關鍵字和保留字均使用大寫。
我相信一定會有人對這個規范持懷疑態度!我也曾為 SQL 語句到底該用大寫還是用小寫糾結了好幾年!在學習和工作中我先后使用過大小寫混合、全小寫、全大寫等風格,嚴格來說,沒有任何一種是在不同場景下都絕對最好的風格,但綜合來講,數據庫關鍵字和保留字全大寫是一種相對較好的風格。
在我學習數據庫編程時,我的老師用的是帕斯卡命名法,這種命名書寫方便、閱讀美觀,於是我延續了老師的風格,並沿用到工作中,從未感覺有任何不妥。直到我第一次使用 Oracle,我用標准的帕斯卡命名法寫好了表結構定義,執行成功之后,打開設計器看到表結構那一刻,我的眼神是無辜的、內心是崩潰的!因為表名和字段名全都變成了大寫,那時我看着順眼的只有帕斯卡命名法命名的表和字段。向來不願主動放棄的我覺得一定有辦法讓 Oracle 支持帕斯卡命名法,還是菜鳥一個的我折騰了半天最后還是不了了之,這令我久久不能釋懷,我也因此曾一度非常厭惡 Oracle。
在 Oracle 中,表名和字段名是會被徹底的強制轉成大寫的,而諸如:視圖、函數、存儲過程、觸發器等對象,雖然通過工具查看時對象名也是大寫的,但 DDL 語句中的名稱卻會保持原來的大小寫。而任務的 DDL 語句甚至會被強制轉成小寫的。
實際上,Oracle 的表名和字段名也是有辦法支持大小寫的。只需要在創建表的時候,把表名和字段名用引號包裹起來,就可以任意選擇帕斯卡命名法和駱駝命名法了。但問題是訪問表或字段時也得用引號包裹起來才能訪問,否則直接報找不到對象之類的錯誤。而實際項目中我從未見人這么用過,貌似大部分人都不知道這種怪異的用法!
1.2、縮進風格
- 程序塊嚴格采用縮進風格書寫,保證代碼清晰易讀,風格一致,統一縮進 2/4 個空格。
程序塊主要是指表結構、視圖、函數、存儲過程等數據庫對象定義中的程序塊。縮進必須使用空格,不允許使用 Tab 鍵。以免在用不同編輯器閱讀程序時,因 Tab 鍵所設置的空格數目不同而造成程序布局不整齊。
- 當一條語句過長需要占用多行時,每行開頭的關鍵字與第一行的關鍵字進行對齊。
書中說應該進行嚴格的右對齊,但我本人還是喜歡嚴格的左對齊,畢竟一般編程語言都是提倡左對齊,而且左對齊也更容易書寫和控制。我個人覺得換行關鍵字左對齊還是右對齊都 OK,但必須是嚴格對齊。
左對齊代碼示例
IF v_staff_name IS NULL THEN
SELECT t.staff_name -- 同上一行相比縮進 2 個空格
INTO v_staff_name -- INTO 與 SELECT 進行左對齊
FROM t_staff t -- FROM 與 SELECT 進行左對齊
WHERE t.staff_id=:p_staff_id; -- WHERE 與 SELECT 進行左對齊
END IF;
右對齊代碼示例
IF v_staff_name IS NULL THEN
SELECT t.staff_name -- 同上一行相比縮進 2 個空格
INTO v_staff_name -- INTO 與 SELECT 進行右對齊
FROM t_staff t -- FROM 與 SELECT 進行右對齊
WHERE t.staff_id=:p_staff_id; -- WHERE 與 SELECT 進行右對齊
END IF;
1.3、換行
- 不允許把多個語句寫在一行中,即一行只寫一條語句。
- 避免將復雜的 SQL 語句寫成一行,建議在關鍵字和謂詞處換行。
- 相對獨立的程序塊之間必須加空行。BEGIN、END 等指令獨立成行。
- 太長的表達式應在低優先級操作符處換行,操作符或關鍵字放在新行之首。划分出新行應適當縮進,使整個語句排列整齊。
- 當多個不同類型操作符混合使用時,應當用括號進行隔離區分,使得代碼更加清晰易懂。
1.4、其它
- 避免在發布代碼中使用 SELECT * 語句,不要用 * 來代替所有字段,應當給出字段列表,以免在表結構發生變化時應用程序出現無法識別等錯誤情況。
- 在發布代碼中 INSERT 語句必須給出字段列表,以免在表結構發生變化時發生編譯錯誤。
- 當一個 PLSQL 或 SQL 語句中涉及多個表時,始終使用別名來限定表名和字段名,這樣其他人閱讀起來更方便,避免了含義模糊的引用,並能夠在別名中清晰地判斷出表名和相關字段。
凡是將來有可能涉及多張表的 SQL 語句,即使當下只有一個表也最好取個別名,且訪問表中任何字段都用表的別名來限定,不要在一條語句中反復使用某個別名。建議養成總是給表取別名且用表的別名來限定表中字段名的好習慣,這可能會給你節省大量時間,也可能會帶來意想不到的驚喜。
本人工作中曾遇到寫在后端程序中的一條 SQL 語句在某個測試環境中運行正常,但在另一個測試環境中就有問題,忘記了是會報錯還是查不到數據,把那條 SQL 語句拷貝到開發環境中運行也沒問題。由於那條語句較長,涉及多個表且包含子查詢,查詢列表的字段超過 20 個,條件中涉及的字段也很多,有些表有別名,有些表又沒有,部分字段有表別名限定,部分有表別名的字段又沒限定,還有一些沒有表別名的字段自然也就沒有限定了,結果看了老半天,眼睛都看花了也找不出問題來。無奈之下我把那條語句照抄了一遍,但我給每個表都取了別名,無論查詢列表還是過濾條件中的字段我都有用表別名來限定,原本我只是想按照我的習慣把語句抄寫整理一遍,方便進一步查找問題,結果寫好之后一測試,開發環境及所有測試環境都 OK 了!
- 確保變量和參數在類型和長度上與表數據列相匹配。以免當較寬或較大的數據傳進來時產生異常。
- 減少控制語句的檢查次數,例如 IF...ELSE 控制語句中,應將最常用的符合條件前置。
2、命名規范
命名規范想要做到完全一致幾乎是不可能的,但我們仍要盡量去遵守,必要的時候通過代碼審查和專家評審來進行約束,因為一個不成熟的規范總好過沒有規范。
2.1、數據庫對象命名
- 以下是常見的幾種數據庫命名風格
- 1、ProjectName/projectName:這是我最喜歡的命名風格,而且一般編程語言也都提倡這類命名風格。書中說這種適合那些英文比較好,並且喜歡抑揚頓挫和有藝術美感的人。如果你用的不是 Oracle,這種命名也許是最好的選擇,即使在 Oracle 中你也能在表結構定義之外地方使用這種命名,但問題是 Oracle 編程過程中幾乎所有語句都是在操作表和字段。我個人認為除非你打算同時采用多個命名風格,否則單單這一種命名風格用在 Oracle 中不太合適。
- 2、PROJECTNAME/projectname:我嘗試過這種命名風格,感覺名稱短的時候還好,要是名稱比較長,尤其是大寫,寫起來費勁,看起來也費勁。書中說這種適合那些英文好,且比較嚴禁的人。可能還是我英文太差吧,至少我以后不會再大量使用這種命名了。
- 3、PROJECT_NAME/project_name:書中說這種適合那些做開發的人,的確開發人員命名時往往會習慣性的加上前綴、后綴或下划線等。應該說我並非特別喜歡這種命名,但如果團隊沒有其它要求或約束的情況下,我會首選這種命名來進行 Oracle 編程。
- 4、XMMC/xmmc/XM_MC/xm_mc:書中說這種適合熱愛中文的人,前提是恐怕你得對這些縮寫先做好相關備注,等大家習慣了才行。首先我肯定是個熱愛中文的人,但也許是我被這種命名坑的太多太狠了,所以情感上我特別厭惡這種命名。有些行業的數據庫國標或省標也是這類命名,大家基於同樣的標准用起來也還好。我曾接手過的一個項目沒有這些標准約束,結果就是各種奇葩的命名,給我熟悉這個項目帶來了較大的困難。舉個實際的例子,項目里有個“內部合同編號”,后來我發現 HTBH、HT_BH、HT_NBBH、NB_HTBH、CONTRACT_BH、CONTRACT_CODE 這些縮寫都有可能是這個意思。所以如果你的項目所屬行業沒有國標、省標等數據庫標准,建議你最好遠離這種風格。
實際上這幾種命名風格各有千秋,很難去指責或否定那種不好,完全取決於整個公司或項目中多數人的習慣,沒有十全十美的命名規范,只要絕大多數人心甘情願地去遵循,那就是好的命名規范。
- 為避免不必要的沖突和麻煩,最好不要用數據庫關鍵字和保留字。
查詢 Oracle 中的關鍵字和保留字的語句如下:
SELECT * FROM v$reserved_words WHERE reserved='Y'; -- reserved='Y' 表示已被完全禁止
實際上 Oracle 是不建議使用 v$reserved_words 表中所有關鍵字,但這個表里的關鍵字太多了。
- 嚴禁使用帶空格的名稱來給表或字段命名。在生產數據庫腳本並重新加載的時候可能會出現錯誤而被迫終止。
- 除數據庫名長度為 1~8 個字符外,其余為 1~30 個字符。命名只能使用英文字母、數字和下划線。
- 其它各種對象的命名與表和字段的命名風格保持一致即可,最好用不同的前綴,采用前綴的方式來命名對象則很容易通過排序對對象進行區分。其它對象命名規范表如下:
對象名 | 前綴 | 范例 |
---|---|---|
表(table) | t_/tbl_/不加前綴 | t_user/tbl_user/user |
視圖(view) | v_/view_ | v_user/view_user |
物化視圖(materialized view) | mv_ | mv_user |
函數(function) | f_/fn_/func_ | fn_user/func_user |
存儲過程(procedure) | p_/sp_/proc_ | sp_user/proc_user |
觸發器(trigger) | trg_ | trg_user |
包和包體(package&package body) | pkg_ | pkg_user |
類和類體(type&type body) | typ_ | typ_user |
主鍵(primary key) | pk_ | pk_user |
外鍵(foreign key) | fk_ | fk_user |
唯一索引(unique index) | uk_ | uk_user |
普通索引(normal index) | idx_ | idx_user |
位圖索引(bitmap index) | bk_ | bk_user |
序列(sequence) | seq_ | seq_user |
簇(cluster) | c_ | c_user |
數據庫鏈接(database link) | 用的不多 | |
同義詞(synonym) | 用的不多 |
2.2、變量命名
- 所有 PLSQL 中的變量與對象名規則相似,如下表所示:
變量類型 | 前綴 | 范例 |
---|---|---|
輸入變量 | i_/i | i_user_id/iuserid |
輸出變量 | o_/o | o_user_name/ousername |
輸入輸出變量 | io_/io | io_user_id/iouserid |
普通變量 | v_/v | v_user_id/vuserid |
全局變量 | gv_/gv | gv_user_id/gvuserid |
常量 | 全大寫 | pi |
游標 | cur_ | cur_user_info |
用戶自定義類型 | type_ | type_user_info |
保存點(save point) | spt_ | spt_user_info |
- 命名不允許使用中文或特殊字符。命名若使用特殊約定或縮寫,則要注釋說明。
- 使用有意義、易於記憶、描述性強、簡短及唯一的英文單詞。保持自己特有的命名風格,不可來回變換。
說明:個人命名風格,在符合所在項目組的命名規則的前提下,才可以使用。
- 對於變量名,禁止取單個字符(如i/j……),建議除了要有具體含義外,還要能表明變量類型。
說明:在長的 SQL 語句中,變量用單個字符表示,容易寫錯,而編譯器往往檢查不出來,有可能因為這個小小的錯誤而花費大量的時間。
3、注釋規范
注釋規范是判斷一個開發人員優劣和成熟度的重要標准。一個優秀的研發人員必然是經過深思熟慮之后才洋洋灑灑妙筆生花的,注釋的書寫體現了一個人思考問題的全過程和步驟。
- 在一般情況下,源程序有效注釋量必須在 30% 左右。
說明:注釋的原則是有助於對程序閱讀理解,在該加的地方都加了,注釋不易太多也不能太少,注釋語言需准確、易懂、簡潔、精煉。
- 所有變量定義都要加注釋,說明該變量的用途和含義。
- 注釋內容要清晰、明了、含義准確,防止注釋二義性。在代碼的功能、意圖層次上進行注釋,提供有用、額外的信息。避免在一行代碼或表達式中間插入注釋。盡量使用“--”注釋,行尾必須用“--”來注釋。
- 對程序分支必須寫注釋。在程序塊結束行右方加注釋,以表明程序塊結束。
說明:這些語句往往是程序實現某一特定功能的關鍵,對於維護人員來說,良好的注釋有助於更好的理解程序,有時甚至優於看設計文檔。
- 注釋應與其描述的代碼相似,對代碼的注釋應放在其上方或右方(對單條語句的注釋)相近未知,不可放在下面。注釋要與所描述的代碼進行同樣的縮排。注釋上面的代碼最好空行隔開。
4、語法規范
良好的語法規范有助於書寫出高效、完備的 PLSQL 程序,同時有助於提高系統的容錯性、健壯性和可追溯性。
- 避免隱式類型轉換。
說明:在書寫代碼時,必須確定表的結構和表中各個字段的數據類型,特別是在書寫查詢條件時的字段就更要注意了。這個也是導致 SQL 性能不佳的原因之一。
- 為了方便不同數據庫平台的移植,盡量使用 SQL99 標准,而不要用 Oracle 的“方言”。
例如:DECODE 函數完全可以用 CASE WHIN 語句代替,而且可編程性更強。(+)=右關聯用 RIGHT OUTER JOIN 語句代替。=(+)左關聯用 LEFT OUTER JOIN 語句代替。
-
對於非常復雜的 SQL(特別是多層嵌套、帶子查詢的)語句,應考慮是否由設計不當引起的。對於比較復雜的 SQL 語句可以考慮使用程序實現,原則上遵循一句話只做一件事。
-
關於 SQL 處理的優先級
- 1>、靜態 SQL > 動態 SQL
- 2>、綁定變量的 SQL > 動態 SQL(在 OLTP 系統中建議這么做)
- 3>、SQL > PLSQL 的過程,極端復雜的 SQL 除外
- 4>、SQL > 游標遍歷
- 5>、Oracle 函數 > 自定義函數
- 6>、盡量使用 Oracle 分析函數代替同一個表多次的關聯。
-
原則上不要使用動態 SQL,如果非得使用動態 SQL,建議使用綁定變量。
-
一定要及時關閉和釋放游標。
-
建議在異常處理中,把收集到的錯誤信息記入錯誤日志,以備查詢和分析。但對於由客戶端調用的存儲過程,建議不要捕獲異常,而是由客戶端程序來處理。
-
不要對空的變量值用比較運算符比較。如果變量可能為空,應使用 IS NULL 或 IS NOT NULL 或 NVL 函數進行比較。
-
盡可能地使用相關表字段的類型定義,如 %TYPE、%ROWTYPE。這樣做當表結構發生變動的時候,能夠最大程度的做到容錯性和健壯性。
-
在存儲過程中聲明變量應集中在 AS 和 BEGIN 關鍵字之間,不允許在代碼中隨意定義變量。在定義變量時,完成相同模塊功能的變量應放在一起,與不同模塊的變量應空行隔開,增加代碼的可讀性。
5、總結
正規點的 IT 公司一般都會制定一些編程規范,但這其中仍有不少公司只片面的強調前后端編程規范,忽略了數據庫編程規范,這既不可取也不合理的。
5.1、代碼的可讀性比說明文檔更重要
代碼的可讀性比說明文檔更重要,這是我在工作中總結出的“真理”之一。如果你有被糟糕的程序結構、怪異的變量命名、凌亂的編碼風格……折磨過的經歷,那么我相信你可能也會有類似的“名句”。
5.2、編程規范必不可少
在我學習編程的時候,我的老師就要求我們取變量名時要取有意義的名字,說實在的那時候我還不能意識到這有多重要,值得慶幸的是我記住了老師的話,並落實到學習和實際工作中,就這樣在無形中養成了一個好的編程習慣。
在我工作這幾年中,接觸的很多代碼可讀性都不高,這些代碼的原作者一般也不在公司了,所以往往需要花比較多的時間才能弄懂個大概。比這個還鬧心的是,這些代碼的可維護性更差,老板可能會想當初那個人做這個功能也就花了兩天,給你一天改一下應該是足夠的,但他不知道的是一天時間可能你根本沒法搞懂那個程序,如果你稀里糊塗的就去改,那結果可能更糟,你會發現隨便一改就出來好幾個 BUG,然后你再去改 BUG,等你把明顯的 BUG 都消滅之后可能已經過去兩天了,而且那個程序也被你改的更長更復雜了,往后更加難改了,如果老板再說要改你可能會建議把這個程序扔到垃圾桶,然后自己重新做一個更好的。
如今有大量開發人員在程序的苦海中重復着低級的勞動,其中一個重要原因就是項目當初沒有遵從良好的編程規范,導致代碼的可讀性、可維護性、可移植性、可測試性、開發效率、運行效率等都比較差。所以在正規開發過程中,編程規范是必不可少的!
本文鏈接:http://www.cnblogs.com/hanzongze/p/oracle-codingstandard.html
版權聲明:本文為博客園博主 韓宗澤 原創,作者保留署名權!歡迎通過轉載、演繹或其它傳播方式來使用本文,但必須在明顯位置給出作者署名和本文鏈接!本人初寫博客,水平有限,若有不當之處,敬請批評指正,謝謝!