<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      歡迎大家下載試用折桂單點(diǎn)登錄系統(tǒng), https://www.zheguisoft.com

      編程經(jīng)驗(yàn)點(diǎn)滴----避免在數(shù)據(jù)庫訪問函數(shù)中使用 try catch

      看到很多數(shù)書中的代碼示例,都在數(shù)據(jù)庫訪問函數(shù)中使用 try catch,誤導(dǎo)初學(xué)者,很是痛心。

      我們來分析一個常見的函數(shù)(來自國內(nèi)某些大公司的代碼,反面例子,不可仿效),

       1     public int updateData(String sql)     {
       2         int resultRow = 0;         
       3         try{
       4             Connection con = ...
       5             statement = con.createStatement();             
       6             resultRow = statement.executeUpdate(sql);
       7             ...                      
       8         } catch (SQLException e) {
       9             e.printStackTrace();         
      10         }                   
      11         return resultRow;     
      12     } 

       

       這里所說的函數(shù)問題在于,在這樣的調(diào)用情況下會有問題(請發(fā)言者仔細(xì)看看這塊偽代碼):
      1) begin database transaction
      2) updateData("update user set last_active_time = ...");
      3) updateData("insert into ....");
      3) ftpSend();
      3) sendMail();
      4) commit();


      updateData() 內(nèi)部就 try catch 或者 commit/rollback ,問題大了!

       

      這里的問題很多:

      a) SQL 執(zhí)行出錯后,簡單地輸出到控制臺。沒有把出錯信息,返回或者通過 throw Exception 拋出。結(jié)果很可能是, SQL 運(yùn)行出錯,界面上卻提示“操作成功”。

      b) 如果代碼連續(xù)執(zhí)行多個 update/delete,放在一個 transaction 中。SQL 執(zhí)行出錯后,SQLException 被 catch 住,transaction 控制代碼,無法 rollback。

      c) 當(dāng)然還有 SQL 注入問題。這里應(yīng)該用 PreparedStatement。

       

      如果要避免代碼“代碼中運(yùn)行出錯,界面上卻提示:操作成功”的問題,則應(yīng)該避免在數(shù)據(jù)庫訪問函數(shù)中使用 try catch。更進(jìn)一步的,在工具類、dao、service 代碼中,都應(yīng)該禁止用  try catch。

      那么,  try catch 應(yīng)該放在哪里呢?

      1) 如果是單機(jī)版程序,出錯信息應(yīng)該提示給用戶,try catch 放在事件響應(yīng)函數(shù)中。當(dāng)然了,如果用 transaction , 也在這里 begin/commit/rollback。

      2) 如果是 Web MVC 程序,出錯信息應(yīng)該提示給用戶,try catch 放在 URL 相應(yīng)的事件響應(yīng) java/C# 代碼中。當(dāng)然了,如果用 transaction , 也在這里 begin/commit/rollback。如果是 Java EE 程序,建議在 filter 中,也放一個 try catch,作為全局的 exception 控制,防止萬一有人在 URL 相應(yīng)的事件響應(yīng) java/C# 代碼中漏寫了try catch 。出錯信息也要放在界面上提示給用戶看。

      3) 如果是定時(shí)任務(wù),try catch 應(yīng)放在定時(shí)任務(wù)類里,當(dāng)定時(shí)任務(wù)類調(diào)用 dao/service/工具類的時(shí)候,被調(diào)用的函數(shù)都不應(yīng)該有 try catch。出錯信息應(yīng)該記錄在日志中。

      4) 如果不用 MVC 的 jsp/asp.net 程序,try catch 怎么處理,就很麻煩。建議不要用這種軟件架構(gòu)。

       

      我覺得正確的代碼應(yīng)該是這樣的:

      import java.sql.Connection;
      import java.sql.PreparedStatement;
      import java.sql.SQLException;
      import java.util.List;
      
      import org.apache.commons.dbutils.DbUtils;
      
      public class MyJdbcUitls {
          public int updateData(Connection con, String sql, List<Object> paramValueList) throws SQLException {
              // int resultRow = 0; try{
              // Connection con = ...
              // statement = con.createStatement();
              // resultRow = statement.executeUpdate(sql);
              // ... } catch (SQLException e) {
              // e.printStackTrace(); }
              // return resultRow; }}
              PreparedStatement ps = null;
              try {
                  ps = con.prepareStatement(sql);
                  if (paramValueList != null) {
                      for (int i = 0; i < paramValueList.size(); i++) {
                          setOneParameter(i, ps, paramValueList.get(i));
                      }
                  }
      
                  int count = ps.executeUpdate();
                  return count;
              } finally {
                  DbUtils.closeQuietly(ps);
              }
          }
      }

      注意:

      之所以要把 connection 從外面?zhèn)魅耄驗(yàn)閷戇@個 update 的函數(shù)時(shí),還不能確定,實(shí)際業(yè)務(wù)邏輯,是一個 update 函數(shù)就是一個 transaction,還是多個 update/delete 組合在一起,做一個 transaction。

       

      補(bǔ)充:

      數(shù)據(jù)庫事務(wù)控制,應(yīng)該從數(shù)據(jù)庫訪問層中獨(dú)立出來,這里是比較正確的控制流程:

      用戶點(diǎn)擊 -- 數(shù)據(jù)庫事務(wù)控制層 --- 調(diào)用一個或者多個數(shù)據(jù)訪問層函數(shù) ---- 代碼返回到數(shù)據(jù)庫事務(wù)控制層,決定 commit/rollback。

       

      這樣做的原因在于:無法避免用戶在代碼中連續(xù)調(diào)用多個數(shù)據(jù)訪問層函數(shù),如果在每個數(shù)據(jù)訪問層函數(shù)中,commit/rollback,會造成整個操作有多個數(shù)據(jù)庫事務(wù),以下是錯誤的流程:

      用戶點(diǎn)擊 --  調(diào)用一個或者多個數(shù)據(jù)訪問層函數(shù)(每個函數(shù)中有 commit/rollback)。

       

      可以寫一個這樣類 JdbcTransactionUtils, 其中包含的函數(shù):

          public static void doWithJdbcTransactionDefaultCommit(SqlRunnable run, Connection con) {
              doWithJdbcTransactionNoCommitRollback(run, con);
              try {
                  con.commit();
              } catch (Exception e) {
                  Log log = LogFactory.getLog(JdbcTransactionUtils.class);
                  log.error(e.getMessage(), e);
                  try {
                      con.rollback();
                  } catch (Exception err) {
                      log.error(err.getMessage(), err);
                  }
                  throw new NestableRuntimeException(e.getMessage(), e);
              }
          }

      要避免把 commit/rollback 做成公共函數(shù),因?yàn)槟菢樱渌绦騿T一不小心漏掉了什么,就有問題了。寫公共函數(shù),要做到易用、不易被錯用。

      上面的數(shù)據(jù)庫事務(wù)控制函數(shù)可以做到。

      然而,這樣還不算完美。畢竟,馬虎的程序員,還是可以在一個 click 中調(diào)用多個數(shù)據(jù)庫事務(wù)控制層,也就是調(diào)用多個 JdbcTransactionUtils.doWithJdbcTransactionDefaultCommit(), 結(jié)果如下:

       

      用戶點(diǎn)擊 -- 數(shù)據(jù)庫事務(wù)控制層函數(shù)1 --- 調(diào)用一個或者多個數(shù)據(jù)訪問層函數(shù) ---- 代碼返回到數(shù)據(jù)庫事務(wù)控制層,決定 commit/rollback -- 數(shù)據(jù)庫事務(wù)控制層函數(shù)2 --- 調(diào)用一個或者多個數(shù)據(jù)訪問層函數(shù) ---- 代碼返回到數(shù)據(jù)庫事務(wù)控制層,決定 commit/rollback

      還是不好。

       

      實(shí)際上,我們期望的是,每次用戶點(diǎn)擊,后臺都應(yīng)該是一個數(shù)據(jù)庫 transaction,因此,我的意思是,數(shù)據(jù)庫事務(wù)控制代碼,要和 web 層的后臺處理代碼(比如 struts 的 action ,  asp.net 頁面對應(yīng)的 .cs 文件),合并掉,并在此處理 try catch。至于其他被調(diào)用的函數(shù),比如數(shù)據(jù)庫訪問函數(shù),比如工具類,都不要 try catch。畢竟,數(shù)據(jù)庫訪問函數(shù),比如工具類,都可能被多個地方的代碼調(diào)用,如果在里面寫 try catch, 如何寫 try catch 達(dá)到所有調(diào)用的模塊都滿意,是很難做到的。

       

      最后我認(rèn)為合理的流程如下:

      用戶點(diǎn)擊 -- 用戶點(diǎn)擊處理程序(struts action/asp.net 頁面.cs),包含 try catch,包含數(shù)據(jù)庫事務(wù)控制 --- 調(diào)用一個或者多個數(shù)據(jù)訪問層函數(shù)(無 try catch) --- 調(diào)用一個或者多個工具類函數(shù)(無 try catch)。

       
      posted @ 2012-05-04 14:22  杰克倫敦塵  Views(11085)  Comments(140)    收藏  舉報(bào)
      歡迎大家下載試用折桂單點(diǎn)登錄系統(tǒng), https://www.zheguisoft.com
      主站蜘蛛池模板: 亚洲成a人片在线观看日本| 国内精品人妻无码久久久影院导航 | 中文字幕日韩有码一区| 免费网站看av片| 粗大的内捧猛烈进出小视频| 日韩不卡在线观看视频不卡| 精品久久一线二线三线区| 亚洲男人AV天堂午夜在| 强奷乱码中文字幕| 亚洲精品国产精品国在线| 欧美大bbbb流白水| 激情内射亚洲一区二区三区| 中文字幕丰满乱子无码视频| 少妇精品视频一码二码三| 亚洲欧洲日韩国内高清| 灵宝市| 热久久美女精品天天吊色| 东方av四虎在线观看| 中文字幕色av一区二区三区| 欧美视频网站www色| 仙桃市| 免费人成年激情视频在线观看| 中文字幕亚洲无线码一区女同| 亚洲国产片一区二区三区| 亚洲AV无码精品色午夜果冻 | 亚洲肥熟女一区二区三区| 精品一区精品二区制服| 秋霞AV鲁丝片一区二区| 无码专区视频精品老司机| 真人无码作爱免费视频| 国产三级a三级三级| free性开放小少妇| 午夜国产小视频| 色欲综合久久中文字幕网| 久久精品蜜芽亚洲国产av| 人妻少妇精品中文字幕| 不卡一区二区国产在线| 国产成人8X人网站视频| 国产精品中文字幕二区| 国产偷国产偷亚洲高清午夜| 亚洲 都市 无码 校园 激情 |