1. 程式人生 > >課堂練習 Word count

課堂練習 Word count

即使 net 定義變量 獲取 UNC num 詞語 當前 upd

1. 團隊介紹

團隊成員:席夢寒,胡琦

2. 項目計劃

我們選第一、二個功能點進行編程。

具體計劃:

(1).首先爬取網站內容及網頁長度;

(2).對爬取的文件內容進行word count操作;

(3).對選定詞語出現頻率進行統計。

3. 環境配置

編程語言:python

代碼規範:

一、命名規約

1.【強制】所有編程相關命名均不能以下劃線或美元符號開始,也不能以下劃線或美元符號結束。反例: _name / __name / $Object / name_ / name$ / Object$

2.【強制】類名使用UpperCamelCase風格,必須遵從駝峰形式,但以下情形例外:(領域模型的相關命名)DO / DTO / VO / DAO等。


正例:MarcoPolo / UserDO / XmlService / TcpUdpDeal / TaPromotion 反例:macroPolo / UserDo /XMLService / TCPUDPDeal / TAPromotion

3.【強制】方法名、參數名、成員變量、局部變量都統一使用lowerCamelCase風格,必須遵從駝峰形式。
正例:localValue / getHttpMessage() / inputUserId

4.【強制】常量命名全部大寫,單詞間用下劃線隔開,力求語義表達完整清楚,不要嫌名字長。正例: MAX_STOCK_COUNT 反例: MAX_COUNT

5.【強制】抽象類命名使用Abstract或Base開頭;異常類命名使用Exception結尾;測試類命名以它要測試的類的名稱開始,以Test結尾。

6.【強制】POJO類中的任何布爾類型的變量,都不要加is,否則部分框架解析會引起序列化錯誤。

反例:定義為基本數據類型boolean isSuccess;的屬性,它的方法也是isSuccess(),RPC

框架在反向解析的時候,“以為”對應的屬性名稱是success,導致屬性獲取不到,進而拋出異常。

7.【強制】包名統一使用小寫,點分隔符之間有且僅有一個自然語義的英語單詞。包名統一使用單數形式,但是類名如果有復數含義,類名可以使用復數形式。

正例: 應用工具類包名為com.alibaba.mpp.util、類名為MessageUtils(此規則參考spring 的框架結構)

8.【推薦】如果使用到了設計模式,建議在類名中體現出具體模式。



說明:將設計模式體現在名字中,有利於閱讀者快速理解架構設計思想。

正例:public class OrderFactory; public class LoginProxy;

public classResourceObserver;

9.【推薦】接口類中的方法和屬性不要加任何修飾符號(public 也不要加),保持代碼的簡潔性,並加上有效的javadoc註釋。盡量不要在接口裏定義變量,如果一定要定義變量,肯定是與接口方法相關,並且是整個應用的基礎常量。

正例:接口方法簽名:void f();

接口基礎常量表示:String COMPANY = "alibaba";

反例:接口方法定義:public abstract void f();

說明:JDK8中接口允許有默認實現,那麽這個default方法,是對所有實現類都有價值的默認實現。

10.接口和實現類的命名有兩套規則:

1) 【強制】對於Service和DAO類,基於SOA的理念,暴露出來的服務一定是接口,內部的實現類用Impl的後綴與接口區別。

正例:CacheServiceImpl實現CacheService接口。

2) 【推薦】 如果是形容能力的接口名稱,取對應的形容詞做接口名(通常是–able的形式)。

正例:AbstractTranslator實現 Translatable。

11. 【參考】枚舉類名建議帶上Enum後綴,枚舉成員名稱需要全大寫,單詞間用下劃線隔開。

說明:枚舉其實就是特殊的常量類,且構造方法被默認強制是私有。

正例:枚舉名字:DealStatusEnum;成員名稱:SUCCESS / UNKOWN_REASON。

12.【參考】各層命名規約:

A) Service/DAO層方法命名規約

1) 獲取單個對象的方法用get做前綴。

2) 獲取多個對象的方法用list做前綴。

3) 獲取統計值的方法用count做前綴。

4) 插入的方法用save(推薦)或insert做前綴。

5) 刪除的方法用remove(推薦)或delete做前綴。

6) 修改的方法用update做前綴。

B) 領域模型命名規約

1) 數據對象:xxxDO,xxx即為數據表名。

2) 數據傳輸對象:xxxDTO,xxx為業務領域相關的名稱。

3) 展示對象:xxxVO,xxx一般為網頁名稱。

4) POJO是DO/DTO/BO/VO的統稱,禁止命名成xxxPOJO。

13.【強制】long或者Long初始賦值時,必須使用大寫的L,不能是小寫的l,小寫容易跟數字1 混淆,造成誤解。

說明:Longa = 2l; 寫的是數字的21,還是Long型的2?

二、格式規約(重要)

1. 【強制】大括號的使用約定。如果是大括號內為空,則簡潔地寫成{}即可,不需要換行;如果是非空代碼塊則:

1) 左大括號前不換行。

2) 左大括號後換行。

3) 右大括號前換行。

4) 右大括號後還有else等代碼則不換行;表示終止右大括號後必須換行。

2. 【強制】 左括號和後一個字符之間不出現空格;同樣,右括號和前一個字符之間也不出現空格。詳見第5條下方正例提示。

3. 【強制】if/for/while/switch/do等保留字與左右括號之間都必須加空格。

4. 【強制】任何運算符左右必須加一個空格。

說明:運算符包括賦值運算符=、邏輯運算符&&、加減乘除符號、三目運行符等。

5. 【強制】代碼塊縮進4個空格,如果使用tab縮進,請設置成1個tab為4個空格。

6.【強制】單行字符數限制不超過120個,超出需要換行,換行時,遵循如下原則:

1) 換行時相對上一行縮進4個空格。

2) 運算符與下文一起換行。

3) 方法調用的點符號與下文一起換行。

4) 在多個參數超長,逗號後進行換行。

5) 在括號前不要換行,見反例。正例:

StringBuffer sb = new StringBuffer();

//超過120個字符的情況下,換行縮進4個空格,並且方法前的點符號一起換行 sb.append("zi").append("xin")…

.append("huang");

反例:
StringBuffer sb = new StringBuffer();

//超過120個字符的情況下,不要在括號前換行

sb.append("zi").append("xin")…append

("huang");

//參數很多的方法調用也超過120個字符,逗號後才是換行處 method(args1,args2, args3, ...

, argsX);

7. 【強制】方法參數在定義和傳入時,多個參數逗號後邊必須加空格。

正例:下例中實參的"a",後邊必須要有一個空格。

method("a", "b","c");

8. 【推薦】沒有必要增加若幹空格來使某一行的字符與上一行的相應字符對齊。

正例:

  1. int a = 3;
  2. long b = 4L;
  3. float c = 5F;
  4. StringBuffer sb = new StringBuffer();


說明:增加sb這個變量,如果需要對齊,則給a、b、c都要增加幾個空格,在變量比較多的情況下,是一種累贅的事情。

三、OOP規約

1. 【強制】避免通過一個類的對象引用訪問此類的靜態變量或靜態方法,無謂增加編譯器解析成本,直接用類名來訪問即可。

2. 【強制】所有的覆寫方法,必須加@Override註解。

反例:getObject()與get0bject()的問題。一個是字母的O,一個是數字的0,加@Override可以準確判斷是否覆蓋成功。另外,如果在抽象類中對方法簽名進行修改,其實現類會馬上編譯報錯。

3. 【強制】相同參數類型,相同業務含義,才可以使用Java的可變參數,避免使用Object。

說明:可變參數必須放置在參數列表的最後。(提倡同學們盡量不用可變參數編程)

正例:public User getUsers(Stringtype, Integer... ids);

4.【強制】所有的相同類型的包裝類對象之間值的比較,全部使用equals方法比較。

說明:對於Integer var=?在-128至127之間的賦值,Integer對象是在IntegerCache.cache 產生,會復用已有對象,這個區間內的Integer值可以直接使用==進行判斷,但是這個區間之外的所有數據,都會在堆上產生,並不會復用已有對象,這是一個大坑,推薦使用equals方法進行判斷。

5.【強制】關於基本數據類型與包裝數據類型的使用標準如下:

1) 所有的POJO類屬性必須使用包裝數據類型。

2) RPC方法的返回值和參數必須使用包裝數據類型。

3) 所有的局部變量推薦使用基本數據類型。

6.【強制】定義DO/DTO/VO等POJO類時,不要設定任何屬性默認值。

反例:某業務的DO的gmtCreate默認值為newDate();但是這個屬性在數據提取時並沒有置入具體值,在更新其它字段時又附帶更新了此字段,導致創建時間被修改成當前時間。

7.【強制】構造方法裏面禁止加入任何業務邏輯,如果有初始化邏輯,請放在init方法中。

8.【推薦】使用索引訪問用String的split方法得到的數組時,需做最後一個分隔符後有無內容的檢查,否則會有拋IndexOutOfBoundsException的風險。

  1. String str = "a,b,c,,"; String[] ary =str.split(",");
  2. //預期大於3,結果是3
  3. System.out.println(ary.length);

9.【推薦】類成員與方法訪問控制從嚴:

1) 如果不允許外部直接通過new來創建對象,那麽構造方法必須是private。
2) 工具類不允許有public或default構造方法。
3) 類非static成員變量並且與子類共享,必須是protected。
4) 類非static成員變量並且僅在本類使用,必須是private。
5) 類static成員變量如果僅在本類使用,必須是private。
6) 若是static成員變量,必須考慮是否為final。
7) 類成員方法只供類內部調用,必須是private。
8) 類成員方法只對繼承類公開,那麽限制為protected。

四、集合處理

1. 【強制】Map/Set的key為自定義對象時,必須重寫hashCode和equals。

正例:String重寫了hashCode和equals方法,所以我們可以非常愉快地使用String對象作為key來使用。

2.【推薦】集合初始化時,盡量指定集合初始值大小。說明:ArrayList盡量使用ArrayList(int initialCapacity) 初始化。

3.【推薦】使用entrySet遍歷Map類集合KV,而不是keySet方式進行遍歷。

說明:keySet其實是遍歷了2次,一次是轉為Iterator對象,另一次是從hashMap中取出key 所對應的value。而entrySet只是遍歷了一次就把key和value都放到了entry中,效率更高。如果是JDK8,使用Map.foreach方法。

正例:values()返回的是V值集合,是一個list集合對象;keySet()返回的是K值集合,是一個Set集合對象;entrySet()返回的是K-V值組合集合。

4.【推薦】高度註意Map類集合K/V能不能存儲null值的情況,如下表格:

技術分享圖片

五、並發處理

1.【強制】SimpleDateFormat 是線程不安全的類,一般不要定義為static變量,如果定義為 static,必須加鎖,或者使用DateUtils工具類。

正例:註意線程安全,使用DateUtils。亦推薦如下處理:

  1. private static final ThreadLocal<DateFormat> df =new ThreadLocal<DateFormat>() {
  2. @Override
  3. protected DateFormat initialValue(){
  4. return newSimpleDateFormat("yyyy-MM-dd");
  5. }
  6. };

說明:如果是JDK8的應用,可以使用instant代替Date,Localdatetime代替Calendar,

Datetimeformatter代替Simpledateformatter,官方給出的解釋:simple beautifulstrong immutable thread-safe。

2.【強制】並發修改同一記錄時,避免更新丟失,要麽在應用層加鎖,要麽在緩存加鎖,要麽在數據庫層使用樂觀鎖,使用version作為更新依據。說明:如果每次訪問沖突概率小於20%,推薦使用樂觀鎖,否則使用悲觀鎖。樂觀鎖的重試次數不得小於3次。

3.【強制】線程池不允許使用Executors去創建,而是通過ThreadPoolExecutor的方式,這樣的處理方式讓寫的同學更加明確線程池的運行規則,規避資源耗盡的風險。

說明:Executors各個方法的弊端:

1) newFixedThreadPool和newSingleThreadExecutor: 主要問題是堆積的請求處理隊列可能會耗費非常大的內存,甚至OOM。

2) newCachedThreadPool和newScheduledThreadPool: 主要問題是線程數最大數是Integer.MAX_VALUE,可能會創建數量非常多的線程,甚至OOM。

4.【強制】創建線程或線程池時請指定有意義的線程名稱,方便出錯時回溯。

正例:
public class TimerTaskThread extends Thread{ publicTimerTaskThread(){ super.setName("TimerTaskThread"); …

}
5.【推薦】使用CountDownLatch進行異步轉同步操作,每個線程退出前必須調用countDown方法,線程執行代碼註意catch異常,確保countDown方法可以執行,避免主線程無法執行至 countDown方法,直到超時才返回結果。說明:註意,子線程拋出異常堆棧,不能在主線程try-catch到。

6.【參考】ThreadLocal無法解決共享對象的更新問題,ThreadLocal對象建議使用static修飾。這個變量是針對一個線程內所有操作共有的,所以設置為靜態變量,所有此類實例共享此靜態變量 ,也就是說在類第一次被使用時裝載,只分配一塊存儲空間,所有此類的對象(只要是這個線程內定義的)都可以操控這個變量。

7.【參考】volatile解決多線程內存不可見問題。對於一寫多讀,是可以解決變量同步問題,但是如果多寫,同樣無法解決線程安全問題。如果想取回count++數據,使用如下類實現:

AtomicIntegercount = new AtomicInteger(); count.addAndGet(1); count++操作如果是

JDK8,推薦使用LongAdder對象,比AtomicLong性能更好(減少樂觀鎖的重試次數)。

六、控制語句

1.【強制】在一個switch塊內,每個case要麽通過break/return來終止,要麽註釋說明程序將繼續執行到哪一個case為止;在一個switch塊內,都必須包含一個default語句並且放在最後,即使它什麽代碼也沒有。

2.強制】在if/else/for/while/do語句中必須使用大括號,即使只有一行代碼,避免使用下面的形式:if (condition) statements;

3.【推薦】循環體中的語句要考量性能,以下操作盡量移至循環體外處理,如定義對象、變量、

獲取數據庫連接,進行不必要的try-catch操作(這個try-catch是否可以移至循環體外)。

七、註釋規約

1.【強制】類、類屬性、類方法的註釋必須使用javadoc規範,使用/**內容*/格式

2.【強制】所有的抽象方法(包括接口中的方法)必須要用javadoc註釋、除了返回值、參數、異常說明外,還必須指出該方法做什麽事情,實現什麽功能。

3.【強制】方法內部單行註釋,在被註釋語句上方另起一行,使用//註釋。方法內部多行註釋使用/* */註釋,註意與代碼對齊。

八、異常處理

1.【強制】不要捕獲Java類庫中定義的繼承自RuntimeException的運行時異常類,如:

IndexOutOfBoundsException/ NullPointerException,這類異常由程序員預檢查來規避,保證程序健壯性。

正例:if(obj != null) {...}

反例:try { obj.method() }catch(NullPointerException e){…}

2.【強制】對大段代碼進行try-catch,這是不負責任的表現。catch時請分清穩定代碼和非穩定代碼,穩定代碼指的是無論如何不會出錯的代碼。對於非穩定代碼的catch盡可能進行區分異常類型,再做對應的異常處理。

3.【強制】不能在finally塊中使用return,finally塊中的return返回後方法結束執行,不會再執行try塊中的return語句。

九、日誌規約

1. 【強制】應用中不可直接使用日誌系統(Log4j、Logback)中的API,而應依賴使用日誌框架
SLF4J中的API,使用門面模式的日誌框架,有利於維護和各個類的日誌處理方式統一。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger logger =LoggerFactory.getLogger(Abc.class);

2. 【強制】日誌文件推薦至少保存15天,因為有些異常具備以“周”為頻次發生的特點。

3. 【強制】應用中的擴展日誌(如打點、臨時監控、訪問日誌等)命名方式:
appName_logType_logName.log。logType:日誌類型,推薦分類有stats/desc/monitor/visit 等;logName:日誌描述。這種命名的好處:通過文件名就可知道日誌文件屬於什麽應用,什麽類型,什麽目的,也有利於歸類查找。
正例:mppserver應用中單獨監控時區轉換異常,如: mppserver_monitor_timeZoneConvert.log
說明:推薦對日誌進行分類,錯誤日誌和業務日誌盡量分開存放,便於開發人員查看,也便於通過日誌對系統進行及時監控。

4. 【強制】對trace/debug/info級別的日誌輸出,必須使用條件輸出形式或者使用占位符的方式。
說明:logger.debug("Processingtrade with id: " + id + " symbol: " + symbol); 如果日誌級別是warn,上述日誌不會打印,但是會執行字符串拼接操作,如果symbol是對象,會執行toString()方法,浪費了系統資源,執行了上述操作,最終日誌卻沒有打印。
正例:(條件)
if (logger.isDebugEnabled()) {
logger.debug("Processing trade with id: " +id + " symbol: " + symbol);
}
正例:(占位符)
logger.debug("Processing trade with id: {} andsymbol : {} ", id, symbol);

5. 【強制】避免重復打印日誌,浪費磁盤空間,務必在log4j.xml中設置additivity=false。
正例:<loggername="com.taobao.ecrm.member.config" additivity="false">

6. 【強制】異常信息應該包括兩類信息:案發現場信息和異常堆棧信息。如果不處理,那麽往上拋。
正例:logger.error(各類參數或者對象toString +"_" + e.getMessage(), e);

7. 輸出的POJO類必須重寫toString方法,否則只輸出此對象的hashCode值(地址值),沒啥參考意義。

十、MYSQL建表規約

1. 【強制】表達是與否概念的字段,必須使用is_xxx的方式命名,數據類型是unsigned tinyint
( 1表示是,0表示否),此規則同樣適用於odps建表。
說明:任何字段如果為非負數,必須是unsigned。

2. 【強制】表名、字段名必須使用小寫字母或數字;禁止出現數字開頭,禁止兩個下劃線中間只出現數字。數據庫字段名的修改代價很大,因為無法進行預發布,所以字段名稱需要慎重考慮。
正例:getter_admin,task_config,level3_name 反例:GetterAdmin,taskConfig,level_3_name

3. 【強制】表名不使用復數名詞。
說明:表名應該僅僅表示表裏面的實體內容,不應該表示實體數量,對應於DO類名也是單數形式,符合表達習慣。

4. 【強制】禁用保留字,如desc、range、match、delayed等,參考官方保留字。

5. 【強制】唯一索引名為uk_字段名;普通索引名則為idx_字段名。
說明:uk_即 unique key;idx_ 即index的簡稱。

6. 【強制】小數類型為decimal,禁止使用float和double。
說明:float和double在存儲的時候,存在精度損失的問題,很可能在值的比較時,得到不
正確的結果。如果存儲的數據範圍超過decimal的範圍,建議將數據拆成整數和小數分開存儲。

7. 【強制】如果存儲的字符串長度幾乎相等,使用CHAR定長字符串類型。

8. 【強制】varchar是可變長字符串,不預先分配存儲空間,長度不要超過5000,如果存儲長度大於此值,定義字段類型為TEXT,獨立出來一張表,用主鍵來對應,避免影響其它字段索引效率。

9. 【強制】表必備三字段:id, gmt_create, gmt_modified。
說明:其中id必為主鍵,類型為unsigned bigint、單表時自增、步長為1;分表時改為從
TDDL Sequence取值,確保分表之間的全局唯一。gmt_create,gmt_modified的類型均為 date_time類型。

10.【推薦】表的命名最好是加上“業務名稱_表的作用”,避免上雲梯後,再與其它業務表關聯時有混淆。
正例:tiger_task/ tiger_reader / mpp_config

十一、MYSQL索引規約

1. 【強制】業務上具有唯一特性的字段,即使是組合字段,也必須建成唯一索引。

說明:不要以為唯一索引影響了insert速度,這個速度損耗可以忽略,但提高查找速度是明顯的;另外,即使在應用層做了非常完善的校驗和控制,只要沒有唯一索引,根據墨菲定律,必然有臟數據產生。

2. 【強制】超過三個表禁止join。需要join的字段,數據類型保持絕對一致;多表關聯查詢時,保證被關聯的字段需要有索引。

說明:即使雙表join也要註意表索引、SQL性能。

3. 【強制】在varchar字段上建立索引時,必須指定索引長度,沒必要對全字段建立索引,根據實際文本區分度決定索引長度。

說明:索引的長度與區分度是一對矛盾體,一般對字符串類型數據,長度為20的索引,區分度會高達90%以上,可以使用count(distinct left(列名, 索引長度))/count(*)的區分度來確定。

4. 【強制】頁面搜索嚴禁左模糊或者全模糊,如果需要請走搜索引擎來解決。

說明:索引文件具有B-Tree的最左前綴匹配特性,如果左邊的值未確定,那麽無法使用此索引。

5. 【推薦】如果有order by的場景,請註意利用索引的有序性。order by 最後的字段是組合索引的一部分,並且放在索引組合順序的最後,避免出現file_sort的情況,影響查詢性能。

正例:where a=? and b=? order by c; 索引:a_b_c

反例:索引中有範圍查找,那麽索引有序性無法利用,如:WHERE a>10 ORDER BY b; 索引a_b 無法排序。

十二、MYSQL的SQL規約

1. 【強制】不要使用count(列名)來替代count(*),count(*)就是SQL92定義的標準統計行數的語法,跟數據庫無關,跟NULL和非NULL無關。

說明:count(*)會統計值為NULL的行,而count(列名)不會統計此列全為NULL值的行。

技術分享圖片

輸入:

select COUNT(*) from wms_record_in

output:3

輸入:

select COUNT(1) from wms_record_in

output:3

輸入:

select COUNT(RECORD_NUMBER) from wms_record_in

output:0

2. 【強制】count(distinct col) 計算該列除NULL之外的不重復數量。註意 count(distinct col1, col2) 如果其中一列全為NULL,那麽即使另一列有不同的值,也返回為0。


3. 【強制】當某一列的值全是NULL時,count(col)的返回結果為0,但sum(col)的返回結果為

NULL,因此使用sum()時需註意NPE問題。

正例:可以使用如下方式來避免sum的NPE問題:SELECTIF(ISNULL(SUM(g)),0,SUM(g)) FROM table;


4. 【強制】使用ISNULL()來判斷是否為NULL值。註意:NULL與任何值的直接比較都為NULL。

說明:
1) NULL<>NULL的返回結果是NULL,不是false。

2) NULL=NULL的返回結果是NULL,不是true。

3) NULL<>1的返回結果是NULL,而不是true。

5. 【強制】在代碼中寫分頁查詢邏輯時,若count為0應直接返回,避免執行後面的分頁語句。

6. 【強制】不得使用外鍵與級聯,一切外鍵概念必須在應用層解決。

說明:(概念解釋)學生表中的student_id是主鍵,那麽成績表中的student_id則為外鍵。

如果更新學生表中的student_id,同時觸發成績表中的student_id更新,則為級聯更新。外鍵與級聯更新適用於單機低並發,不適合分布式、高並發集群;級聯更新是強阻塞,存在數據庫更新風暴的風險;外鍵影響數據庫的插入速度。

7. 【強制】禁止使用存儲過程,存儲過程難以調試和擴展,更沒有移植性。

8. 【強制】IDB數據訂正時,刪除和修改記錄時,要先select,避免出現誤刪除,確認無誤才能提交執行。

9. 【推薦】in操作能避免則避免,若實在避免不了,需要仔細評估in後邊的集合元素數量,控制在1000個之內。

10.【參考】因阿裏巴巴全球化需要,所有的字符存儲與表示,均以utf-8編碼,那麽字符計數方法註意:

說明:
SELECT LENGTH("阿裏巴巴"); 返回為12

SELECT CHARACTER_LENGTH("阿裏巴巴"); 返回為4

如果要使用表情,那麽使用utfmb4來進行存儲,註意它與utf-8編碼。

11.【參考】TRUNCATE TABLE 比 DELETE 速度快,且使用的系統和事務日誌資源少,但TRUNCATE 無事務且不觸發trigger,有可能造成事故,故不建議在開發代碼中使用此語句。

說明:TRUNCATETABLE 在功能上與不帶 WHERE 子句的 DELETE 語句相同。

十三、MYSQL的ORM規約

1. 【強制】在表查詢中,一律不要使用 * 作為查詢的字段列表,需要哪些字段必須明確寫明。

說明:1)增加查詢分析器解析成本。2)增減字段容易與resultMap配置不一致。

2. 【強制】POJO類的boolean屬性不能加is,而數據庫字段必須加is_,要求在resultMap中進行字段與屬性之間的映射。

說明:參見定義POJO類以及數據庫字段定義規定,在sql.xml增加映射,是必須的。

3. 【強制】不要用resultClass當返回參數,即使所有類屬性名與數據庫字段一一對應,也需要定義;反過來,每一個表也必然有一個與之對應。

說明:配置映射關系,使字段與DO類解耦,方便維護。

4. 【強制】xml配置中參數註意使用:#{},#param#不要使用${} 此種方式容易出現SQL註入。

5. 【強制】iBATIS自帶的queryForList(StringstatementName,int start,int size)不推薦使用。

說明:其實現方式是在數據庫取到statementName對應的SQL語句的所有記錄,再通過subList 取start,size的子集合,線上因為這個原因曾經出現過OOM。

正例:在sqlmap.xml中引入 #start#, #size#

Map<String, Object> map = new HashMap<String,Object>(); map.put("start",start); map.put("size", size);

6. 【強制】不允許直接拿HashMap與HashTable作為查詢結果集的輸出。

反例:某同學為避免寫一個<resultMap>,直接使用HashTable來接收數據庫返回結果,結果出現日常是把bigint轉成Long值,而線上由於數據庫版本不一樣,解析成BigInteger,導致線上問題。

7. 【強制】更新數據表記錄時,必須同時更新記錄對應的gmt_modified字段值為當前時間。

8. 【推薦】不要寫一個大而全的數據更新接口,傳入為POJO類,不管是不是自己的目標更新字段,都進行update table set c1=value1,c2=value2,c3=value3; 這是不對的。執行SQL時,盡量不要更新無改動的字段,一是易出錯;二是效率低;三是binlog增加存儲。

9. 【參考】@Transactional事務不要濫用。事務會影響數據庫的QPS,另外使用事務的地方需要考慮各方面的回滾方案,包括緩存回滾、搜索引擎回滾、消息補償、統計修正等。

10.【參考】<isEqual>中的compareValue是與屬性值對比的常量,一般是數字,表示相等時帶上此條件;<isNotEmpty>表示不為空且不為null時執行;<isNotNull>表示不為null值時執行。《代碼規範來自https://blog.csdn.net/cheidou123/article/details/79996463》

倉庫鏈接:https://gitee.com/XMHbb/software_engineering

課堂練習 Word count