CloudJavaBackendSummaries
1、開發環境eclipse工程,引入jw倉庫的jw-base,3-base,3-common工程,引入cw倉庫的自己的工程,以及cw倉dto庫中31開頭工程,方Concurrent便調試(因為現在機器配置較低,建議刪除McAfee,停掉其他殺毒軟件,和防火墻)
啟動jvm,增加參數,-Dlog4j.home=D:/sqlCmd,其中"log4j.home"配置自己機器路徑
2、每個功能操作必須對應一個API,不能復用(比如,刪除單條,批量刪除),A層每個功能一定要拆開。
ps:增加了Controller方法操作所對應系統功能code注解@OperFunCode(funCode="xxx-xxx-001")
3、除了包名、工程名、A層controller類的RequestMapping之外,不要用工程名命名任何東西。
ps:A層controller類的URL命名,參照如下/bs/3510010/GrpCrmProfile
刪除無用A層方法,及其后續P層、I層、D層代碼生成的方法!!!
4、xdo.cfg文件在啟動時候生成,會根據當前工程位置生成,因此不要上傳
4、清除暫時不用的代碼,只刪除代碼生成的,如果有在代碼生成后,修改有用信息的,均不刪除ps:要記得修改相應的P層和A層的配置文件
5、entity實體生成后,根據業務需要修改其繼承父實現類、以及實現的接口類。目前提供的接口類匯總如下:
BaseEntity:CreatedBy\CreatedByUid\CreatedByCD\CreatedDateBaseEntityWithUnit:CreatedBy\CreatedByUid\CreatedByCd\CreatedDate\CreatedUnitUid\CreatedUnitCdBusinessBaseEntity:CreatedBy\CreatedByUid\CreatedByCd\CreatedDate\ModifiedBy\ModifiedByUid\ModifiedByCd\ModifiedDateBusinessBaseEntityWithUnit:CreatedBy\CreatedByUid\CreatedByCd\CreatedDate\CreatedUnitUid\CreatedUnitCd\ModifiedBy\ModifiedByUid\ModifiedByCd\ModifiedDate\ModifiedUnitUid\ModifiedUnitCdChainUidEntity:ChainUidDomainObject:id\versionOucdEntity:UnitUidOuPoscdEntity:UnitUidPos
6、Junit至少覆蓋增刪改查,盡量提高I層和P層核心代碼的覆蓋率,另外,需把測試的json實例,寫個txt文件放在測試類同級目錄中。
編寫ConcurrentTest,測試一下并發情況【尤其是自己寫的核心業務】
7、公共靜態枚舉,統一使用com.jw.base.framework.core.Constant,目前包含如下:
狀態枚舉 0:無效 1:有效(默認)休眠標識 0:正常(默認) 1:休眠保密標識 0:不保密(默認) 1:保密性別 0:男(默認) 1:女 2:未知默認標志 0:非默認 1:默認常用標志 0:非常用(默認) 1:常用聯系方式類型 0:電話,1:QQ,2:EMAIL,3:微信建立方式 1:酒店 2:網站 3:線下會員系統 4:CRS
null標識:1:null 0:not null
寫枚舉時,枚舉類型,及其包含屬性必須編寫相應注釋;根據需要設置default值(若有必要)或拋出異常;要有isEquals方法、以及getEnumConsNm【switch case用】
靜態變量定義要功能閉包。
8、小數數字entity統一用java.math.BigDecimal,整數統一用Integer,字符統一用String,日期統一用java.util.Date
ps:不要用com.ibm.icu.math.BigDecimal,要用java.math.BigDecimal
9、所有的相同類型的包裝類對象之間值的比較,全部使用 equals 方法比較。說明: 對于Integer var = ?在-128至127之間的賦值,Integer對象是在 IntegerCache.cache 產生,會復用已有對象,這個區間內的 Integer 值可以直接使用==進行 判斷,但是這個區間之外的所有數據,都會在堆上產生,并不會復用已有對象,這是一個大坑, 推薦使用 equals 方法進行判斷。
10、entity的@Column中nullable = false或true,要和數據庫保持一致(數據庫變更要通知開發人員)
11、注意變量名的拼寫(部分單詞中某些字符前后顛倒)
12、新增方法,I層需統一設置默認值,不能依賴前端傳值(如是否休眠、是否有效、是否黑名單)
13、注意不要忽略A層validator的校驗,要寫全面完整
ps:ValidConstant,命名統一按照:VALID_ + 模塊英文名稱(表名) + 序號(2位:類型(1非空、2長度) + 3位:流水號)
例如:
/** 作廢日期為空 /public static final String VALID_GRPCRMCORPCONTRACT_001 = "VALID_GRPCRMCORPCONTRACT_001";/* 作廢原因為空 /public static final String VALID_GRPCRMCORPCONTRACT_002 = "VALID_GRPCRMCORPCONTRACT_002";/* 所屬單位不可為空 /public static final String VALID_GRPCRMCORPCONTRACT_003 = "VALID_GRPCRMCORPCONTRACT_003";/* 開始日期不可大于結束日期 /public static final String VALID_GRPCRMCORPCONTRACT_004 = "VALID_GRPCRMCORPCONTRACT_004";/* 合同類型不可為空 */public static final String VALID_GRPCRMCORPCONTRACT_005 = "VALID_GRPCRMCORPCONTRACT_005";
14、3105001工程中ValidConstant、LogConstant按照業務分包放
15、對象復制不使用BeanUtil.copyPropertiesExceptNull,統一使用entity中copyentity方法
16、dto中不再用現成的entity做定義,用新定義的dto(結合頁面元素),新增模塊package
dto的子包,包名要全部小寫,不要已大寫字母開頭命名
17、所有sql語句select列表,默認order by 自增主鍵
18、帶條件和排序查詢,統一使用增強的enhanceQueryListByProerties方法,暫不允許使用批量更新方法,批量更新業務實現,需先enhanceGet,再逐條保存
19、日期查詢sql統一使用如下方式:(禁止在where條件屬性中使用函數)
select cast(字段 as timestamp) from where cast('2015-10-12 12:02:45' as timestamp) <= 字段;統一使用DateUtil.DATE_TIME_FORMAT(yyyy-MM-dd HH:mm:ss,大寫HH代表24小時制)

20、悲觀鎖統一使用lock類鎖表,各個業務實現自己的鎖表類
Map<String,String> paramMap = new HashMap<String, String>();paramMap.put(BsSysUser.class.getName(), bsSysUserRequestFormDto.getSubmitData().getId().toString());lockProvider.lock(paramMap); 鎖表用法
21、改子表,保存后,更新主表version表
22、DTO中每條業務記錄都需帶著“操作標示”(統一放在entity的subdto中)
23、要優先使用目前提供的工具類
StringUtil:isnull、isnotnull、spilt
集合工具統一用import org.apache.commons.collections4.CollectionUtils;
24、新增修改需為兩個方法,不能復用一個
25、統一用CodeBean.java返回給前端key + code + name
26、checkbox類似數組存儲,不用逗號隔開,用統一的子表(多項表)
27、ResponseFormDto返回結果數據中統一叫resultData
28、要使spring中校驗生效,需增加調用doValidator

29、A層@OperSysType注解,暫不用打,不用注解該方法調用哪個數據源;【考慮到以后校驗,可能以后會打,統一再重構】
S層增加@OperSysType注解,說明本方法提供對應數據源類型;S層@OperSysType注解,增加屬性isSlave,默認false,切換為主庫,如果為true,切換從庫PCM標示切換到PCM庫,HPT標示根據操作酒店對應數據庫切換、GRP標示根據當前集團對應數據庫切換ps:目前dto中專了sourceNm,以sourceNm切,優先級最高;第二優先級為S層上的注解,第三優先級為A層注解(A層注解咱不用打)
30、A層@DrptAPI注解中增加屬性listParam,dtoResponse,如下:
@DrptAPI(infnm="列表獲取數據",infdrpt="列表獲取數據",dtoParam="BsSysUserQueryDto",dtoResponse="com.jw.common.framework.m0002.f001.dto.DataTableDto",listParam="id,staff_id,staff_code,user_name,user_name_en,login_account,modified_date,pwd,created_date,language_type")@DrptAPI(infnm="根據ID獲取詳細信息",infdrpt="根據ID獲取詳細信息",dtoParam="IdRequestDto",dtoResponse="com.jw.hms.example.m31xx.f001.dto.BsSysUserResponseFormDto")
31、@DrptAPI注解必須書寫全參數@DrptAPI(infnm="列表獲取數據",infdrpt="列表獲取數據",dtoParam="GrpRolePermissionQueryDto",dtoResponse="com.jw.common.framework.m0002.f001.dto.DataTableDto",listParam="...")
32、共同參數統一調用CmmParameterProvider中的如下方法
獲取數據字典List(過濾后的字典集合)public DictionaryResponseDto querylistDictionaryList(DictionaryQueryDto dictQueryDto) throws Exception獲取數據字典key對應的描述(單條描述)public DictionaryResponseDto querylistDictDescription(DictionaryQueryDto dictQueryDto) throws Exception
P層遠程調用P層,所有調用查參數統一用:字典表獲取 PlfCmmParameterServiceImpl.queryListToDictionary
ps:PSM庫沒有參數表
33、列表查詢方法(P層)統一使用queryList開頭、查復雜記錄方法(P層)統一使用queryIds開頭、查報表方法(P層)統一使用queryReport開頭。
34、查詢sql,當前操作酒店條件,統一使用ShareSession.getSessionUnitUid_EXCU。
35、sql的like查詢,要根據業務需要,增加前后百分號;in用List,order by多個用List;
36、PMS和餐飲的entity需implements OucdEntity,字段可以任意起名,但需在成員變量上打上如下注解@FieldUnitcd(systyp=Constant.SYS_TYP_PMS),并實現getUnitUidOu(),和setUnitUidOu方法。A層給RequestCommonDto中的UnitUid賦值,P層新增要增加@CheckUnitcd(systyp=Constant.SYS_TYP_PMS)。
37、CRM和GROUP中,前臺需要選擇酒店,錄入新增記錄場景,其對應entity需implements PoscdEntity,字段可以任意起名,但需在成員變量上打上如下注解@FieldUnitcd(systyp=Constant.SYS_TYP_GRP),并實現getUnitUidPos(),和setUnitUidPos方法
系統會只在保存時,給其賦值,賦值來源ShareSession.getSessionUnitUid_EXCU(),該值由A層初始化賦值中獲取(RequestCommonDto中的UnitUid)--dto.getRequestCommonDto().setUnitUid("xxxxxxxxx");P層之前的AuthorityFilter,會將RequestCommonDto中的UnitUid,set到threadlocal中。統一的CheckUnitcdAdvice攔截進行同登錄人能操作酒店進行校驗P層僅僅新增要增加@CheckUnitcd(systyp=Constant.SYS_TYP_GRP
38、查詢列表頁面,傳入查詢條件的dto,不建議是個通用的map,并且要做必要的spring @Valid
39、用@Deprecated注釋的程序元素,不鼓勵程序員使用這樣的元素,通常是因為它很危險或存在更好的選擇。在使用不被贊成的程序元素或在不被贊成的代碼中執行重寫時,編譯器會發出警告。
java.lang.Deprectated是J2SE 5.0中標準的Annotation型態之一,它對編譯器說明某個方法已經不建議使用,如果有人試圖使用或重新定義該方法,必須提出警示訊息。
40、檢查建的表,應該沒有默認值,并且可以為空字段應為DEFAULT NULL
41、前端聯調機器192.168.18.35(Administrator\123456),把在本機開發環境maven install的R和RA工程的target下的war包放到相應webapp下重啟服務
ps:35部署記得清緩存,D:\java\apache-tomcat-8.5.4\work
ps:R和RA工程必須,clean + install,這樣其.war包才是最新的
42、代碼注釋原則:凡同示例代碼不同邏輯,均需編寫必要代碼注釋做相應說明(方法說明,應寫明業務,不能僅僅些表名英文)
43、無用的老代碼,不要保留,建議全部刪掉(git上會有版本,可以找回),尤其注意功能調整變化造成的已無用的代碼
44、@DrptController、@DrptAPI、@DrptField等接口自定義系統注解,要增加必要業務說明
ps:dto注解DrptField增加屬性nullable、length、precision,并且其中fieldnm放字段英文名
45、A層@Log注解中的logCD,應用對應靜態類靜態變量進行賦值
46、A層Controller中try\catch捕獲異常處理類中增加請求dto參數,供log4j日志記錄用(bug調試用)
ExceptionTools.handleException(exception, dto, this.getRequest(), this.getResponse());
47、>微服務層必須注解事務@Transactional,在get,is等讀操作微服務中必須@Transactional(readOnly = true),即從這一點設置的時間點開始(時間點a)到這個事務結束的過程中,其他事務所提交的數據,該事務將看不見(查詢中不會出現別人在時間點a之后提交的數據)(如果你一次執行單條查詢語句,則沒有必要啟用事務支持,數據庫默認支持SQL執行期間的讀一致性)
如果你一次執行多條查詢語句,例如統計查詢,報表查詢,在這種場景下,多條查詢SQL必須保證整體的讀一致性,否則,在前條SQL查詢之后,后條SQL查詢之前,數據被其他用戶改變,則該次整體的統計查詢將會出現讀數據不一致的狀態,此時,應該啟用事務支持。>@Transactional 只能被應用到public方法上, 對于其它非public的方法,如果標記了@Transactional也不會報錯,但方法沒有事務功能。>在具體的類(或類的方法)上使用 @Transactional 注解,而不要使用在類所要實現的任何接口上。>用 spring 事務管理器,由spring來負責數據庫的打開,提交,回滾.默認遇到運行期異常(throw new RuntimeException("注釋");)會回滾,即遇到不受檢查(unchecked)的異常時回滾;而遇到需要捕獲的異常(throw new Exception("注釋");)不會回滾,即遇到受檢查的異常(就是非運行時拋出的異常,編譯器會檢查到的異常叫受檢查例外或說受檢查異常)時,需我們指定方式來讓事務回滾 要想所有異常都回滾,要加上 @Transactional( rollbackFor={Exception.class,其它異常})
48、變量命名,不要以_開頭
49、盡量不要在字段中存入null值,null值可用-1替代,在oracle中,null跟''是一樣的,oracle都會理解為是null值;在mysql、PostgreSQL中,null與''是不相同的,''會插入一個空字符串
50、@SuppressWarnings。該批注的作用是給編譯器一條指令,告訴它對被批注的代碼元素內部的某些警告保持靜默。如:@SuppressWarnings("deprecation")表示不顯示使用了不贊成使用的類或方法時的警告。
51、注意各個業務RequestFormDto中getLogDiffer,要和界面保持一致,以便后面頁面還原使用(dto中getLogDiffer方法不能都給注釋掉,要按照頁面元素進行相應編碼)
52、dto中getLogDiffer方法,不要用@JsonIgnore注解,或@JsonIgnoreProperties,這兩個是jackson來處理json串轉換的問題的(有些時候我們經常有忽略某些屬性的情況),不是FastJson的,改用@JSONField(serialize=false),或用FastJson提供的各種filter機制來實現
53、不要用JsonUtil,改用FastJsonUtil,否則轉換整形會有小數點(Gson默認將int和long型數據轉換為double)
ps:fastjson解析json時報錯default constructor not found. class.
類需要有一個空的構造函數public JwMessage() {super();}
54、getLogDiffer中setPfieldvalue值,如果是Integet不要加.toString(),統一使用StringUtil.nullToEmpty方法處理,如下:改為:ib.setPfieldvalue(StringUtil.nullToEmpty(getOriginData().getSeq()));大家要根據代碼生成,根據不同類型,做相應處理
55、代碼注釋建議使用javadoc的/** xxxxxxxxx /,不用/ xxxxxxxxx / a、單選注釋:符號是:// b、塊注釋: 符號是: / / 可以跨多行 c、javadoc注釋: 符號是: / */ 可以跨多行, 生成javadoc時,這樣的注釋會被生成標準的javaapi注釋。
56、redis調用(批量、同時操作多個key值的)方法如mset、msetnx、mget、rename、renamenx、smove、sinter、sdiff、sunion、zunionstore、時,key值前面拼接上Constant.KEY_SLOTkeySlot算法中,如果key包含{},就會使用第一個{}內部的字符串作為hash key,這樣就可以保證擁有同樣{}內部字符串的key就會擁有相同slot。
57、G是帶泛型的,非G是非泛型的產品baseDAO實現:BaseProductJdbcDaoImpl.java(BaseProductJdbcDaoImpl 增加三個with語句拼接方法)BaseProductProvider原子服務接口:BaseProductGProvider.javaBaseProductProvider原子服務接口:BaseProductProvider.javaBaseProductService微服務接口:BaseProductGService.javaBaseProductService微服務接口:BaseProductService.javaBaseProductProviderImpl原子服務實現:BaseProductGProviderImpl.javaBaseProductProviderImpl原子服務實現:BaseProductProviderImpl.javaBaseProductServiceImpl微服務實現:BaseProductGServiceImpl.javaBaseProductServiceImpl微服務實現:BaseProductServiceImpl.java
58、D層DaoQueryMysqlImpl、DaoQueryOracleImpl、DaoQuerySqlServerImpl先刪掉,生成的不放到工程代碼中
59、修改為統一只用日志框架SLF4J中的API【門面模式的日志框架】,有利于維護各個類的日志處理方式
import org.slf4j.Logger;import org.slf4j.LoggerFactory;private static final Logger logger = LoggerFactory.getLogger(Abc.class);
60、對trace、debug、info級別的日志輸出,必須使用條件輸出形式或者使用占位符方式if(logger.isDebugEnabled()){logger.debug("Processing trade with id:"+id+",symbol:"+symbol);\條件輸出}或者logger.debug("Processing trade with id:{},symbol:{}", id, symbol);\占位符方式
61、log4j按照日志級別輸出(分包記錄,后續完善)${log4j.home}/log4j_31xx001R_info.log【請求的header信息 + requestbody信息 + tranceid鏈信息】${log4j.home}/log4j_31xx001R_error.log【controller捕獲返回給給前端的異常dot】另外,tomcat控制臺信息,查看apache-tomcat-8.5.4\logs下的catalina.*.log
62、金額、房間數、人數等放置默認值"0",字符串的根據業務需要放置默認值,不建議有值為null
63、接口自定義系統,包名注意,按照變化及時修改(dto)
64、dto和entity中,成員變量,均要運用駝峰命名法(處敏感信息外)
entity中Integer類型字段打上@Size注解 保存時會報 HV000030: No validator could be found for type: java.lang.Integer.這個錯誤,應該打@Max注解ps:一定注意String改為Integer時,要進行相應修改
65、所有GRP的表,應該createtype字段,統一在A層放值ps:檢查所有表,createtype字段是否建全
66、修改字段名、字段類型、字段長度等,建議全部工程Search一下,該字段名 + 字段名的駝峰命名,確認修改完整ps:如果涉及框架,要和劉博文溝通
67、單表新增不用鎖記錄,修改鎖當前記錄;主子表情況,子表新增或修改鎖主表,并且修改時鎖自身;
68、在做功能前查看一下,是否已有人對應相應業務表做了代碼生成(Ctrl+Shift+R)
69、發番統一獲取,在P層注入I層發番類@Resourceprivate CmmComIdProvider cmmComIdProvider;cmmComIdProvider.getNumberId(GrpCrmCorpConst.CONTRACT_NO_KZNO)其中GrpCrmCorpConst.CONTRACT_NO_KZNO,需在各自庫中cmm_number表中,配置相應發番規則
按照該《系統配置.xlsx》中發番配置,統一從com.jw.base.framework.core.Constant獲取發番類型
70、注入類,用@Resource,默認安照名稱進行裝配,名稱可以通過name屬性進行指定,變量名要與類名一致@Resourceprivate HptRsvRateCalendarService hptRsvRateCalendarService;
71、測試要記得清臟數據,如grp庫中createtyp中值為null,以前代碼問題造成的臟數據等
ps:貨幣統一用NUMERIC(16,4)
72、p層,RPC遠程調用其他P層(統一在R層配置,方便管理)

P層調用時要把commondto中屬性值賦值上,如sessionkey、token等
ps:
P層配置服務提供方接口

A層配置服務消費方接口【需要把RA工程的Eclipse中Jetty配置勾去“Compile Scope”,不影響開發的熱部署】
若RA工程的Eclipse中Jetty配置勾上“Compile Scope”,把A層工程target勾掉,并且把“spring-web”的jar包勾掉勾上的JRebel將監聽【monitored】classes文件的changes

73、對于大表,不要用hibernate查詢,用sql。Hibernate: select ... from XXX order by id desc limit ? offset ? 手拼SQL不用參數化: select ... from XXX order by id desc limit 30 offset 0 select里如果用參數,將極慢,如果直接拼到sql里,就快很多,差好幾個數量級
74、jdbc查詢sql,只能用于列表、報表,不允許使用在事務中(jdbc同hibernate不是一個鏈接)新提供了下面幾個org.hibernate.Session的方法public List<Map<?, ?>> findBySqlToMap(final String sql);【現有query方法做復雜查詢不方便時使用】public List<Map<?,?>> findBySqlToMap(final String sql, final Object[] params);【現有query方法做復雜查詢不方便時使用,也適用于有返回結果集的存儲過程或查詢語句】public Integer executeSql(final String sql);【只在select insert等特殊情況下用,此方法不能用于執行存儲過程】
拼寫select insert語句執行,也要參數化!!!!
75、queryListByProerties 修改比較值操作 List list = grpCrmProfileProvider.queryListByProerties(new String[] { "createdDate" }, new Object[] { new HsqlCompare(Constant.ENUM_COMPARE.Larger, Calendar.getInstance().getTime()) });傳入 new HsqlCompare(Constant.ENUM_COMPARE.Larger, Calendar.getInstance().getTime()) 對象
76、一個事務中,如業務需要一次性創建多對象,建議executeSql執行select insert語句,提高速度
77、使用各自賬戶進行測試
用戶名/密碼:admin/1 (單位代碼UNIT001,語種:中文){"chainCd":"CHAIIN001","unitCd":"UNIT001","systemInfo":"YWRtaW4sMQ==","dbType":"0","sysId":"GRP"}
用戶名/密碼:1/1 (單位代碼UNIT001,語種:中文){"chainCd":"CHAIIN001","unitCd":"UNIT001","systemInfo":"MSwx","dbType":"0","sysId":"GRP"}
用戶名/密碼:2/1 (單位代碼UNIT001,語種:中文){"chainCd":"CHAIIN001","unitCd":"UNIT001","systemInfo":"Miwx","dbType":"0","sysId":"GRP"}
用戶名/密碼:4/1 (單位代碼UNIT002,語種:英文){"chainCd":"CHAIIN001","unitCd":"UNIT002","systemInfo":"NCwx","dbType":"0","sysId":"GRP"}
用戶名/密碼:5/1 (單位代碼UNIT002,語種:英文){"chainCd":"CHAIIN001","unitCd":"UNIT002","systemInfo":"NSwx","dbType":"0","sysId":"GRP"}
用戶名/密碼:6/1 (單位代碼UNIT002,語種:英文){"chainCd":"CHAIIN001","unitCd":"UNIT002","systemInfo":"Niwx","dbType":"0","sysId":"GRP"}
用戶名/密碼:7/1 (單位代碼UNIT003,語種:日文){"chainCd":"CHAIIN001","unitCd":"UNIT003","systemInfo":"Nywx","dbType":"0","sysId":"GRP"}
用戶名/密碼:8/1 (單位代碼UNIT003,語種:日文){"chainCd":"CHAIIN001","unitCd":"UNIT003","systemInfo":"OCwx","dbType":"0","sysId":"GRP"}
用戶名/密碼:9/1 (單位代碼UNIT003,語種:日文){"chainCd":"CHAIIN001","unitCd":"UNIT003","systemInfo":"OSwx","dbType":"0","sysId":"GRP"}
78、字典表如下
共同參數:plf_cmm_parameter, plf_cmm_param_multilang(PCM、GRP、PMS)集團參數:cmm_base_param, cmm_base_param_multilang(PCM、GRP、PMS)酒店參數:cmm_unit_param, cmm_unit_param_multilang(PCM、GRP、PMS)pos參數: cmm_pos_param, cmm_pos_param_multilang(GRP、PMS)系統參數:plf_cmm_config, plf_cmm_config_multilang(PCM、GRP、PMS)
配合朱倩梳理現有參數表數據,梳理后會刪掉pcm庫和pms庫中10張參數表,后續需要增加參數數據,統一找朱倩,需要增加類型(修改EXCEL),統一找韓松
按照《業務-參數定義.xlsx》梳理共同參數、酒店集團參數等,調用參數類型統一修改為com.jw.base.framework.core.Constant中靜態變量ps:有之前部分共同參數修改為了參數、酒店集團參數
79、CountDownLatch和CyclicBarrier線程同步的輔助工具,通過它可以做到使一條線程一直阻塞等待,直到其他線程完成其所處理的任務。CountDownLatch:用給定的計數初始化CountDownLath。調用countDown()方法計數減 1,在計數被減到 0之前,調用await方法會一直阻塞。減為 0之后,則會迅速釋放所有阻塞等待的線程,并且調用await操作會立即返回。CyclicBarrier:用計數 N 初始化CyclicBarrier, 每調用一次await,線程阻塞,并且計數+1(計數起始是0),當計數增長到指定計數N時,所有阻塞線程會被喚醒。繼續調用await也將迅速返回。
CountDownLatch用法之一:初始化CountDownLatch startSwitch = new CountDownLatch(1),以及CountDownLatch stopSwitch = new CountDownLatch(groupNum),先在線程池中初始化要并行的線程,每個線程中startSwitch開關先阻塞,在主線程中startSwitch.countDown()(計數-1),開始所有線程池中線程(解鎖獲得資源),同時主線程stopSwitch.await()阻塞,每個線程池中線程完成各自工作后stopSwitch.countDown()計數器減一,最后一個子線程完成工作后,喚醒主線程繼續。CyclicBarrier用法之一:初始化CyclicBarrier startSwitch = new CyclicBarrier(groupNum + 1),以及CyclicBarrier stopSwitch = new CyclicBarrier(groupNum),先在線程池中初始化要并行的線程,每個線程中startSwitch開關先阻塞(計數+1),在主線程中startSwitch.await()(計數+1),開始所有線程池中線程(當計數增長到指定計數N時,所有阻塞線程會被喚醒),同時主線程service.shutdown(),在等待所有線程池中線程運行完成,每個線程池中線程完成各自工作后stopSwitch.await()阻塞(計數+1),最后一個子線程完成工作后,主線程service.shutdown()完成并繼續。
80、線程池創建至少是通過靜態成員變量方式,不能是局部成員變量,后續修改為通過ThreadPoolExecutor方式
81、框架提供了攔截器進行統一的限流 + 系統參數cfg.properties定時重新加載【訪問路徑計數是否大于限流值】
82、線程不安全的(和公共資源相關的),getUUID,獲取賬號,主鍵,獲得密鑰key,減庫存,搶優惠券(用到某些數據結構,隊列或集合,參照如下結構使用)(方法內部定義的變量,不涉及線程安全,通常設計線程安全的變量一般都是成員變量)
HashMap非線程安全,改用java.util.concurrent.concurrentHashMap,或HashTable(HashTable不允許插入空值,HashMap允許),或者使用Collection工具類將集合包裝成線程安全的集合(pubilc static Map m = Collections.synchronizedMap(new HashMap()),此方法在并發級別不高是也夠用)
ArrayList非線程安全,雖然Vector是線程安全的,但Vector效率低,因此不建議使用(ArrayList和Vector都是使用“數組”作為其內部實現)可以考慮使用java.util.concurrent.CopyOnWriteArrayList(在讀多寫少的場景,次List性能非常好,對于它來說,讀取是完全不用加鎖的,寫入也不會阻塞讀取操作,只有寫入和寫入之間需要進行同步等待),所謂CopyOnWrite就是在寫入操作時,進行一次自我復制,即,當List需要修改時,并不修改原有內容(這對于保證當前在讀線程的數據一致性非常重要),而是對原有數據進行一次復制,將修改內容寫入副本中,寫完后,再將修改完的副本替換原有數據,這樣就保證寫操作不會影響讀了。
LinkedList非線程安全,使用鏈表的數據結構實現了List,可以使用Collections.synchronizedList()方法來包裝任意List(pubilc static List<String> l = Collections.synchronizedList(new LinkedList<String>())
StringBuffer是線程安全,StringBuilder是線程不安全的(這句話是不對的),StringBuffer只是說他的方法是排他的,也就是說,StringBuffer每一次append是線程安全的,但眾多次append的組合并不是線程安全的(在方法上加synchronized關鍵字),如果換成StringBuilder,甚至有可能append一半,就讓位其他線程
83、JDK并發包中,有一個atomic包,里面實現了一些直接使用CAS操作的線程安全的類型無鎖(原子)線程安全整數:AtomicInteger,對于整數的封裝無鎖(原子)數組:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray無鎖(原子)的對象引用:AtomicReference,對于普通對象的引用帶有時間戳的對象引用:AtomicStampReference讓普通變量也能享受原子操作:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater
84、之后我們前后端接口的敲定遵循契約精神,按如下流程進行:1、數據庫設計完成后韓松、趙翔、博文、后端開發一起商量所需接口個數和每個接口需要實現的功能。2、后端項目經理按照接口數和工作量分配負責開發每個接口的后端人員。3、后端相關人員進行所負責接口的定義,包括參數說明及返回值說明。4、定義好的接口給博文審核,確保技術實現上無問題且實現方式最優。5、博文審核過的接口給趙翔審核,確保可以完全實現前端業務需求。6、審核通過的接口進入接口定義系統,包括輸入輸出結構定義,此時形成契約。7、后端人員進行接口開發及單元測試,注意接口健壯性、容錯(如數據庫字段變更不應影響契約)和方便性(如允許傳入最少的調入參數)。8、開發完成的接口提交測試環境,崔俊依據接口系統生成自動化測試腳本,并進行返回值驗證,判斷返回鍵值是否符合契約。9、測試通過的接口通知前端進行聯調,否則退回后端進行修改,使之遵守契約。
85、"push git 411"問題,如下:error: RPC failed; result=22, HTTP code = 411fatal: The remote end hung up unexpectedlyps:以上發生在push命令中,有可能是push的文件過大導致解決方法:修改倉庫下.git/config 文件>windows:在 .git/config 文件中加入[http]postBuffer = 524288000>Linux:git config http.postBuffer 524288000
86、配置統一放置,便于自動化部署,所有配置信息均匯總于cfg.properties,以后修改為從xdiamond中獲取
增加com.jw.base.framework.core.config.PropertyConfigurer,通用獲取cfg.properties屬性,以后修改為從xdiamond中獲取
app-include.xml中propertyConfigurer,從org.springframework.beans.factory.config.PropertyPlaceholderConfigurer修改為自定義子類PropertyConfigurer
但realpath還是從自定義servlet:StartUpServlet中獲取,web.xml中明確定義log4jConfigLocation【spring】
cfg.properties中增加
log4j.home=D:/sqlCmd【log4j日志路徑】log4j.filename=3171001R【各個工程名】不用在工程啟動參數中增加-Dlog4j.home=D:/sqlCmd
重寫org.springframework.web.util.Log4jConfigListener
<listener><listener-class>com.jw.base.framework.core.listener.Log4jConfigListener</listener-class></listener>其中增加System.setProperty("log4j.home",(String)PropertyConfigurer.getContextProperty("log4j.home"));System.setProperty("log4j.filename",(String)PropertyConfigurer.getContextProperty("log4j.filename"));
MQ配置,Redis配置文件放到相應base工程中
87、寫枚舉時,枚舉類型,及其包含屬性必須編寫相應注釋;根據需要設置default值(若有必要)或拋出異常;要有isEquals方法、以及getEnumConsNm

88、部署tomcat注意配置,一種是指向工程方式【webapps】下不要放置工程war包<Context path="/3171001R" docBase="D:\java\3171001R-1.0.0-SNAPSHOT" debug="0" crossContext="true" /><Context path="/" docBase="D:\java\3160001RA-1.0.0-SNAPSHOT" debug="0" crossContext="true" />
89、druid配置initialSize配置合適就行,但maxActive盡量設置大些// 防止創建超過maxActive數量的連接if (activeCount + poolingCount >= maxActive) {empty.await();continue;}連接太多了的時候,在empty條件上等待,就是等空了再運行
90、在工程中增加禁止爬蟲爬取的robots.txt配置文件
91、上線一定要根據需要設置druid的maxActive,最大并發數
注意調整好服務器時間~~
92、dubbo異步調用定義如下<dubbo:reference id="bsSysUserServiceAsync" interface="com.jw.hms.example.m31xx.f001.microservice.BsSysUserService" timeout="50000" retries="0" check="false" registry="localzk" async="true" sent="true" />A層或P層充當消費者調用DataTableDto data2 = bsSysUserService.queryListAsync(bsSysUserQueryDto, page);System.err.println("立即返回為null:"+data2); //拿到調用的Future引用,當結果返回后,會被通知和設置到此Future。 Future<DataTableDto> pFuture = RpcContext.getContext().getFuture(); //如果data已返回,直接拿到返回值,否則線程wait,等待data返回后,線程會被notify喚醒。 data2 = pFuture.get();System.out.println("返回異步值"+data2);
PS:注意dubbo異步調用傳遞性問題
ServiceA異步調ServiceB,ServiceB再同步調ServiceC,此時ServiceC會當異步調用。但是,如果后續還有同步調用,則因B調C為同步,則就會正常同步調用了。
93、多線程并發,建議使用實現Callable接口,與Future + 線程池結合使用private static ExecutorService service1 = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(Constant.BLOCKING_QUEUE_NUMBER));Callable<DataTableDto> task1 = () -> {try {System.out.println("excute=================task1");Thread.sleep(2000);return bsSysUserServiceRef.queryListAsync(bsSysUserDto, page);} catch (Exception e) {throw e;} finally {}};Future<DataTableDto> result1 = service1.submit(task1);System.out.println("result1================="+result1.get());
94、框架中提供的NamedParameterJdbcTemplate檢索查詢,有兩個,一個是帶分頁的,一個是不帶分頁的,帶分頁的會查詢兩次【其中有一次是統計總條數】,建議根據需要用對應方法,非必要的,不要用分頁的方法
95、ArrayList底層是動態數組,默認初始化大小為10,自動擴充容量是原有容量的1.5倍+1,通過底層的復制方法將原有數據復制,因此 如果數據量很大,那么造成數組重新分配的次數會增加,但對于一般的數據量下,1千需要分配 11次,1萬一級需要分配17次,10萬 需要分配23次,100萬需要分配28次。所以應根據實際情況,大致分配一個初始化的容量還是有必要的。但是如果你初始容量太大,而數據增長很慢,那么就在浪費內存了。如何取舍,還是看具體的應用場景。
96、HashMap底層是數組+鏈表,默認初始化大小為16,加載因子為0.75,即容量超過16*0.75=12時自動擴容,HashMap在擴容時,新數組的容量將是原來的2倍,由于容量發生變化,原有的每個元素需要重新計算bucketIndex,再存放到新數組中去,也就是所謂的rehash。在設置初始容量時應該考慮到映射中所需的條目數及其加載因子,以便最大限度地降低 rehash 操作次數。
97、創建dblinkcreate extension dblink;select * from pg_extension;select dblink_connect('test1_dblink','dbname=jw_platform_test1 host=192.168.18.206 port=5432 user=jw_test1 password=123456');通過dblink查詢select id,login_account fromdblink('test1_dblink','select id,login_account from bs_sys_user where id=10') as t1(id int, login_account varchar);通過dblink進行insert selectinsert into jw_test2.bs_sys_user(id,login_account) select id,login_account fromdblink('test1_dblink','select id,login_account from bs_sys_user where id=10') as t1(id int, login_account varchar);根據不同當前人不同酒店\集團,切換對應dblink標示
98、增加異步消費者接口定義<dubbo:reference id="bsxxxxxxxxxxxAsync" interface="com.jw.hms.example.m3xxx.f001.microservice.BsxxxxxxxxxxService" timeout="60000" retries="0" check="false" registry="localzk" async="true" sent="true" return="false" />
99、報表制作注意事項:a、繪制報表,中文注意字體,建議先設置好所需樣式,單元格設置其樣式b、不用國際化,不同文字繪制不同報表c、圖片使用fastDFS的URLd、手工設置每個單元格高度、寬度,使上下單元格對其,可避免導出excel出現單元格擠在一起的情況【按照每個單元格對其方式畫,空白地方用空白label填充,方便對齊】以@開頭和@結尾,如:"@chainUid@、@unitUid@,系統域宏替換【中間只可以有字符\數字\下劃線】以#開頭和#結尾,如:"#resv_no#",做主子SQL替換,并自動填充值【中間只可以有字符\數字\下劃線】以&開頭和&結尾,如:&account.floor_id|param_id|FLOOR|param_drpt|account.floor_name&,做參數替換,并自動填充值【中間除了可以有字符\數字\下劃線,還可以有.和|】【其中參數類型,如FLOOR,參見《SVN:\新產品研發\platform\03.設計開發\02.數據庫設計\業務-參數定義.xlsx》】以$開頭和$結尾,$ and account.arr_dt >= cast(:arr_dt_begin as timestamp) |arr_dt_begin|EQUALS$,做SQL查詢條件的拼接和替換e、html報表多頁,每頁都是帶表頭和頁數信息的f、穿透可以使用"JavaScript:alert("+$F{id}+")"方式調用js腳本【a標簽】j、圖片URL,動態填充【圖片一定要勾選上“Is lazy”這個選項】h、子報表URL,動態填充【相對路徑】i、字典填充【以&開頭和&結尾,如:&account.floor_id|param_id|FLOOR|param_drpt|account.floor_name&】j、非字典查詢條件where拼接【以$開頭和$結尾,$ and account.arr_dt >= cast(:arr_dt_begin as timestamp) |arr_dt_begin|EQUALS$】查詢條件關鍵字:EQUALS:等值IN-LIST:IN集合PRE-LIKE/SUF-LIKE/ALL-LIKE:前%/后%/前后%模糊查詢k、字典查詢條件where拼接【$account.floor_name|floor_name|FILTER.ALL-LIKE$】查詢條件關鍵字:FILTER.EQUALS:等值FILTER.IN-LIST:IN集合FILTER.PRE-LIKE/FILTER.SUF-LIKE/FILTER.ALL-LIKE:前%/后%/前后%模糊查詢ps:SQL數據源不拼接order by語句,排序在ireport中設置l、條件值,寫死拼接,放在xxx域中,用于展示【字典】m、查詢條件接口【填充字典內容】n、parameters框架封裝共享session參數o、目前框架封裝如下16種中文字體SIMFANG【仿宋】、simhei【黑體】、simkai【楷體】、SIMLI【隸書】、simsun【宋體】、SIMYOU【幼圓】、STCAIYUN【華文彩云】、STFANGSO【華文仿宋】、STHUPO【華文琥珀】、STKAITI【華文楷體】、STLITI【華文隸書】、STSONG【華文宋體】、STXIHEI【華文細黑】、STXINGKA【華文行楷】、STXINWEI【華文新魏】、STZHONGS【華文中宋】p、非參數類型房含 【grp_rsv_package】 【PARA_PACKAGE】房含分組【grp_rsv_package_group】【PARA_PACKAGE_GROUP】房型 【grp_hk_unit_roomtype】 【PARA_ROOMTYPE】交易代碼【grp_fin_base_trncode】 【PARA_TRNCODE】部門 【grp_cmm_department】 【PARA_DEPT】班組 【?】 【PARA_?】職員 【grp_cmm_employee】 【PARA_EMP】職員角色【grp_cmm_role】 【PARA_ROLE】銷售員 【grp_cmm_saler】 【PARA_SALER】操作員 【grp_cmm_user】 【PARA_USER】
100、threadlocal的remove()將當前線程局部變量的值刪除,目的是為了減少內存的占用,該方法是JDK 5.0新增的方法。需要指出的是,當線程結束后,對應該線程的局部變量將自動被垃圾回收,所以顯式調用該方法清除線程的局部變量并不是必須的操作,但它可以加快內存回收的速度。threadlocal里面使用了一個存在弱引用的map,當釋放掉threadlocal的強引用以后,map里面的value卻沒有被回收.而這塊value永遠不會被訪問到了. 所以存在著內存泄露. 最好的做法是將調用threadlocal的remove方法。dubbo服務提供方,線程池,線程結束并不被銷毀,需要必須顯式的去回收,人工調用remove(),否則內存泄漏
101、entity上增加注解,@UniqueKeyEntity,說明本實體的唯一標示是哪個字段,所有模型類都需要增加注解

102、所有需要記日志的dto,都增加實現LogOrigin接口相關代碼

103、 獲取客戶端訪問IP,用這個從頭獲取X-Real-IP
做強壯處理如果X-Real-IP為null,則用request.getRemoteAddr

104、手工插入數據庫,番號增加,則需把redis做相應增加
手工造數據到數據庫,則主鍵ID序列需要做相應增加
105、grp庫、pms庫、pcm庫中cmm_number表手工增加數據,需要加大該表序列
106、日志庫所有表都按照日志時間進行了分區,查詢必須帶著相應分區字段
107、@Override是偽代碼,表示重寫,但如果方法名稱相同而參數列表不同(返回類型可以相同也可以不同),那么只是方法的重載,而非重寫。

不要按照上面的這種寫法寫了哦
108、根據業務定義初始化數據庫連接池,目前約定如下,
每50個酒店左右一個庫,在增加到接近酒店數是,新建一套grp_dev、pms_dev、log_dev、stat_dev
所有酒店共享一個pcm_dev、cms_dev、jw_reportools
只有一套練習庫,包括:grp_dev、pms_dev、log_dev、stat_dev
只有一套測試庫,包括:grp_dev、pms_dev、log_dev、stat_dev
R層工程啟動,建立默認數據庫連接,并讀取現有數據庫連接配置,建立所有數據庫連接
默認數據庫連接:
maxActive=20【池最大20個鏈接】initialSize=1 【初始一個鏈接】minIdle=1 【池最小1個鏈接】
每個plf_ops_dbinfo中配置的業務庫連接,配置如下
開發環境 生產環境
initialSize.pcm=1 initialSize.pcm=10minIdle.pcm=1 minIdle.pcm=1maxActive.pcm=1000 maxActive.pcm=1000
109、select o from com.jw.hms.cmm.m3130.f010.entity.GrpRsvRate o where 1=1 and o.chainUid=:chainUid and o.unitUid=:unitUid and o.statusFlg=:statusFlg and o.rateCd=:rateCd上面第一條HSQL,查出的對象,Hibernate一級緩存起來了下面第二個SQl執行前,怕數據庫上面查出的數據已經被更改,query.list()進行了update,以保證一致性select o from com.jw.hms.cmm.m3130.f010.entity.GrpRsvRate o where 1=1 and o.chainUid=:chainUid and o.unitUid=:unitUid and o.rateId=:rateId因此,大家在寫代碼時,請注意,查詢出對象能復用就復用,盡量不要多次查詢,會有一致性問題
110、檢查一下自己發番的KEY用的對不對哦,
別復制過來忘了改,用的其他的流水號!
111、對List、Set、Map在迭代的時候如果同時對其進行修改就會拋出java.util.ConcurrentModificationException異常,原因調用list.remove()方法導致modCount和expectedModCount的值不一致。注意,像使用for-each進行迭代實際上也會出現這種問題。不要使用Itr類中的remove()方法,雖然在單線程下不會報錯,但在多線程下仍會拋錯,因此建議用并發容器CopyOnWriteArrayList和ConcurrentHashMap代替ArrayList和Vector和HashMap。
CopyOnWriteArrayList注意事項
(1) CopyOnWriteArrayList不能使用Iterator.remove()進行刪除。(2) CopyOnWriteArrayList使用Iterator且使用List.remove(Object);會出現如下異常:java.lang.UnsupportedOperationException: Unsupported operation removejava.util.concurrent.CopyOnWriteArrayList$ListIteratorImpl.remove
例如:List<string> list =
new
CopyOnWriteArrayList<string>();
for(String item : list){ String tem = item + "..."; list.remove(item); list.add(tem); }
112、去掉無用的System.out.println(),增加必要的logger.info ()和logger.error(),用于上線后,復雜業務方便跟蹤,快速有效解決問題。
113、根據下述索引建議,優化SQL語句
(1)負向條件查詢不能使用索引select * from order where status!=0 and stauts!=1not in/not exists都不是好習慣可以優化為in查詢:select * from order where status in(2,3)
(2)前導模糊查詢不能使用索引select * from order where desc like '%XX'而非前導模糊查詢則可以:select * from order where desc like 'XX%'
(3)數據區分度不大的字段不宜使用索引select * from user where sex=1原因:性別只有男,女,每次過濾掉的數據很少,不宜使用索引。
PS:特別說明一下區分度1: 重復度越高,區分度越小,索引效果越不好2: 重復度越低,區分度越高,索引效果越好,但帶來的影響也越大--增刪改變慢,并間接影響查詢速度.慣用手法: 截取不同長度,并測試其區分度select count(distinct left(word,6))/count(*) from dict;截取word字段長度,從1開始截取,計算字符前綴沒有重復的字符占全部數據的比例對于一般的系統應用: 區別度能達到0.1-0.2,索引的性能就可以接受
(4)在屬性上進行計算不能命中索引select * from order where YEAR(date) < = '2017'即使date上建立了索引,也會全表掃描,可優化為值計算:select * from order where date < = CURDATE()或者:select * from order where date < = '2017-01-01'
(5)如果業務大部分是單條查詢,使用Hash索引性能更好,例如用戶中心select * from user where uid=?select * from user where login_name=?原因:B-Tree索引的時間復雜度是O(log(n))Hash索引的時間復雜度是O(1)
(6)允許為null的列,查詢有潛在大坑單列索引不存null值,復合索引不存全為null的值,如果列允許為null,可能會得到“不符合預期”的結果集select * from user where name != 'shenjian'如果name允許為null,索引不存儲null值,結果集中不會包含這些記錄。
(7)復合索引最左前綴,并不是值SQL語句的where順序要和復合索引一致用戶中心建立了(login_name, passwd)的復合索引select * from user where login_name=? and passwd=?select * from user where passwd=? and login_name=?都能夠命中索引select * from user where login_name=?也能命中索引,滿足復合索引最左前綴select * from user where passwd=?不能命中索引,不滿足復合索引最左前綴
PS:多說一下聯合索引聯合索引能夠滿足最左側查詢需求,例如(a, b, c)三列的聯合索引,能夠加速a | (a, b) | (a, b, c) 三組查詢需求。這也就是為何不建立(passwd, login_name)這樣聯合索引的原因,業務上幾乎沒有passwd的單條件查詢需求,而有很多login_name的單條件查詢需求。最左前綴:顧名思義,就是最左優先,上例中我們創建了a_b_c多列索引,相當于創建了(a)單列索引,(a,b)組合索引以及(a,b,c)組合索引。 a ab abc標準寫法 ba bac bca cab cba acb這五種引擎會自動優化成ab和abc的查詢順序查索引。
(8)使用ENUM而不是字符串ENUM保存的是TINYINT,別在枚舉中搞一些“中國”“北京”“技術部”這樣的字符串,字符串空間又大,效率又低。
(9)如果明確知道只有一條結果返回,limit 1能夠提高效率select * from user where login_name=?可以優化為:select * from user where login_name=? limit 1原因:你知道只有一條結果,但數據庫并不知道,明確告訴它,讓它主動停止游標移動
(10)把計算放到業務層而不是數據庫層,除了節省數據的CPU,還有意想不到的查詢緩存優化效果select * from order where date < = CURDATE()這不是一個好的SQL實踐,應該優化為:$curDate = date('Y-m-d');$res = mysql_query('select * from order where date < = $curDate');原因:釋放了數據庫的CPU多次調用,傳入的SQL相同,才可以利用查詢緩存
(11)強制類型轉換會全表掃描select * from user where phone=13800001234不會命中索引
114、業務表為Date的字段,在做equals比較時要尤其注意
entity.getField().equals(java.util.Date),是無法比較的
原因:從數據庫里查詢的這個時間字段的類型,已經被Hibernate默認轉化為:java.sql.Timestamp類型,同java.util.Date類型比較會由于類型不一致,而直接返回false

建議:
1、都轉成String 再比較
2、Timestamp轉成Date
3、Date轉成Timestamp
4、java.util.Date.equals(entity.getField())
115、DAO封裝增加了
private void enhanceSaveEntiy_cache(E entity) throws Exception
private void enhanceUpdateEntiy_cache(E entity) throws Exception
以減少類反射的次數,大家用到相應類反射地方,可以參考
116、每次上傳后要統計代碼數量,供品質量化使用
一段時間內的差分代碼行數統計【統計JW + CW兩個倉庫】git log --author="bwliu" --since=3.day.ago --pretty=tformat: --numstat | gawk '{ add += $1 ; subs += $2 ; loc += $1 + $2 } END { printf "added lines: %s removed lines : %s total lines: %s \n",add,subs,loc }'

一段時間內的新歸代碼行數統計自己根據近期新增文件統計
一段時間內的差分代碼母代碼行數統計【修改代碼總行數】先打印某人某段時間提交文件查看行數命令git log --author="bwliu" --since=1.day.ago --pretty=tformat: --name-status | gawk '{print "wc -l """"D:/_git/jw-source/"""$2}'

然后執行打印出來的查看條數的腳本

117、通過ID查名字的,都統一用如下接口

118、正式環境無感知迭代發布流程梳理如下:
1、導流把需要發布的集中中一個點的流量導到其他節點中去2、暫停一分鐘后,停前后端服務3、更新此次迭代的最新數據庫結構,緩存結構及相應數據4、發布后端程序5、發布前端程序6、啟動前后端服務7、測試后,流量導回到新發布服務上8、其他服務重復上述過程
灰度發布流程梳理如下:1、導流把需要發布的需調整灰度策略(目前可以根據請求頭上集團UID和酒店UID進行切換)節點的流量導到其他節點中去2、暫停一分鐘后,停前后端服務3、更新此次迭代的最新數據庫結構,緩存結構及相應數據4、發布后端程序5、發布前端程序6、啟動前后端服務7、測試后,流量導回到新發布服務上
119、正式環境GIT開發、測試、發布流程

120、query.list()的FlushMode默認為AUTO,當session設置為FlushMode.AUTO時,hibernate在進行查詢的時候會判斷緩存中的數據是否為臟數據,是則刷數據庫,不是則不刷
Hibernate session FlushMode有五種屬性:1、NEVEL:已經廢棄了,被MANUAL取代了2、MANUAL:如果FlushMode是MANUAL或NEVEL,在操作過程中hibernate會將事務設置為readonly,所以在增加、刪除或修改操作過程中會出現如下錯誤org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into FlushMode.AUTO or remove 'readOnly' marker from transaction definition;解決辦法:配置事務,spring會讀取事務中的各種配置來覆蓋hibernate的session中的FlushMode3、AUTO設置成auto之后,當程序進行查詢、提交事務或者調用session.flush()的時候,都會使緩存和數據庫進行同步,也就是刷新數據庫4、COMMIT提交事務或者session.flush()時,刷新數據庫;查詢不刷新5、ALWAYS:每次進行查詢、提交事務、session.flush()的時候都會刷數據庫
ALWAYS和AUTO的區別:當hibernate緩存中的對象被改動之后,會被標記為臟數據(即與數據庫不同步了)。當 session設置為FlushMode.AUTO時,hibernate在進行查詢的時候會判斷緩存中的數據是否為臟數據,是則刷數據庫,不是則不刷,而always是直接刷新,不進行任何判斷。很顯然auto比always要高效得多。
121、所有dto和entity的描述和name要標示正確
fieldnm是字段名,后面是中文描述這邊入ES轉化,要用這個的要不就轉化亂了
122、postgresql正則表達式使用:
操作符
描述
例子
~
匹配正則表達式,大小寫相關
'thomas' ~ '.thomas.'
~*
匹配正則表達式,大小寫無關
'thomas' ~* '.Thomas.'
!~
不匹配正則表達式,大小寫相關
'thomas' !~ '.Thomas.'
!~*
不匹配正則表達式,大小寫無關
'thomas' !~* '.vadim.'
正則表達式原子
原子
描述
(re)
(這里的 re 是任何正則表達式) 匹配一個對 re 的匹配,有可報告的匹配信息
(?:re)
同上,但是匹配不會被報告 (一個"不捕獲"圓括弧) (只在 ARE 中有)
.
匹配任意單個字符
[chars]
一個 方括弧表達式, 匹配任意的字符(參閱 Section 9.7.3.2 獲取更多細節)
*k*
(這里的 k 是非字母數字字符) 匹配一個當作普通字符看待的特定字符, 比如,\ 匹配一個反斜杠
*c*
這里的 c 是一個字母數字 (可能跟著其它字符),它是一個逃逸, 參閱 Section 9.7.3.3(僅存在于 ARE; 在 ERE 和 BRE 中,它匹配 c)
{
如果后面跟著一個字符,而不是數字, 那么就匹配左花括弧{;如果跟著一個數字, 那么它是范圍的開始(見下面)
x
這里的 x 是一個沒有其它特征的單個字符, 則匹配該字符
正則表達式量詞
量詞
匹配
一個匹配 0 或者更多個原子的序列
一個匹配 1 或者更多個原子的序列
?
一個匹配 0 個或者 1 個原子的序列
{m}
一個正好匹配 m 個原子的序列
{m,}
一個匹配m 個或者更多原子的序列
{m,n}
一個匹配 m 到 n 個(包含兩端) 原子的序列;m 不能比 n 大
*?
- 的非貪婪模式
+?
- 的非貪婪模式
??
? 的非貪婪模式
{m}?
{m} 的非貪婪模式
{m,}?
{m,} 的非貪婪模式
{m,n}?
{m,n} 的非貪婪模式
正則表達式約束
約束
描述
^
匹配字串的開頭
$
匹配字串的結尾
(?=re)
正前瞻 匹配任何匹配 re 的 子字串起始點(只在 ARE 中有)
(?!re)
負前瞻 匹配任何不匹配 re 的子字串的起始點。(只在 ARE 中有)
上面只列出正則表達式的一些基礎知識,正則表達式的檢索能力相當強大,特別是對于類型為Text類型,并且存儲的是XML數據時,正則表達式的優勢將更能發揮作用。
關于更詳細的信息可以參考文檔http://www.postgresql.org/docs/9.0/static/functions-matching.html
舉例:SELECT * FROM ind_dtofield where fieldnm !~* '[a-z]'
123、DTO的注解說明中,應為界面上的名稱【參照界面填寫】

124、完善DTO中map的key值描述信息


125、完善DTO中字典屬性的注解說明

126、完善DTO中特殊信息的特殊標記說明

127、 語種以前用的zh(中文)和en(英文),現在改為zh-CN(中文簡體:1220)和en-US(英語(美國:1056)),日語用ja-JP(日語(日本:1120))。前端傳的字符串應該是小寫,數據庫是大小寫均有,寫SQL時注意轉換
128、共同參數、集團酒店餐飲參數、系統參數處室話到緩存中的格式為:
共同參數:類型語種.param_id.param_drpt
集團酒店餐飲參數:類型語種.attribute_vlu.attribute_drpt
系統參數:類型_語種_master庫名.param_id.param_drpt【從庫查詢,得把從threadlocal中獲取的庫名轉化為主庫的】
上述紅字部分為key值,后面為map
設置方式:
jwCache.hmset(key, map)
jwCache.hset(key, field, value)
獲取方式
jwCache.hmget(key, fields...)
jwCache.hgetAll(key)
命令行示例:
hgetAll BLKLSTCXLRSN_1220hmget BLKLSTCXLRSN_1220 1hmget MARKET_1220_grp_dev 1000313echo -e -n "\xe5\x85\x8d\xe8\xb4\xb9\xe6\x88\xbf"
其中:(中文:1220)(英語:1056)(日語:1120)
129、除下圖之外,還會有一套模板庫,【模板庫僅供copy用,不程序不鏈接到其上】

PS:
dev庫不能被覆蓋,僅供開發用
已使用的庫,也不能被模板庫覆蓋
練習庫和測試庫,可以被本身的正式庫覆蓋
新建庫的發番配置數據要完整【韓松負責】
130、postgresql連接到schema【jdbc:postgresql://postgreSlave:5432/pcm_dev?characterEncoding=utf8¤tSchema=pcm_dev】
參見:https://jdbc.postgresql.org/documentation/head/connect.html
一個數據庫包含一個或多個命名的模式,模式又包含表。模式還包含其它命名的對象,包括數據類型、函數,以及操作符。同一個對象名可以在不同的模式里使用而不會導致沖突; 比如,schema1和myschema都可以包含叫做mytable的表。和數據庫不同,模式不是嚴格分離的:一個用戶可以訪問他所連接的數據庫中的任意模式中的對象,只要他有權限。 我們需要模式有以下幾個主要原因: 1). 允許多個用戶使用一個數據庫而不會干擾其它用戶。 2). 把數據庫對象組織成邏輯組,讓它們更便于管理。 3). 第三方的應用可以放在不同的模式中,這樣它們就不會和其它對象的名字沖突。
我們在使用一個數據庫對象時可以使用它的全稱來定位對象,然而這樣做往往也是非常繁瑣的,每次都不得不鍵入owner_name.object_name。PostgreSQL中提供了模式搜索路徑,這有些類似于Linux中的$PATH環境變量,當我們執行一個Shell命令時,只有該命令位于$PATH的目錄列表中,我們才可以通過命令名直接執行,否則就需要輸入它的全路徑名。PostgreSQL同樣也通過查找一個搜索路徑來判斷一個表究竟是哪個表,這個路徑是一個需要查找的模式列表。在搜索路徑里找到的第一個表將被當作選定的表。如果在搜索路徑中 沒有匹配表,那么就報告一個錯誤,即使匹配表的名字在數據庫其它的模式中存在也如此。 在搜索路徑中的第一個模式叫做當前模式。除了是搜索的第一個模式之外,它還是在CREATE TABLE沒有聲明模式名的時候,新建表所屬于的模式。要顯示當前搜索路徑,使用下面的命令:


131、不允許出現DTO嵌套自己的情況出現【除特殊需要外】


132、熱部署JRebel的spring監控插件,對于spring-data的監控有問題,請大家在開發環境啟動參數配置中關掉,如下圖所示:

133、防止NPE【NullPointerException】,是調用者的責任,注意NPE產生的場景:
1)返回類型為基本數據類型,return包裝數據類型的對象時,自動拆箱有可能產生NPE。
反例:public int f() { return Integer對象}, 如果為null,自動解箱拋NPE。
2) 數據庫的查詢結果可能為null。
3) 集合里的元素即使isNotEmpty,取出的數據元素也可能為null。
4) 遠程調用返回對象時,一律要求進行空指針判斷,防止NPE。
5) 對于Session中獲取的數據,建議NPE檢查,避免空指針。
6) 級聯調用obj.getA().getB().getC();一連串調用,易產生NPE。
正例:使用JDK8的Optional類來防止NPE問題。
【Optional的代碼相對更加簡潔,當代碼量較大時,我們很容易忘記進行null判定,但是使用Optional類則會避免這類問題。】
例子:return str.length(); 改為: return Optional.ofNullable(str).map(String::length).orElse(0);
例子:Optional<String> optStr = Optional.ofNullable(str); // 如果str是null,則創建一個空對象
例子:【手機和郵箱不是一個人的必須有的,所以我們利用Optional定義。】
public class User {/** 用戶編號 */private long id;private String name;private int age;// private Optional<Long> phone;// 不能序列化// private Optional<String> email;// 不能序列化
public User(String name, int age) {this.name = name;this.age = age;}
// 省略setter和getter
// 注意事項:Optional是一個final類,未實現任何接口,所以當我們在利用該類包裝定義類的屬性的時候,如果我們定義的類有序列化的需求,那么因為Optional沒有實現Serializable接口,這個時候執行序列化操作就會有問題
private long phone;
public Optional<Long> getPhone() {return Optional.ofNullable(this.phone);}
}
例子:【映射:map與flatMap】【映射是將輸入轉換成另外一種形式的輸出的操作】
String name = Optional.ofNullable(user).map(User::getName).orElse("no name");因為map之后返回的是Optional,我們把這種稱為Optional嵌套,我們必須在map一次才能拿到我們想要的結果:long phone = optUser.map(User::getPhone).map(Optional::get).orElse(-1L);其實這個時候,更好的方式是利用flatMap,一步拿到我們想要的結果:long phone = optUser.flatMap(User::getPhone).orElse(-1L);
例子:【過濾:fliter 】【可以將過濾操作做為參數傳遞給該方法,從而實現過濾目的】
optUser.filter(u -> u.getAge() >= 18).ifPresent(u -> System.out.println("Adult:" + u));
134、避免出現重復的代碼(Don’t Repeat Yourself),即DRY原則。
隨意復制和粘貼代碼,必然會導致代碼的重復,在以后需要修改時,需要修改所有的副本,容易遺漏。必要時抽取共性方法,或者抽象公共類,甚至是組件化。 正例:一個類中有多個public方法,都需要進行數行相同的參數校驗操作,這個時候請抽取:private boolean checkParam(DTO dto) {...}
135、編寫單元測試代碼遵守BCDE原則,以保證被測試模塊的交付質量。
B:Border,邊界值測試,包括循環、特殊取時間點數據順序等。
C:Correct,正確的輸入,并得到預期結果。
D:Design,與設計文檔相結合,來編寫單元測試。
E:Error,強制錯誤信息輸入(如:非法數據、異常流程業務允許等),并得到預期的結果。
136、為了更方便地進行單元測試,業務代碼應避免以下情況:
a) 構造方法中做的事情過多。
b) 存在過多的全局 變量 和靜態方法。
c) 存在過多的外部依賴。
d) 存在過多的條件語句。
說明: 多層條件語句建議使用衛、策略模式狀態等方重構。