对于JDBC操作的一些想法
今天无意间写了一个JDBC关闭的方法,出了一个小小的问题,但却暴露了一个很严重的问题,于是我必须记下。
先请大家比较一下下面两个JDBC关闭方法:
方法一:
- public static void closeDataConnection(ResultSet rs, PreparedStatement ps,
- Connection conn)
- {
- try
- {
- if (null != rs)
- {
- rs.close();
- }
- }
- catch (SQLException e)
- {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- try
- {
- if (null != ps)
- {
- ps.close();
- }
- }
- catch (SQLException e)
- {
- e.printStackTrace();
- }
- try
- {
- if (null != conn)
- {
- conn.close();
- }
- }
- catch (SQLException e)
- {
- e.printStackTrace();
- }
- }
方法二:
- public static void closeDataConnection(ResultSet rs, PreparedStatement ps,
- Connection conn)
- {
- try
- {
- if (null != rs)
- {
- rs.close();
- }
- }
- catch (SQLException e)
- {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- finally
- {
- try
- {
- if (null != ps)
- {
- ps.close();
- }
- }
- catch (SQLException e)
- {
- e.printStackTrace();
- }
- finally
- {
- try
- {
- if (null != conn)
- {
- conn.close();
- }
- }
- catch (SQLException e)
- {
- e.printStackTrace();
- }
- }
- }
- }
我想问的是,这两种写法有什么区别,或者说哪个更好!以前我一直认为方法二是最好的,认为在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关闭写法就没有什么区别了。但是这样的写法实际上并没有对异常进行任何的处理。换言之,这种关闭异常的处理,我们程序员也是无能为力的,大多数都是向外抛,由调用此方法的人去处理。这种情形下最顶层的人,就会因为要处理多种异常而忽略原始的错误不利于程序排错。
这里还有个更重要的地方,因为每个人的编码习惯不一样,处理异常的方式也不一样,就很容易造成"异常丢失"的情况。这样一来,系统真正的错误就被掩盖掉了,这对于程序员来说可就是噩梦了。
异常丢失的情况有多种,这里我讲主要的两种情况。
一.人为的情况,主要是程序员捕获了异常后,向外抛出自定义异常,这样上一层的人也就看不到原始的异常了。
代码好下:
- class MyException extends Exception
- {
- public MyException()
- {
- super();
- }
- public MyException(String mes)
- {
- super(mes);
- }
- }
测试方法
- public void myExceptionTest() throws MyException
- {
- try
- {
- throw new Exception();
- }
- catch (Exception e)
- {
- // TODO: handle exception
- throw new MyException();
- }
- }
二.异常覆盖,就是在try{......}catch{......}finally{......}块中,如果catch{}中有向外抛出的异常A,而在finally{}中同样有try{......}catch{......}块同样抛出一个异常B。这个时候上一层的人处理时就只能看到抛出的异常B了,也就是B异常覆盖掉了A异常。
代码好下:
- public void dothing() throws Exception
- {
- try
- {
- throw new Exception("A");
- }
- catch (Exception e)
- {
- // TODO: handle exception
- throw e;
- }
- finally
- {
- try
- {
- throw new Exception("B");
- }
- catch (Exception e2)
- {
- // TODO: handle exception
- throw e2;
- }
- }
- }
不过具体如何处理异常才是最完美的呢!这个只能说是根据你的业务需求了,不同的处理方式是对应你的系统业务流程的。下面推荐别人写的一篇如何处理异常的文章,写得不错希望大家看一下。
转载于:https://blog.51cto.com/carrot1989/842224