posts - 122,  comments - 25,  trackbacks - 0
          一般業(yè)務(wù)系統(tǒng)中總會(huì)存在一些基礎(chǔ)數(shù)據(jù),在其他的業(yè)務(wù)單據(jù)中會(huì)被套引用。因此,系統(tǒng)必須保證這些被業(yè)務(wù)單據(jù)引用的基礎(chǔ)數(shù)據(jù)不能任意的刪除。最常見(jiàn)的做法就是,在刪除基礎(chǔ)數(shù)據(jù)時(shí),預(yù)先校驗(yàn)該類(lèi)數(shù)據(jù)是否在相關(guān)業(yè)務(wù)表中存在,若不存在才允許用戶(hù)刪除,否則給用戶(hù)以提示。

          但這樣的處理方法,有些缺點(diǎn),就是需要編碼對(duì)每個(gè)業(yè)務(wù)類(lèi)提供查詢(xún)方法,或在刪除邏輯中增加判斷邏輯。因此,每次引用關(guān)系變化,增加或減少時(shí)免不了要修改原來(lái)的邏輯,時(shí)間越長(zhǎng),系統(tǒng)的維護(hù)成本就越來(lái)越高了。因此,有必要對(duì)系統(tǒng)進(jìn)行重構(gòu),將這類(lèi)的處理邏輯進(jìn)行抽象,單獨(dú)封裝成一個(gè)服務(wù),當(dāng)引用關(guān)系有變更時(shí),不用再修改原有邏輯,通過(guò)配置就可以完成變更。

          通用引用關(guān)系查詢(xún)服務(wù),主要就是通過(guò)db表或xml配置文件,對(duì)系統(tǒng)中每個(gè)基礎(chǔ)數(shù)據(jù)有引用的所有關(guān)系進(jìn)行定義,定義屬性主要是引用的表及字段名稱(chēng)。查詢(xún)時(shí),從配置文件中讀取指定類(lèi)別的引用關(guān)系,并逐一查詢(xún)這些表中的記錄,以確定數(shù)據(jù)是否被引用。這種處理方法的優(yōu)點(diǎn)為,易擴(kuò)展、可維護(hù)性強(qiáng),引用關(guān)系變更時(shí),僅通過(guò)維護(hù)配置文件,不必進(jìn)行編碼,就能實(shí)現(xiàn),這樣能大大的提高系統(tǒng)的穩(wěn)定性。

          xml配置文件如下:
          <rule bizName='product' desc="產(chǎn)品關(guān)聯(lián)項(xiàng)定義">
              
          <item>
                  
          <refTable>sale_item</refTable>
                  
          <refField>product_id</refField>
                  <!-- 用于查詢(xún)條件的擴(kuò)展,允許為空 -->
                  <extCondition>CORP_ID = #corpId#</extCondition>
              
          </item>
              
          <item>
                  
          <refTable>sale_order_item</refTable>
                  
          <refField>product_id</refField>
                  
          <extCondition>CORP_ID = #corpId#</extCondition>
              
          </item>
          </rule>
          <rule bizName='customer' desc="客戶(hù)關(guān)聯(lián)項(xiàng)定義">
              
          <item>
                  
          <refTable>sale_order</refTable>
                  
          <refField>cust_id</refField>
                  
          <extCondition>CORP_ID = #corpId#</extCondition>
              
          </item>
              
          <item>
                  
          <refTable>sale_bill</refTable>
                  
          <refField>cust_id</refField>
                  
          <extCondition></extCondition>
              
          </item>
              ... ...

          </rule>

          通用業(yè)務(wù)引用查詢(xún)類(lèi)代碼片段如下:
          public class BizReferenceService implements IBizReferenceService {

              
          private static Map<String,List<BizReferenceRule>> ruleMaps;
              
              
          private static final String PATTERN = "#[\\w]+#";
              
          private static final String CFG_FILE = "bizReferenceRule.xml";
              ... ...

            
              
          /**
               * 查詢(xún)指定業(yè)務(wù)數(shù)據(jù)是否被其他業(yè)務(wù)表關(guān)聯(lián)依賴(lài).
               * 
          @param bizName 關(guān)聯(lián)業(yè)務(wù)名稱(chēng)
               * 
          @param bizId 關(guān)聯(lián)業(yè)務(wù)ID.
               * 
          @param extParam 擴(kuò)展條件
               * 
          @return true 被關(guān)聯(lián)/false 未被關(guān)聯(lián).
               
          */
              
          public boolean isBizReference(String bizName,String bizId,Map<String,Object>extParam) throws ServiceException {
                  Assert.notNull(bizName, 
          "業(yè)務(wù)名稱(chēng)不能為空,bizName is NULL。");
                  Assert.notNull(bizId, 
          "記錄ID不能為空,bizId is NULL。");

                  
          try {
                      
          //逐個(gè)檢查依賴(lài)項(xiàng)是否有數(shù)據(jù)關(guān)聯(lián).
                      List<BizReferenceRule> rules = getBizRelationRule(bizName);
                      
          for(BizReferenceRule rule : rules){
                          StringBuilder sqlBuilder 
          = new StringBuilder();
                          sqlBuilder.append(
          "select count(*) from ").append(rule.getRelTable()).append(" where ")
                              .append(rule.getRelField()).append(
          "='").append(bizId).append("");
                          String extConditon 
          = rule.getExtCondition();
                          
          if(StringUtil.isNotBlank(extConditon)){
                              initTenantParam(extParam);
                              sqlBuilder.append(
          " and ").append(getExtParamSql(extConditon,extParam));
                          }
                          logger.debug(sqlBuilder);
                          
          int nCount = bizReferenceDao.getBizRelationCount(sqlBuilder.toString());
                          
          if (nCount != 0return true;
                      }
                      
          return false;
                  }
                  
          catch(Exception ex){
                      logger.error(
          "調(diào)用業(yè)務(wù)關(guān)聯(lián)服務(wù)錯(cuò)誤。"+bizName+",bizId:"+bizId+",extParam"+LogUtil.parserBean(extParam),ex);
                      
          throw new ServiceException("調(diào)用業(yè)務(wù)關(guān)聯(lián)服務(wù)錯(cuò)誤。");
                  }
              }
              
              
          /**
               * 組裝擴(kuò)展查詢(xún)條件的sql
               * 
          @param condition
               * 
          @param extParam
               * 
          @return
               * 
          @throws Exception
               
          */
              
          private String getExtParamSql(String condition,Map<String,Object>extParam) throws Exception {
                  List
          <String> paramList = parseDyncParam(condition);
                  
          for(String param : paramList){
                      String simpleParam 
          = simpleName(param);
                      
          if(!extParam.containsKey(simpleParam)){
                          
          throw new ServiceException("動(dòng)態(tài)參數(shù)值未設(shè)置! param:"+param+",extParam:"+LogUtil.parserBean(extParam));
                      }
                      condition 
          = condition.replaceAll(param, "'"+String.valueOf(extParam.get(simpleParam))+"'");
                  }
                  
          return condition;
              }
              
              
          /**
               * 解析擴(kuò)展查詢(xún)條件中的動(dòng)態(tài)參數(shù)名.
               * 
          @param condition
               * 
          @return
               * 
          @throws Exception
               
          */
              
          private List<String> parseDyncParam(String condition) throws Exception {
                  PatternCompiler compiler 
          = new Perl5Compiler();
                  PatternMatcher matcher 
          = new Perl5Matcher();
                  MatchResult result 
          = null;
                  PatternMatcherInput input 
          = null;
                  List
          <String> paramList = new ArrayList<String>();
                  input 
          = new PatternMatcherInput(condition);
                  Pattern pattern 
          = compiler.compile(PATTERN,Perl5Compiler.CASE_INSENSITIVE_MASK);
                  
          while (matcher.contains(input, pattern)){
                      result 
          = matcher.getMatch();
                      input.setBeginOffset(result.length());
                      paramList.add(result.group(
          0));
                  }
                  
          return paramList;
              }
              
              
          /**
               * 獲取業(yè)務(wù)關(guān)聯(lián)查詢(xún)規(guī)則.
               
          */
              
          private List<BizReferenceRule> getBizRelationRule(String bizName){
                  Assert.notNull(bizName, 
          "業(yè)務(wù)名稱(chēng)不能為空,bizName is NULL。");
                  
                  
          //配置定義未加載到內(nèi)存時(shí),讀取配置文件
                  if(ruleMaps == null){
                      parseRuleConfig();
                      
          if(ruleMaps == nullreturn null;
                  }
                  
                  
          return ruleMaps.get(bizName);
              }
              
              
          /**
               * 讀取業(yè)務(wù)關(guān)聯(lián)規(guī)則配置文件
               
          */
              @SuppressWarnings(
          "unchecked")
              
          private synchronized void parseRuleConfig(){
                  
          if(ruleMaps != null){
                      
          return;
                  }
                  
                  
          //解析業(yè)務(wù)引用定義文件.
                   
              }
              
              
          /**
               * 讀取Xml文檔
               * 
          @return
               
          */
              
          private Document getXmlDocument(){
                  InputStream is 
          = null;
                  
          try {
                      ClassLoader loader 
          = Thread.currentThread().getContextClassLoader();
                      is 
          = loader.getResourceAsStream(CFG_FILE);
                      SAXBuilder sb 
          = new SAXBuilder();
                      
          return sb.build(new BufferedInputStream(is));
                  }
                  
          catch(Exception ex) {
                      logger.error(
          "讀取配置文件錯(cuò)誤. file:"+CFG_FILE, ex);
                      
          return null;
                  }
                  
          finally {
                      
          try {
                          
          if(is != null){
                              is.close();
                              is 
          = null;
                          }
                      }
                      
          catch(Exception ex) {
                          logger.error(ex);
                      }
                  }
              }

               
          }

          其他的一些可選處理方法:
          b. 在客戶(hù)表增加引用計(jì)數(shù)字段;
          需額外維護(hù)引用計(jì)數(shù)字段,在引用的業(yè)務(wù)邏輯增加或刪除記錄時(shí),需對(duì)該字段的數(shù)值進(jìn)行更新。適用于需要直接查詢(xún)記錄被引用次數(shù)的場(chǎng)景,但在集群環(huán)境下,需注意并發(fā)問(wèn)題。
          posted on 2009-07-14 14:42 josson 閱讀(389) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): java 開(kāi)發(fā)
          <2009年7月>
          2829301234
          567891011
          12131415161718
          19202122232425
          2627282930311
          2345678

          常用鏈接

          留言簿(3)

          隨筆分類(lèi)

          隨筆檔案

          收藏夾

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 安龙县| 双桥区| 鹤峰县| 九寨沟县| 连平县| 佛冈县| 西昌市| 大丰市| 盈江县| 石景山区| 阜阳市| 彝良县| 泾源县| 延寿县| 孟州市| 于都县| 东丰县| 马鞍山市| 双鸭山市| 太谷县| 泽州县| 新乐市| 正安县| 安乡县| 大洼县| 通渭县| 潮安县| 政和县| 土默特左旗| 瓮安县| 乌拉特前旗| 襄汾县| 广饶县| 昌吉市| 广平县| 德州市| 宣汉县| 开远市| 凉山| 通河县| 定陶县|