对于JDBC操作的一些想法

    今天无意间写了一个JDBC关闭的方法,出了一个小小的问题,但却暴露了一个很严重的问题,于是我必须记下。

先请大家比较一下下面两个JDBC关闭方法: 

方法一:

  1. public static void closeDataConnection(ResultSet rs, PreparedStatement ps, 
  2.             Connection conn) 
  3.     { 
  4.         try 
  5.         { 
  6.             if (null != rs) 
  7.             { 
  8.                 rs.close(); 
  9.             } 
  10.         } 
  11.         catch (SQLException e) 
  12.         { 
  13.             // TODO Auto-generated catch block 
  14.             e.printStackTrace(); 
  15.         } 
  16.          
  17.         try 
  18.         { 
  19.             if (null != ps) 
  20.             { 
  21.                 ps.close(); 
  22.             } 
  23.         } 
  24.         catch (SQLException e) 
  25.         { 
  26.             e.printStackTrace(); 
  27.         } 
  28.          
  29.         try 
  30.         { 
  31.             if (null != conn) 
  32.             { 
  33.                 conn.close(); 
  34.             } 
  35.         } 
  36.         catch (SQLException e) 
  37.         { 
  38.             e.printStackTrace(); 
  39.         } 
  40.     } 

方法二: 

  1. public static void closeDataConnection(ResultSet rs, PreparedStatement ps, 
  2.             Connection conn) 
  3.     { 
  4.  
  5.         try 
  6.         { 
  7.             if (null != rs) 
  8.             { 
  9.                 rs.close(); 
  10.             } 
  11.         } 
  12.         catch (SQLException e) 
  13.         { 
  14.             // TODO Auto-generated catch block 
  15.             e.printStackTrace(); 
  16.         } 
  17.         finally 
  18.         { 
  19.             try 
  20.             { 
  21.                 if (null != ps) 
  22.                 { 
  23.                     ps.close(); 
  24.                 } 
  25.             } 
  26.             catch (SQLException e) 
  27.             { 
  28.                 e.printStackTrace(); 
  29.             } 
  30.             finally 
  31.             { 
  32.                 try 
  33.                 { 
  34.                     if (null != conn) 
  35.                     { 
  36.                         conn.close(); 
  37.                     } 
  38.                 } 
  39.                 catch (SQLException e) 
  40.                 { 
  41.                     e.printStackTrace(); 
  42.                 } 
  43.             } 
  44.         } 
  45.     } 

我想问的是,这两种写法有什么区别,或者说哪个更好!以前我一直认为方法二是最好的,认为在finally{......}中嵌套写的方式更加保险,因为不管什么情况下里面的代码都会被执行;认为方法一只要try{......}中抛了异常,则当前及其以后的代码都不会执行。如果你认同我的观点,那么你也同样掉进了我以前的思维中了。

好吧!我现在告诉你,这两个方法都对,并且没什么区别!

原因,是我以前理解错了。我们都知道异常有checked 异常和unChecked 异常之分。所有继承.Exception 的异常都属于checked异常。所有继承RuntimeException的异常都属于unChecked异常。而对于checked异常,我们通常采用两种方式处理。

方式一:向外抛异常,也就是在方法后加上throws (xxx )Exception。这种方式,报异常的代码及以后的代码都不会再执行了。

方式二:通过try{......}catch{......}finally{......}块的方式,将会报异常的代码放在try{}块中,catch{}块负责处理异常,finally{}块作一些善后工作。但是我们往往忽略了最重要的细节,如果try{.....}中代码报了异常,系统首先会执行catch{}finally{}中的代码,然而在try{......}中报异常的代码及以后的代码都不会再执行了(注意了这里指的是在try{}中的代码),但是try{......}catch{......}finally{......}以外的后面的代码依旧会执行。当然,前提是你在catch{......}块中没使用throw (xxx )Exception语句人为的向外抛异常;如果使用了则与方式一一样,但是只会执行catch{}finally{}中的代码。

如些,上面两种方式的JDBC关闭写法就没有什么区别了。但是这样的写法实际上并没有对异常进行任何的处理。换言之,这种关闭异常的处理,我们程序员也是无能为力的,大多数都是向外抛,由调用此方法的人去处理。这种情形下最顶层的人,就会因为要处理多种异常而忽略原始的错误不利于程序排错。

这里还有个更重要的地方,因为每个人的编码习惯不一样,处理异常的方式也不一样,就很容易造成"异常丢失"的情况。这样一来,系统真正的错误就被掩盖掉了,这对于程序员来说可就是噩梦了。

异常丢失的情况有多种,这里我讲主要的两种情况。

一.人为的情况,主要是程序员捕获了异常后,向外抛出自定义异常,这样上一层的人也就看不到原始的异常了。 

代码好下:

  1. class MyException extends Exception 
  2.     public MyException() 
  3.     { 
  4.         super(); 
  5.     } 
  6.      
  7.     public MyException(String mes) 
  8.     { 
  9.         super(mes); 
  10.     } 
  11. }

测试方法

  1. public void myExceptionTest() throws MyException 
  2.     { 
  3.         try 
  4.         { 
  5.             throw new Exception(); 
  6.         } 
  7.         catch (Exception e) 
  8.         { 
  9.             // TODO: handle exception 
  10.             throw new MyException(); 
  11.         } 
  12.     }

二.异常覆盖,就是在try{......}catch{......}finally{......}块中,如果catch{}中有向外抛出的异常A,而在finally{}中同样有try{......}catch{......}块同样抛出一个异常B。这个时候上一层的人处理时就只能看到抛出的异常B,也就是B异常覆盖掉了A异常 

代码好下: 

  1. public void dothing() throws Exception 
  2.     { 
  3.         try 
  4.         { 
  5.             throw new Exception("A"); 
  6.         } 
  7.         catch (Exception e) 
  8.         { 
  9.             // TODO: handle exception 
  10.             throw e; 
  11.         } 
  12.         finally 
  13.         { 
  14.             try 
  15.             { 
  16.                 throw new Exception("B"); 
  17.             } 
  18.             catch (Exception e2) 
  19.             { 
  20.                 // TODO: handle exception 
  21.                 throw e2; 
  22.             } 
  23.              
  24.         } 
  25.     } 
 

不过具体如何处理异常才是最完美的呢!这个只能说是根据你的业务需求了,不同的处理方式是对应你的系统业务流程的。下面推荐别人写的一篇如何处理异常的文章,写得不错希望大家看一下。

http://fashion.iteye.com/blog/434359