亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 數據庫 > 文庫 > 正文

在CRUD操作中與業務無關的SQL字段賦值的方法

2020-10-29 21:48:45
字體:
來源:轉載
供稿:網友

提高效率一直是個永恒的話題,編程中有一項也是可以提到效率的,那就是專注做一件事情,讓其它沒有強緊密聯系的與之分開。這里分享下我們做CRUD時遇到的常見數據處理場景:

•數據庫表字段全部設計為非空,即使這個字段在業務上是可以為空的,之所以將數據庫表字段全部設計為非空,這里有優點也有缺點,我們認為優點大于缺點,所以選擇了它

優點:

1.獲取值時,不用判斷這個字段是否為null,直接可用于邏輯運算。

2.mysql DBA推薦此方案,可能是有利于性能,這里我并非求證過。

缺點:

1.業務含義沒有null清楚,比如int字段默認值設置成0,0就沒有null語義清晰。

2.在使用ORM插入數據時,需要處理非空字段值為null的問題。

• 系統字段的賦值,比如創建人,創建人id,創建時間,編輯人,編輯人id,編輯時間等,這些都需要在實際插入數據庫前賦值給Model。這些系統字段與具體的業務一般沒有太大的關聯關系,只是起到標注數據被什么人在什么時間處理的,當這些非業務相關的代碼充斥在代碼中時,就顯得有些多余,而且這類代碼多了也會顯示冗余,最后帶來的結果就是非關鍵代碼比例大。

上面關于默認值與null語義問題不需要解決,因為我們認為具有默認值帶來的優點遠大于可空字段帶來的煩惱,我們來看默認值與系統字段一般情況下如何處理:

•在操作ORM時,將模型所有可空的字段都手動賦值成默認值,int的賦值為0等。

•在設計數據庫時,將非空字段加上默認值,讓數據庫來處理這些未插入值的字段,如果使用mybatis的話,mapper中提到的插入操作有兩個:insert,insertSelective,后面這個insertSelective就是處理非空字段的,即插入的模型對于不需要賦值的字段就保持null值,數據庫在插入時生成的sql語句也不會包含這些字段,這樣就可以利用上數據庫的默認值了。如果正巧數據庫的結構當初設計時沒有設計默認值,又不能改的情況就比較糟糕了,情況回到上面手動賦值,可能會出現類似如下的代碼:編寫一個函數通過反射來解析每個字段,如果為null就修改為默認值:

public static <T> void emptyNullValue(final T model) {Class<?> tClass = model.getClass();List<Field> fields = Arrays.asList(tClass.getDeclaredFields());for (Field field : fields) {Type t = field.getType();field.setAccessible(true);try {if (t == String.class && field.get(model) == null) {field.set(model, "");} else if (t == BigDecimal.class && field.get(model) == null) {field.set(model, new BigDecimal(0));} else if (t == Long.class && field.get(model) == null) {field.set(model, new Long(0));} else if (t == Integer.class && field.get(model) == null) {field.set(model, new Integer(0));} else if (t == Date.class && field.get(model) == null) {field.set(model, TimeHelper.LocalDateTimeToDate(java.time.LocalDateTime.of(1990, 1, 1, 0, 0, 0, 0)));}} catch (IllegalAccessException e) {e.printStackTrace();}}} 

然后在代碼調用insert前調用函數來解決:

ModelHelper.emptyNullValue(request); 

如何處理系統字段呢,在創建編輯數據時,需要獲取當前用戶,然后根據邏輯分別更新創建人信息以及編輯人信息,我們專門編寫一個反射機制的函數來處理系統字段:

注:下面的系統字段的識別,是靠系統約定實現的,比如creator約定為創建人等,可根據不同的情況做數據兼容,如果系統設計的好,一般在一個系統下所有表的風格應該是相同的。

public static <T> void buildCreateAndModify(T model,ModifyModel modifyModel,boolean isCreate){Class<?> tClass = model.getClass();List<Field> fields = Arrays.asList(tClass.getDeclaredFields());for (Field field : fields) {Type t = field.getType();field.setAccessible(true);try {if(isCreate){if (field.getName().equals(modifyModel.getcId())) {field.set(model, modifyModel.getUserId());}if (field.getName().equals(modifyModel.getcName())) {field.set(model, modifyModel.getUserName());}if (field.getName().equals(modifyModel.getcTime())) {field.set(model, new Date());}}if (field.getName().equals(modifyModel.getmId())) {field.set(model, modifyModel.getUserId());}if (field.getName().equals(modifyModel.getmName())) {field.set(model, modifyModel.getUserName());}if (field.getName().equals(modifyModel.getmTime())) {field.set(model, new Date());}} catch (IllegalAccessException e) {e.printStackTrace();}}}

最后在數據處理前,根據創建或者編輯去調用函數來給系統字段賦值,這類代碼都混雜在業務代碼中。

ModifyModel modifyModel = new ModifyModel();modifyModel.setUserId(getCurrentEmployee().getId());modifyModel.setUserName(getCurrentEmployee().getName());if (request.getId() == 0) {ModelHelper.buildCreateAndModify(request, modifyModel, true);deptService.insert(request);} else {ModelHelper.buildCreateAndModify(request, modifyModel, false);deptService.updateByPrimaryKey(request);}

我們可以利用參數注入來解決。參數注入的理念就是在spring mvc接收到前臺請求的參數后,進一步對接收到的參數做處理以達到預期的效果。我們來創建

ManageModelConfigMethodArgumentResolver,它需要實現HandlerMethodArgumentResolver,這個接口看起來比較簡單,包含兩個核心方法:

• 判斷是否是需要注入的參數,一般通過判斷參數上是否有特殊的注解來實現,也可以增加一個其它的參數判斷,可根據具體的業務做調整,我這里只以是否有特殊注釋來判定是否需要參數注入。

@Overridepublic boolean supportsParameter(MethodParameter parameter) {return parameter.hasParameterAnnotation(ManageModelConfig.class);}

• 參數注入,它提供了一個擴展入口,讓我們有機會對接收到的參數做進一步的處理。

@Overridepublic Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {Object manageModel =getRequestResponseBodyMethodProcessor().resolveArgument(parameter, mavContainer, webRequest, binderFactory);ServletRequest servletRequest = webRequest.getNativeRequest(ServletRequest.class);Employee currentUser = (Employee) servletRequest.getAttribute(DEFAULT_ATTRIBUTE_GET_USER_FROM_REQUEST);if (null == currentUser){return manageModel;}ManageModelConfig parameterAnnotation = parameter.getParameterAnnotation(ManageModelConfig.class);ModelHelper.setDefaultAndSystemFieldsValue(manageModel, currentUser,parameterAnnotation.isSetDefaultFieldsValue());return manageModel;}

這段函數有幾處核心邏輯:

•取得參數對象,因為我們處理的是ajax請求的參數,最簡單的注入方法就是得到實際參數通過反射去處理默認字段以及系統的值。ajax請求與form表單post提交的數據綁定略有不同,可參考之前文章分享的列表頁動態搜索的參數注入(列表頁的動態條件搜索)。獲取當前請求參數對象,我們可以借助如下兩個對象配合來完成:

•RequestMappingHandlerAdapter

•RequestResponseBodyMethodProcessor

private RequestMappingHandlerAdapter requestMappingHandlerAdapter=null;private RequestResponseBodyMethodProcessor requestResponseBodyMethodProcessor = null;private RequestResponseBodyMethodProcessor getRequestResponseBodyMethodProcessor() {if(null==requestMappingHandlerAdapter){requestMappingHandlerAdapter=new RequestMappingHandlerAdapter();}if (null==requestResponseBodyMethodProcessor) {List<HttpMessageConverter<?>> messageConverters = requestMappingHandlerAdapter.getMessageConverters();messageConverters.add(new MappingJackson2HttpMessageConverter());requestResponseBodyMethodProcessor = new RequestResponseBodyMethodProcessor(messageConverters);}return requestResponseBodyMethodProcessor;} 

通過如下代碼就可以取到參數對象了,其實就是讓spring mvc重新解析了一遍參數。

Object manageModel =getRequestResponseBodyMethodProcessor().resolveArgument(parameter, mavContainer, webRequest, binderFactory); 

•如何獲取當前用戶,我們在成功登錄系統后,將當前用戶的信息存儲在request中,然后就可以在函數中獲取當前用戶,也可以采用其它方案,比如ThreadLocal,緩存等等。

ServletRequest servletRequest = webRequest.getNativeRequest(ServletRequest.class);Employee currentUser = (Employee) servletRequest.getAttribute(DEFAULT_ATTRIBUTE_GET_USER_FROM_REQUEST); 

•調用處理函數解決默認字段以及系統的賦值,可以根據配置來決定是否處理字段默認值。

ManageModelConfig parameterAnnotation = parameter.getParameterAnnotation(ManageModelConfig.class);ModelHelper.setDefaultAndSystemFieldsValue(manageModel, currentUser,parameterAnnotation.isSetDefaultFieldsValue());

最后將我們的參數注入邏輯啟動起來,這里選擇在xml中配置:

<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"><mvc:argument-resolvers><bean class="cn.wanmei.party.management.common.mvc.method.annotation.ManageModelConfigMethodArgumentResolver"/></mvc:argument-resolvers></mvc:annotation-driven> 

再看action中的調用:只需要在參數前面增加注解@ManageModelConfig,如果需要處理默認值,則將啟用默認值的選項設置成true即可,下面的實現部分完全看不到任何與業務無關的代碼。

@RequestMapping(value = "/addOrUpdateUser")@ResponseBodypublic Map<String, Object> addOrUpdateUser(@ManageModelConfig(isSetDefaultFieldsValue=true) EmployeeDto request) {Map<String, Object> ret = new HashMap<>();ValidateUtil.ValidateResult result= new ValidateUtil().ValidateModel(request);boolean isCreate=request.getId() == 0;try {if (isCreate){employeeService.insert(request);}else{employeeService.updateByPrimaryKey(request);}ret.put("data", "ok");}catch (Exception e){ret.put("err", e.getMessage());}return ret;}

通過自定義實現HandlerMethodArgumentResolver,來捕獲ajax請求的參數,利用反射機制動態的將系統字段以及需要處理默認值的字段自動賦值,避免人工干預,起到了代碼精簡,邏輯干凈,問題統一處理的目的。需要注意的是這些實現都是結合當前系統設計的,比如我們認為id字段>0就代表是更新操作,為空或者等于小于0就代表是創建,系統字段也是約定名稱的等等。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
色综合伊人色综合网| 亚洲视频一区二区| 亚洲一区二区三区毛片| 91色精品视频在线| 欧美日韩亚洲激情| 91亚洲精品久久久久久久久久久久| 国产精品com| 欧美中文字幕视频在线观看| 精品国产乱码久久久久久婷婷| 狠狠操狠狠色综合网| 都市激情亚洲色图| 久久精视频免费在线久久完整在线看| 国产亚洲激情在线| 日韩av免费网站| 91中文字幕一区| 国产精品久久久久久久久久尿| 国产精品观看在线亚洲人成网| 亚洲人成人99网站| 日韩精品欧美国产精品忘忧草| 亚洲最新在线视频| 精品日本美女福利在线观看| 日韩在线观看免费高清完整版| 精品综合久久久久久97| 欧美色视频日本版| 超碰日本道色综合久久综合| 成人激情视频在线| 成人精品久久久| 亚洲人成在线电影| 精品中文视频在线| 国产一级揄自揄精品视频| 91色精品视频在线| 亚洲а∨天堂久久精品喷水| 九九九久久久久久| 亚洲色图13p| 色av中文字幕一区| 韩国一区二区电影| xvideos成人免费中文版| 欧美精品18videosex性欧美| 久久久久久久久国产精品| 永久免费毛片在线播放不卡| 欧美日韩国产丝袜另类| 91经典在线视频| 久久久成人的性感天堂| 精品久久久久久久久中文字幕| 日韩欧美高清视频| 午夜精品久久久久久久白皮肤| 中文字幕在线成人| 久久久久久久久久久网站| 欧美日韩不卡合集视频| 日韩av免费网站| 国产亚洲欧美一区| 国产精品色视频| 久久久久亚洲精品| 69国产精品成人在线播放| 久久久久久久亚洲精品| 亚洲国产精品女人久久久| 亚洲成色999久久网站| 国产一区私人高清影院| 欧美高清第一页| 大胆人体色综合| 欧美精品情趣视频| 亚洲电影中文字幕| 久久久久www| 在线日韩av观看| 日本精品视频网站| 日韩av有码在线| 午夜精品蜜臀一区二区三区免费| 日韩一区视频在线| 日本成熟性欧美| 日韩一级裸体免费视频| 亚洲欧美日韩天堂| 俺去啦;欧美日韩| 国产成人在线一区二区| 国产精品视频在线观看| 亚洲免费人成在线视频观看| 2019亚洲日韩新视频| 欧美亚洲成人xxx| 欧美成年人视频| 成人免费视频网址| 97视频免费看| 日本亚洲欧洲色| 久久久免费高清电视剧观看| 欧美精品久久久久久久免费观看| 欧美香蕉大胸在线视频观看| 久久夜色精品亚洲噜噜国产mv| 综合136福利视频在线| 日韩在线免费高清视频| 97成人在线视频| 高清欧美一区二区三区| 亚洲第一福利网| 全色精品综合影院| 国产精品视频自拍| 久久综合免费视频| 岛国视频午夜一区免费在线观看| 欧美精品九九久久| 国产区精品在线观看| 欧美伊久线香蕉线新在线| 亚洲欧美第一页| 国产精品久久久久久久7电影| 日韩精品在线观看一区二区| 2019精品视频| 69久久夜色精品国产69乱青草| 日韩av观看网址| 亚洲电影av在线| 视频在线观看一区二区| 亚洲国产成人久久| 欧美成人免费大片| 色综久久综合桃花网| 日韩av在线高清| 色偷偷av亚洲男人的天堂| 国产欧美在线播放| 亚洲电影在线观看| 欧美成人精品一区| 成人免费视频97| 欧美成人免费一级人片100| 成人免费观看49www在线观看| 成人免费网站在线观看| 欧美日韩成人在线播放| 91亚洲精品一区| 国产精品久久77777| zzijzzij亚洲日本成熟少妇| 国产精品中文久久久久久久| 日韩大片在线观看视频| 91免费版网站入口| 91午夜在线播放| 欧美精品日韩www.p站| 欧美国产亚洲视频| 国产精品无av码在线观看| 国产亚洲日本欧美韩国| 久99九色视频在线观看| 精品中文视频在线| 欧美有码在线观看视频| 日韩精品免费看| 日本不卡视频在线播放| 日韩精品中文字幕视频在线| 国产精品久久9| 日韩一区二区久久久| 68精品国产免费久久久久久婷婷| 久久久精品视频在线观看| 国产精品久久久久久久久免费看| 国产成人精品午夜| 欧美高跟鞋交xxxxhd| 久久精品99国产精品酒店日本| 欧美日韩在线第一页| 不卡伊人av在线播放| 欧美特黄级在线| 日韩中文字幕免费视频| 97久久国产精品| 成人中文字幕在线观看| 亚洲综合中文字幕68页| 在线播放日韩av| 亚洲的天堂在线中文字幕| 亚洲欧美色婷婷| 欧美区二区三区| 国产成人精品日本亚洲专区61| 狠狠色香婷婷久久亚洲精品| 久久影院在线观看| 亲子乱一区二区三区电影| 国产在线视频欧美| 亚洲女人天堂色在线7777| 国产精品久久久久久婷婷天堂| 俺去亚洲欧洲欧美日韩| 欧美高清一级大片| 欧美国产激情18|