## java開發規范
>在我們的日常開發過程中好的代碼開發規范是必不可少的,下面我們來注意一下具體要注意哪些。
### **1.類名使用** `UpperCamelCase` **風格**
>例如:`ForceCode` `UserDO` `HtmlDTO` `XmlService` `TcpUdpDeal` `TaPromotion`
### **2.方法名、參數名、成員變量、局部變量都統一使用** `lowerCamelCase` **風格。**
>例如:`localValue` `getHttpMessage()` `inputUserId`
### **3.常量命名全部大寫,單詞間用下劃線隔開,力求語義表達完整清楚,不要嫌名字長。**
>例如:`MAX_STOCK_COUNT` `CACHE_EXPIRED_TIME`
### **4.抽象類命名使用** `Abstract` **或** `Base` **開頭;異常類命名使用** `Exception` **結尾;測試類命名以它要測試的類的名稱開始,以** `Test` **結尾。**
### **5.類型與中括號緊挨相連來表示數組。**
>定義整形數組 `int[]` `arrayDemo`
### **6.**`POJO` **類中的任何布爾類型的變量,都不要加** `is` **前綴,否則部分框架解析會引起序列化錯誤。**
>例如:在本文 MySQL 規約中的建表約定第一條,表達是與否的值采用 is_xxx 的命名方式,所以,需要在設置從 is_xxx 到 xxx 的映射關系。
### **7.包名統一使用小寫,點分隔符之間有且僅有一個自然語義的英語單詞。包名統一使用單數形式,但是類名如果有復數含義,類名可以使用復數形式。**
>例如:應用工具類包名為 `com.alibaba.ei.kunlun.aap.util`類名為 `MessageUtils`(此規則參考 `spring` 的框架結構)
### **8.在** `long` **或者** `Long` **賦值時,數值后使用大寫的 L,不能是小寫的 l,小寫容易跟數字混淆,造成誤解。**
>例如:Long a = 2l; 寫的是數字的 21,還是 Long 型的 2。
### **9.不要使用一個常量類維護所有常量,要按常量功能進行歸類,分開維護。**
>例如:大而全的常量類,雜亂無章,使用查找功能才能定位到修改的常量,不利于理解,也不利于維護。
### **10.如果變量值僅在一個固定范圍內變化用** `enum` **類型來定義。**
>說明:如果存在名稱之外的延伸屬性應使用 `enum` 類型,下面正例中的數字就是延伸信息,表示一年中的第幾個季節。
```
public enum SeasonEnum {
SPRING(1), SUMMER(2), AUTUMN(3), WINTER(4);
private int seq;
SeasonEnum(int seq) {
this.seq = seq;
}
public int getSeq() {
return seq;
}
}
```
### **11.** `IDE` **的** `text file encoding` **設置為** `UTF-8`; `IDE` **中文件的換行符使用** `Unix` **格式,不要使用** `Windows` **格式。**
### **12.任何貨幣金額,均以最小貨幣單位且整型類型來進行存儲。**
### **13.浮點數之間的等值判斷,基本數據類型不能用** `==` **來比較,包裝數據類型不能用** `equals` **來判斷。**
>說明:浮點數采用“尾數+階碼”的編碼方式,類似于科學計數法的“有效數字+指數”的表示方式。二進制無法精確表示大部分的十進制小數。
```
float a = 1.0f - 0.9f;
float b = 0.9f - 0.8f;
float diff = 1e-6f;
if (Math.abs(a - b) < diff) {
System.out.println("true");
}
```
### **14.類成員與方法訪問控制從嚴。**
>1) 如果不允許外部直接通過 `new` 來創建對象,那么構造方法必須是 `private`。
>2) 工具類不允許有 `public` 或 `default` 構造方法。
>3) 類非 `static` 成員變量并且與子類共享,必須是 `protected`。
>4) 類非 `static` 成員變量并且僅在本類使用,必須是 `private`。
>5) 類 `static` 成員變量如果僅在本類使用,必須是 `private`。
>6) 若是 `static` 成員變量,考慮是否為 `final`。
>7) 類成員方法只供類內部調用,必須是 `private`。
>8) 類成員方法只對繼承類公開,那么限制為 `protected`。
### **說明:**
任何類、方法、參數、變量,嚴控訪問范圍。過于寬泛的訪問范圍,不利于模塊解耦。思考:如果是一個 `private` 的方法,想刪除就刪除,可是一個 `public` 的 `service` 成員方法或成員變量,刪除一下,不得手心冒點汗嗎?變量像自己的小孩,盡量在自己的視線內,變量作用域太大,無限制的到處跑,那么你會擔心的。
### **15.用戶敏感數據禁止直接展示,必須對展示數據進行脫敏。**
>說明:中國大陸個人手機號碼顯示為:137****0969,隱藏中間 4 位,防止隱私泄露。
### **16.用戶輸入的** `SQL` **參數嚴格使用參數綁定或者** `METADATA` **字段值限定,防止** `SQL` **注入,禁止字符串拼接** `SQL` **訪問數據庫。**
### **17.用戶請求傳入的任何參數必須做有效性驗證。**
>說明:忽略參數校驗可能導致:
>1.`page size` 過大導致內存溢出
>2.惡意 `order by` 導致數據庫慢查詢
>3.緩存擊穿
>4.`SSRF`
>5.任意重定向
>6.`SQL` 注入,`Shell` 注入,反序列化注入
>7.正則輸入源串拒絕服務 `ReDoS`
**Java 代碼用正則來驗證客戶端的輸入,有些正則寫法驗證普通用戶輸入沒有問題,但是如果攻擊人員使用
的是特殊構造的字符串來驗證,有可能導致死循環的結果。**
### **18.禁止向 HTML 頁面輸出未經安全過濾或未正確轉義的用戶數據。**
### **19.表單、AJAX 提交必須執行 CSRF 安全驗證。**
>說明:CSRF(Cross-site request forgery)跨站請求偽造是一類常見編程漏洞。對于存在 CSRF 漏洞的應用/網站,攻擊者可以事先構造好 URL,只要受害者用戶一訪問,后臺便在用戶不知情的情況下對數據庫中用戶參數進行相應修改。
### **20.URL 外部重定向傳入的目標地址必須執行白名單過濾。**
### **21.在使用平臺資源,譬如短信、郵件、電話、下單、支付,必須實現正確的防重放的機制,如數量限制、疲勞度控制、驗證碼校驗,避免被濫刷而導致資損。**
>說明:如注冊時發送驗證碼到手機,如果沒有限制次數和頻率,那么可以利用此功能騷擾到其它用戶,并造成短信平臺資源浪費。
### **22.發貼、評論、發送即時消息等用戶生成內容的場景必須實現防刷、文本內容違禁詞過濾等風控策略。**
### **23.數據庫表約定。**
1).表名、字段名必須使用小寫字母或數字,禁止出現數字開頭,禁止兩個下劃線中間只出現數字。數據庫字段名的修改代價很大,因為無法進行預發布,所以字段名稱需要慎重考慮。
>說明:`MySQL` 在 `Windows` 下不區分大小寫,但在 `Linux` 下默認是區分大小寫。因此,數據庫名、表名、字段名,都不允許出現任何大寫字母,避免節外生枝。
例如:`aliyun_admin` `rdc_config` `level3_name`
2).表達 `是與否` 概念的字段,必須使用 `is_xxx` 的方式命名,數據類型是 `unsigned tinyint`(1 表示是,0 表示否)。
>說明:任何字段如果為非負數,必須是 `unsigned`。
>注意:POJO 類中的任何布爾類型的變量,都不要加 `is` 前綴,所以,需要在設置從 `is_xxx` 到 `Xxx` 的映射關系。數據庫表示是與否的值,使用 `tinyint` 類型,堅持 `is_xxx` 的命名方式是為了明確其取值含義與取值范圍。
>例如:表達邏輯刪除的字段名 `is_deleted`,1 表示刪除,0 表示未刪除。
3).主鍵索引名為 `pk_`字段名;唯一索引名為 `uk_`字段名;普通索引名則為 `idx_`字段名。
>說明:`pk_` 即 `primary key`;`uk_` 即 `unique key`;`idx_` 即 `index` 的簡稱。
4).小數類型為 `decimal`,禁止使用 `float` 和 `double`。
>說明:在存儲的時候,`float` 和 `double` 都存在精度損失的問題,很可能在比較值的時候,得到不正確的結果。如果存儲的數據范圍超過 `decimal` 的范圍,建議將數據拆成整數和小數并分開存儲。
5).如果存儲的字符串長度幾乎相等,使用 `char` 定長字符串類型。
6).`varchar` 是可變長字符串,不預先分配存儲空間,長度不要超過 `5000`,如果存儲長度大于此值,定義字段類型為 `text`,獨立出來一張表,用主鍵來對應,避免影響其它字段索引效率。
7).表必備三字段:`id` `gmt_create` `gmt_modified`。
說明:其中 `id` 必為主鍵,類型為 `bigint unsigned` 單表時自增、步長為 `1`。`gmt_create` `gmt_modified`的類型均為 `datetime` 類型,前者現在時表示主動式創建,后者過去分詞表示被動式更新。
8).表的命名最好是遵循 `業務名稱_表的作用`。
>例如:`alipay_task` `force_project` `trade_config`
9).庫名與應用名稱盡量一致。
10).如果修改字段含義或對字段表示的狀態追加時,需要及時更新字段注釋。
11).字段允許適當冗余,以提高查詢性能,但必須考慮數據一致。冗余字段應遵循:
>1) 不是頻繁修改的字段。
>2) 不是唯一索引的字段。
>3) 不是 `varchar` 超長字段,更不能是 `text` 字段。
>說明:各業務線經常冗余存儲商品名稱,避免查詢時需要調用 `IC` 服務獲取。
10).單表行數超過 `500` 萬行或者單表容量超過 `2GB`,才推薦進行分庫分表。
>說明:如果預計三年后的數據量根本達不到這個級別,請不要在創建表時就分庫分表。
11).合適的字符存儲長度,不但節約數據庫表空間、節約索引存儲,更重要的是提升檢索速度。
>說明:無符號值可以避免誤存負數,且擴大了表示范圍。
### **24.索引規約**
1).業務上具有唯一特性的字段,即使是組合字段,也必須建成唯一索引。
>說明:不要以為唯一索引影響了 insert 速度,這個速度損耗可以忽略,但提高查找速度是明顯的;另外,即使在應用層做了非常完善的校驗控制,只要沒有唯一索引,根據墨菲定律,必然有臟數據產生。
2).超過三個表禁止 `join`。需要 `join` 的字段,數據類型保持絕對一致;多表關聯查詢時,保證被關聯的字段需要有索引。
>說明:即使雙表 `join` 也要注意表索引、`SQL 性能`。
3).在 `varchar` 字段上建立索引時,必須指定索引長度,沒必要對全字段建立索引,根據實際文本區分度決定索引長度。
>說明:索引的長度與區分度是一對矛盾體,一般對字符串類型數據,長度為 20 的索引,區分度會高達 90%以上,可以使用 count(distinct left(列名, 索引長度))count(*)的區分度來確定。
4).如果有 `order by` 的場景,請注意利用索引的有序性。`order by` 最后的字段是組合索引的一部分,并且放在索引組合順序的最后,避免出現 `file_sort` 的情況,影響查詢性能。
>說明:where a=? and b=? order by c; 索引:a_b_c
5).利用覆蓋索引來進行查詢操作,避免回表。
>說明:如果一本書需要知道第 11 章是什么標題,會翻開第 11 章對應的那一頁嗎?目錄瀏覽一下就好,這個目錄就是起到覆蓋索引的作用。
>例如:能夠建立索引的種類分為主鍵索引、唯一索引、普通索引三種,而覆蓋索引只是一種查詢的一種效果,用 `explain` 的結果,`extra` 列會出現:`using index`。
7).利用延遲關聯或者子查詢優化超多分頁場景。
>說明:`MySQL` 并不是跳過 `offset` 行,而是取 `offset+N` 行,然后返回放棄前 `offset` 行,返回 `N` 行,那當 `offset` 特別大的時候,效率就非常的低下,要么控制返回的總頁數,要么對超過特定閾值的頁數進行 SQL改寫。
>正例:先快速定位需要獲取的 id 段,然后再關聯:
```
SELECT a.* FROM 表 1 a, (select id from 表 1 where 條件 LIMIT 100000,20 ) b where a.id=b.id
```
8).`SQL` 性能優化的目標:至少要達到 `range` 級別,要求是 `ref` 級別,如果可以是 `consts` 最好。
>1) `consts` 單表中最多只有一個匹配行(主鍵或者唯一索引),在優化階段即可讀取到數據。
>2) `ref` 指的是使用普通的索引`(normal index)`。
>3) `range` 對索引進行范圍檢索。
9).建組合索引的時候,區分度最高的在最左邊。
>例如:如果 where a=? and b=?,a 列的幾乎接近于唯一值,那么只需要單建 idx_a 索引即可。
### **25.不得使用外鍵與級聯,一切外鍵概念必須在應用層解決。**
>說明:(概念解釋)學生表中的 `student_id` 是主鍵,那么成績表中的 `student_id` 則為外鍵。如果更新學生表中的 `student_id`,同時觸發成績表中的 `student_id` 更新,即為級聯更新。外鍵與級聯更新適用于單機低并發,不適合分布式、高并發集群;級聯更新是強阻塞,存在數據庫更新風暴的風險;外鍵影響數據庫的插入速度。
### **26.禁止使用存儲過程,存儲過程難以調試和擴展,更沒有移植性。**
### **27.數據訂正(特別是刪除或修改記錄操作)時,要先 select,避免出現誤刪除,確認無誤才能執行更新語句。**
### **28.在表查詢中,一律不要使用** `*` **作為查詢的字段列表,需要哪些字段必須明確寫明。**
>1)增加查詢分析器解析成本。
>2)增減字段容易與 `resultMap` 配置不一致。
>3)無用字段增加網絡消耗,尤其是 `text` 類型的字段。