seaairland

           

          你擦了嗎?確定擦了?真的確定擦了?

          java的try-finally給我們提供了一個“保證某個動作必然執行”的機會。

          一個try-finally結構,只要try塊開始執行了,finally塊里面的代碼保證執行一次并且只有一次。
          打個比方,就象你上廁所,只要你一旦開始拉了,我們保證無論如何,是拉稀了也好,放屁了也罷,最終你肯定是擦了屁股走出衛生間。


          應用try-finally,我們可以在異常滿天飛的程序里保證我們的關鍵資源被按時正確清理。一個最常見的應用就是jdbc的Connection, Statement, ResultSet等。

          但是,我最近驚奇地發現,不知道怎么正確清理資源的人大有人在,即使是一些java老手。

          看一個例子先:

          java代碼:?

          void f(){
          ? Connection conn = ...;
          ? Statement stmt = conn.createStatement();
          ? ResultSet rset = ...;
          ? ...
          }


          典型的jdbc程序。但是也是典型的光著屁股,其臭如蘭地走出廁所的典范。哎,你擦屁股了嗎?
          有的哥們振振有辭:我不用管,我的jdbc driver/我的應用服務器/garbage collector會處理的。
          這是典型的糊涂蛋邏輯。沒有close(),jdbc driver, 應用服務器怎么知道你是拉完了,還是光著屁股出去接個電話先?難不成這driver都智能地會算命了?
          garbage collector倒確實管得了。不過,garbage collector不一定運行啊。你要是有10G得內存,要是你的程序就用了10M,garbage collector說不定就一直睡大覺。而且,就算它管,也許等你光著屁股上班被警察抓起來之后才匆匆趕到,你等的起嗎?


          好,有人說,那我擦,我擦,我擦擦擦。行了吧?


          java代碼:?

          void f(){
          ? Connection conn = ...;
          ? Statement stmt = conn.createStatement();
          ? ResultSet rset = ...;
          ? rset.close();
          ? conn.close();
          ? ...
          }



          呵呵。我的傻哥們,你只擦了靠近后背的那三公分,剩下的嘛,別人看不見你就樂得省土塊兒了是么?

          按jdbc標準,ResultSet, Statement, Connection都要close(),也許有的driver會在Connection關閉的時候同時正確清理ResultSet, Statement,但是,并沒有一條規定讓所有的driver都這么做。
          另外,也許你的Connection是從一個池里面來的,它只是回到池中去,如果你不關閉Statement, ResultSet,下一個拿到這個Connection的人也許就倒霉了!
          做事要有始有終,既然開始擦了,就擦干凈點兒,行不?(那個,誰誰誰,借我個防毒面具先!)


          ok,有個講衛生的小傻子這樣擦:


          java代碼:?

          void f(){
          ? Connection conn = ...;
          ? Statement stmt = conn.createStatement();
          ? ResultSet rset = ...;
          ? rset.close();
          ? stmt.close();
          ? conn.close();
          ? ...
          }



          然后洋洋得意地說:我是好孩子,我天天擦屁屁。


          是啊,多聽話的孩子呀。可惜,某天,這孩子正坐在馬桶上美著呢,媽媽喊了嗓子:二傻子,吃飯啦。
          哦!吃飯。二傻子褲子都沒提就竄出來了,熏得媽媽一個跟頭。

          什么問題,傻子做事一根筋,不能打擾,一旦有異常情況出現,屁股就忘了擦了。



          所以,我這里鄭重提醒大家,請用"try-finally"!它獨有凹槽,防止側漏...(糟了,串臺了)

          是啊,java老手們都不是傻子,都知道用try-finally的,可是,別美,你現在就保不齊擦沒擦屁股呢!


          常見擦法:
          java代碼:?

          void f(){
          ? Connection conn = null;
          ? Statement stmt = null;
          ? ResultSet rset = null;
          ? try{
          ? ? conn = ...;
          ? ? stmt = ...;
          ? ? rset = ...;
          ? ? ...
          ? }
          ? finally{
          ? ? ? if(rset!=null)rset.close();
          ? ? ? if(stmt!=null)stmt.close();
          ? ? ? if(conn!=null)conn.close();

          ? }
          }



          嗯。怎么說呢。挺聰明的。都學會if(xxx!=null)這種傳說中條件判斷的上古絕學了。
          可惜,你屁股大,一張紙不夠,你用了第一張紙,滿意地看著它圓滿地完成了金燦燦的任務,再用第二張,靠,只太薄,破了,一手金燦燦地,象帶了個金戒指。你大怒,起,絕塵而去。于是也忘了第三張紙,
          哥們兒,close()是可以出異常的,你rset關了,stmt.close()出現了異常,但是conn就不管了?


          近日有位室外高人,據說是鬼谷子高徒,鑒于憐我世人,不擦屁股的實多的高尚情操,親手賺寫一本絕世擦功秘籍,其文美,其意高,除了擦不干凈之外,真可以說是稱霸擦林。

          java代碼:?


          void close(Connection conn){
          ? try{
          ? ? if(conn!=null) conn.close();
          ? }
          ? catch(Exception e){
          ? ? e.printStackTrace();
          ? }
          }
          void close(ResultSet rset){
          ? ...
          }
          void close(Statement rset){
          ? ...
          }
          void f(){
          ? Connection conn = null;
          ? Statement stmt = null;
          ? ResultSet rset = null;
          ? try{
          ? ? conn = ...;
          ? ? stmt = ...;
          ? ? rset = ...;
          ? ? ...
          ? }
          ? finally{
          ? ? ?close(rset);
          ? ? ?close(stmt);
          ? ? ?close(conn);

          ? }
          }



          哈,你們不能紙擦破了就不接著擦啊,甚至大而化之,不能擦股用具有了問題就半途而廢呀!

          具信,該高人以此法擦遍天下凡十數載,未有擦而無功者。

          可惜,高人卻忽視了,除了紙會出故障,甚至大而化之,一切擦具(如土塊兒,木條兒,手指)都可能出現故障,還有別的地方也會出故障地!
          除了Exception,還有Error啊,我的高人!如果close(rset)拋了一個Error,你的close(stmt), close(conn)不都歇菜了?

          后來,高人在《絕世武功補遺》里面解釋說:Error代表不可恢復錯誤,說明整個排泄大業都受阻了,所以根本不應該試圖對這種情況做任何處理,你也處理不了(自然也隱含此時你也根本無法擦屁股了的論斷)。任何試圖在這種情況下仍然固執擦屁股的做法都是倒行逆施,螳臂當車,必然被歷史的車輪所攆碎。

          此書一處,天下辟易。其革命性之深遠,難以估量。具有關方面評論,Sun這個公共廁所的try-finally這個工具的設定本身就是不合理的,應該被歷史車輪攆碎的,因為try-finally居然試圖在出現Error的時候去做一些事情!是可忍,孰不可忍?
          可以預見,try-finally將被sun徹底廢棄,并且向廣大公眾做公開道歉以檢討多年來的欺騙造成的惡劣影響。
          另外,公廁的構造也受到質疑,因為一旦有一個拉客在擦的時候某一步無可挽回地失敗(比如,太緊張,手一抖,紙掉到了坑里,又死活伸手撈不著),那么他就大搖大擺不再繼續擦,而如果碰巧此人剛吃了蘿卜,就會把整個廁所里的其它拉客都熏得無法繼續。(想想一個app server吧。你一個程序歇菜,樂得請病假不擦了,別人也跟著倒霉?)


          嘿嘿,那么,你擦了嗎?你肯定你擦了?擦干凈了?

          幸好,我們翻遍上古秘籍,最終在北京山頂洞人的失傳寶典《呼呼,擦!》中發現了一個據稱絕對干凈的擦法,那就是------------

          一下一下擦!

          具體操作辦法如下:

          java代碼:?


          void f(){
          ? finalConnection conn = ...;
          ? try{
          ? ? finalStatement stmt = ...;
          ? ? try{
          ? ? ? finalResultSet rset = ...;
          ? ? ? try{
          ? ? ? ? ...
          ? ? ? }
          ? ? ? finally{rset.close();}
          ? ? }
          ? ? finally{stmt.close();}
          ? }
          ? finally{conn.close();}
          }




          其訣竅就是,每建立一個需要清理的資源,就用一個try-finally來保證它可以被清理掉。

          如此,任何時候,你都是屁股干干靜靜地離開衛生間。


          哪。好多圣人門徒跟我說:這樣一下一下擦,姿勢非常不雅觀(看看那嵌套的try塊吧),有違古禮。我們反對!


          靠,你說孔丑兒古還是山頂洞人古??
          屁股還泛著味兒呢,還拽什么“雅”?

          而且,要是死要面子,也可以拉個簾子,擦的時候別讓人看見嘛。比如:

          java代碼:?


          interface ResultListener{
          ? void call(ResultSet rset);
          }
          class SqlReader{
          void read(ResultListener l){
          ? ? finalConnection conn = ...;
          ? ? try{
          ? ? ? finalStatement stmt = ...;
          ? ? ? try{
          ? ? ? ? finalResultSet rset = ...;
          ? ? ? ? try{
          ? ? ? ? ? l.call(rset);
          ? ? ? ? }
          ? ? ? ? finally{rset.close();}
          ? ? ? }
          ? ? ? finally{stmt.close();}
          ? ? }
          ? ? finally{conn.close();}
          ? }
          }



          這一下一下擦的動作都藏在SqlReader這個簾子里,你直接在ResultListener里面拉不就行了?

          那位高人說了,這太復雜,就為了擦個屁股不值。

          這個嘛,值不值的另說,你那個簡單,就是簡簡單單地擦不干凈屁股。要不您干脆別擦得了,更簡單呢還。反正您出門兒就愣說擦的是Chanel香水兒就是了。有啥比瞪眼兒說白話兒簡單?

          對了, 我還忘了一個條款:
          就是擦屁股的時候按順序擦。誰進廁所的,要讓人家出去。

          “什么狗屁規則?“那位問了。

          這個這個--,啊,你猜猜~~~?

          嗯,對了,是這樣的,上廁所都不著急,姍姍來遲,上課更不著急,更喜歡遲到了,對不對?而誰上課天天遲到早退還不擔心畢業?當然是太子黨了,是不?
          人家都太子黨了,你還不讓人家先出去?活膩味了你?(此處尾音要拉長,而且向上拐)


          反正啊,具體說,ResultSet最后創建,但是要先關。

          Statement其次。Connection最后。


          當然了,也許在你的環境下,次序錯了也沒出事情。但是,咱么吃軟飯的(吃軟件這口飯的)圖啥?不就圖個放心嗎?上廁所圖啥?不就圖個別讓太子黨抓去當兔子嗎?
          也許某個driver對次序不敏感,但是不好說哪天你換個環境就忽然她奶奶的敏感了呢?
          比如吧,你有connection pool, conn.close()把connection返回到connection。

          你要是先conn.close(),好嘛,connection先回到pool了,正好別的線程里面等著要connection,立馬這個connection又給分配出去了。
          這下齊了,你statement, resultset還沒關呢,那邊事故單位領導就找上門了。什么香油油的桌子,什么桐油炸丸子,全給你送來了。這不添堵嗎?

          好在,在我們《呼呼,擦!》寶典中記載的“一下一下擦”神功,老少咸宜,童叟無欺,有道是:法擦大法好,不如法擦冰箱好!

          跑題了。反正是,只要你一個try-finally對應一個資源,你就不可能在次序上出錯。自然而然的就是后入先出的堆棧結構。
          反觀別的擦法,就沒有這個效果,次序如何,全靠你自己掌握。弄錯了,系統也不告訴你。等著吃桐油炸丸子吧。

          這也是我們推廣一下一下擦的一個原因。

          嘖嘖,又跑這兒來推銷你的“擦屁股大法”了呀?不行,你這臭烘烘的(嘿嘿)帖子不反駁可不行。我說你就不能稍稍包裝一下,讓那些個 close 不要拋出異常?你后面那些個更加復雜的問題,都是這一條帶出來的。如果我們可以保證 close 不拋出異常,那么下面這樣的代碼也就足夠了:

          java代碼:?

          void f(){
          ? ...
          ? try{
          ? ? ...
          ? }
          ? finally{
          ? ? ?if(rset != null) close(rset);
          ? ? ?if(stmt != null) close(stmt);
          ? ? ?if(conn != null) close(conn);
          ? }



          OK,我知道你會大叫:“那底層 API 在執行關閉動作的時候拋出的異常怎么辦?”很簡單啊,保存下來,以備將來想要關心這些事情的人隨時檢查。簡單地說就是一個類似 last_error() 這樣的機制。這個很容易實現,而且完全可以放進可復用的框架、庫或是別的什么東西,而不用程序員自己動手。

          這樣做為什么更好、為什么應該這樣做呢?嗯嗯,讓我們先回想一下,當年人們為什么要引入異常這種錯誤處理機制?“長胡子的程序員”應該記得,最主要的原因是為了把錯誤處理的代碼從執行正常邏輯的代碼里面剝離出來,從而讓執行正常邏輯的“主流程”更加清晰,方便閱讀和理解。

          ajoo 你的做法就部分違背了引入異常的初衷。“一下一下擦”,安全性是可以保證了,但是這一段代碼被 try ... finally 分割得支離破碎,完成錯誤處理的代碼和執行正常邏輯的代碼交織在一起。這樣做部分地抵消了引入異常的好處。

          那么規定 close 不能拋出異常會帶來什么問題嗎?完全不會。首先對于 close 而言,前面那位“上古秘笈”的作者有一點是沒說錯,那個錯誤在當時其實是沒法處理的,我們要做的就是把這個錯誤記錄下來,“相信我們的后代比我們有智慧”。與此同時,我們又希望這個錯誤不要干擾正常的函數流程,因為我們還要 close 其他東西。OK,明眼人一望即知,這恰恰就是 last_error() 型錯誤處理機制所做的事情。一方面 close 報告的錯誤被保留了(如果你需要保留多于一個,那么自然也可以保留一個隊列),想要看手紙有沒有破的人一定可以滿足他們的好奇心;另一方面,這里也沒有異常拋出,我們還是可以很平凡地繼續調用后面的 close 。

          科學在發展,世界在進步,怎么擦屁股的方法卻越來越倒退了那?
          我來介紹一下我們公司最新的自動屁股清洗機。
          java代碼:?


          void f(){
          Cleaner cleaner=new Cleaner();
          try
          {
          ? Connection conn = ...;
          ? cleaner.add(conn);
          ? Statement stmt = conn.createStatement();
          ? cleaner.add(stmt );
          ? ResultSet rset = ...;
          ? cleaner.add(rset );
          ? ...
          }
          catch(Exception e)
          {
          throw newRuntimeException("",e);
          }
          finally
          {
          cleaner.cleanAll();
          }
          }




          java代碼:?




          import java.lang.reflect.Method;
          import java.sql.Connection;
          import java.sql.PreparedStatement;
          import java.sql.ResultSet;
          import java.sql.Statement;
          import java.util.HashMap;
          import java.util.Iterator;
          import java.util.Map;
          import java.util.Stack;

          /**
          * @author pufan
          *
          */

          publicfinalclass Cleaner
          {
          ? ? privatefinalstaticMap map = newHashMap()
          ? ? {
          ? ? ? ? {
          ? ? ? ? ? ? put(Connection.class, "close");
          ? ? ? ? ? ? put(Statement.class, "close");
          ? ? ? ? ? ? put(PreparedStatement.class, "close");
          ? ? ? ? ? ? put(ResultSet.class, "close");
          ? ? ? ? }
          ? ? };
          ? ? privatefinalStack garbageContainer = newStack();
          ? ? publicvoid add(Object garbage)
          ? ? {
          ? ? ? ? garbageContainer.add(new Garbage(garbage));
          ? ? }
          ? ? publicvoid cleanAll()
          ? ? {
          ? ? ? ? Throwable throwable = null;
          ? ? ? ? while(garbageContainer.size()>0)
          ? ? ? ? ? ? try
          ? ? ? ? ? ? {
          ? ? ? ? ? ? ? ? Garbage garbage = (Garbage) garbageContainer.pop();
          ? ? ? ? ? ? ? ? garbage.clean();
          ? ? ? ? ? ? }
          ? ? ? ? ? ? catch(Throwable t)
          ? ? ? ? ? ? {
          ? ? ? ? ? ? ? ? if(throwable == null)
          ? ? ? ? ? ? ? ? ? ? throwable = t;
          ? ? ? ? ? ? }
          ? ? ? ? if(throwable != null)
          ? ? ? ? ? ? throw newRuntimeException("error in closing garbage!", throwable);
          ? ? }
          ? ? privatestaticMethod getMethod(Object obj)
          ? ? {
          ? ? ? ? Class clazz = obj.getClass();
          ? ? ? ? String methodName = getMethodName(clazz);
          ? ? ? ? try
          ? ? ? ? {
          ? ? ? ? ? ? return clazz.getMethod(methodName, newClass[0]);
          ? ? ? ? }
          ? ? ? ? catch(Exception e)
          ? ? ? ? {
          ? ? ? ? ? ? throw newRuntimeException("can't find close method by " + obj, e);
          ? ? ? ? }
          ? ? }
          ? ? private static String getMethodName(Class clazz)
          ? ? {
          ? ? ? ? for (Iterator it = map.keySet().iterator(); it.hasNext() ; )
          ? ? ? ? {
          ? ? ? ? ? ? Class c = (Class) it.next();
          ? ? ? ? ? ? if (c.isAssignableFrom(clazz))
          ? ? ? ? ? ? ? ? return (String) map.get(c);
          ? ? ? ? }
          ? ? ? ? return null;
          ? ? }
          ? ? private static class Garbage
          ? ? {
          ? ? ? ? Object obj;
          ? ? ? ? Method method;
          ? ? ? ? Garbage(Object obj)
          ? ? ? ? {
          ? ? ? ? ? ? method = getMethod(obj);
          ? ? ? ? ? ? this.obj=obj;
          ? ? ? ? }
          ? ? ? ? void clean() throws Throwable
          ? ? ? ? {
          ? ? ? ? ? ? method.invoke(obj, new Object[0]);
          ? ? ? ? }
          ? ? }
          }
          樓上的,如果我要在connection 關閉異常的時候print screen,而在statment 關閉異常的時候write log file.
          怎么辦?

          屬于需求變更,這樣解決。

          java代碼:?


          void f(){
          Cleaner cleaner=new Cleaner();
          try
          {
          ? Connection conn = ...;
          ? cleaner.add(conn,new Cleaner.CleanListener()
          ? ? ? ? ? ? ? ? ? ? ? ? {
          ? ? ? ? ? ? ? ? ? ? publicvoid catchClean(Object obj,Throwable t)
          ? ? ? ? ? ? ? ? ? ? {
          ? ? ? ? ? ? ? ? ? ? ? ? System.out.println("打印屏幕");
          ? ? ? ? ? ? ? ? ? ? }
          ? ? ? ? ? ? ? ? ? ? });
          ? Statement stmt = conn.createStatement();
          ? cleaner.add(stmt,new Cleaner.CleanListener()
          ? ? ? ? ? ? ? ? ? ? ? ? {
          ? ? ? ? ? ? ? ? ? ? publicvoid catchClean(Object obj,Throwable t)
          ? ? ? ? ? ? ? ? ? ? {
          ? ? ? ? ? ? ? ? ? ? ? ?logger.log(t);
          ? ? ? ? ? ? ? ? ? ? }
          ? ? ? ? ? ? ? ? ? ? });
          ? ResultSet rset = ...;
          ? cleaner.add(rset );
          ? ...
          }
          catch(Exception e)
          {
          throw newRuntimeException("",e);
          }
          finally
          {
          cleaner.cleanAll();
          }
          }



          java代碼:?


          import java.io.InputStream;
          import java.lang.reflect.Method;
          import java.net.Socket;
          import java.sql.Connection;
          import java.sql.PreparedStatement;
          import java.sql.ResultSet;
          import java.sql.Statement;
          import java.util.HashMap;
          import java.util.Iterator;
          import java.util.Map;
          import java.util.Stack;

          /**
          * @author pufan
          *
          */

          publicfinalclass Cleaner
          {
          ? ? publicstaticinterface CleanListener
          ? ? {
          ? ? ? ? void catchClean(Object obj, Throwable t);
          ? ? }
          ? ? privatefinalstatic CleanListener NONE_LISTENER = new CleanListener()
          ? ? {
          ? ? ? ? publicvoid catchClean(Object obj, Throwable t)
          ? ? ? ? {
          ? ? ? ? }
          ? ? };
          ? ? privatefinalstaticMap map = newHashMap()
          ? ? {
          ? ? ? ? {
          ? ? ? ? ? ? put(Connection.class, "close");
          ? ? ? ? ? ? put(Statement.class, "close");
          ? ? ? ? ? ? put(PreparedStatement.class, "close");
          ? ? ? ? ? ? put(ResultSet.class, "close");
          ? ? ? ? ? ? put(InputStream.class, "close");
          ? ? ? ? ? ? put(Socket.class, "close");
          ? ? ? ? }
          ? ? };
          ? ? privatefinalStack garbageContainer = newStack();
          ? ? publicvoid add(Object garbage)
          ? ? {
          ? ? ? ? garbageContainer.add(new Garbage(garbage, NONE_LISTENER));
          ? ? }
          ? ? publicvoid add(Object garbage, CleanListener listener)
          ? ? {
          ? ? ? ? garbageContainer.add(new Garbage(garbage, listener));
          ? ? }
          ? ? publicvoid cleanAll()
          ? ? {
          ? ? ? ? Throwable throwable = null;
          ? ? ? ? while(garbageContainer.size() > 0)
          ? ? ? ? ? ? try
          ? ? ? ? ? ? {
          ? ? ? ? ? ? ? ? Garbage garbage = (Garbage) garbageContainer.pop();
          ? ? ? ? ? ? ? ? garbage.clean();
          ? ? ? ? ? ? }
          ? ? ? ? ? ? catch(Throwable t)
          ? ? ? ? ? ? {
          ? ? ? ? ? ? ? ? if(throwable == null)
          ? ? ? ? ? ? ? ? ? ? throwable = t;
          ? ? ? ? ? ? }
          ? ? ? ? if(throwable != null)
          ? ? ? ? ? ? if(throwable instanceof Error)
          ? ? ? ? ? ? ? ? throw (Error) throwable;
          ? ? ? ? ? ? else
          ? ? ? ? ? ? ? ? throw newRuntimeException("error in closing garbage!", throwable);
          ? ? }
          ? ? privatestaticMethod getMethod(Object obj)
          ? ? {
          ? ? ? ? Class clazz = obj.getClass();
          ? ? ? ? String methodName = getMethodName(clazz);
          ? ? ? ? try
          ? ? ? ? {
          ? ? ? ? ? ? return clazz.getMethod(methodName, newClass[0]);
          ? ? ? ? }
          ? ? ? ? catch(Exception e)
          ? ? ? ? {
          ? ? ? ? ? ? throw newRuntimeException("can't find close method by " + obj, e);
          ? ? ? ? }
          ? ? }
          ? ? private static String getMethodName(Class clazz)
          ? ? {
          ? ? ? ? for (Iterator it = map.keySet().iterator(); it.hasNext() ; )
          ? ? ? ? {
          ? ? ? ? ? ? Class c = (Class) it.next();
          ? ? ? ? ? ? if (c.isAssignableFrom(clazz))
          ? ? ? ? ? ? ? ? return (String) map.get(c);
          ? ? ? ? }
          ? ? ? ? return null;
          ? ? }
          ? ? private static class Garbage
          ? ? {
          ? ? ? ? Object obj;
          ? ? ? ? Method method;
          ? ? ? ? CleanListener listener;
          ? ? ? ? Garbage(Object obj, CleanListener listener)
          ? ? ? ? {
          ? ? ? ? ? ? method = getMethod(obj);
          ? ? ? ? ? ? this.obj = obj;
          ? ? ? ? ? ? this.listener = listener;
          ? ? ? ? }
          ? ? ? ? void clean() throws Throwable
          ? ? ? ? {
          ? ? ? ? ? ? try
          ? ? ? ? ? ? {
          ? ? ? ? ? ? ? ? method.invoke(obj, new Object[0]);
          ? ? ? ? ? ? }
          ? ? ? ? ? ? catch (Throwable t)
          ? ? ? ? ? ? {
          ? ? ? ? ? ? ? ? listener.catchClean(obj, t);
          ? ? ? ? ? ? ? ? throw t;
          ? ? ? ? ? ? }
          ? ? ? ? }
          ? ? }
          }

          由計劃的擦pipi
          java代碼:?

          Job job = new JdbcCloseJobImpl();
          ? ? ? ? try
          ? ? ? ? {
          ? ? ? ? ? ? Connection conn = ...
          ? ? ? ? ? ? job.addJob(conn);
          ? ? ? ? ? ? Statement sta = ...
          ? ? ? ? ? ? job.addJob(sta);
          ? ? ? ? ? ? ResultSet rs = ..
          ? ? ? ? ? ? job.addJob(rs);
          ? ? ? ? }finally
          ? ? ? ? {
          ? ? ? ? ? ? job.startJob();
          ? ? ? ? }



          java代碼:?

          public? interface Job {

          ? ? public? void startJob()throwsThrowable;

          ? ? publicvoid addJob(Object o);

          }



          java代碼:?

          public class JdbcCloseJobImpl implements Job {
          ? ? private java.util.Stack customerJob = newStack();
          ? ? private java.util.List innerJob = newArrayList();
          ? ? publicvoid startJob()throwsThrowable{
          ? ? ? ? Object o = null;
          ? ? ? ? while((o = customerJob.pop()) != null)
          ? ? ? ? {
          ? ? ? ? ? ? if(o instanceof ResultSet)
          ? ? ? ? ? ? {
          ? ? ? ? ? ? ? ? try{
          ? ? ? ? ? ? ? ? ? ? ((ResultSet)o).close();
          ? ? ? ? ? ? ? ? }catch(Throwable e){
          ? ? ? ? ? ? ? ? ? ? innerJob.add(e);
          ? ? ? ? ? ? ? ? }
          ? ? ? ? ? ? }
          ? ? ? ? ? ? elseif(o instanceof Statement)
          ? ? ? ? ? ? {
          ? ? ? ? ? ? ? ? try{
          ? ? ? ? ? ? ? ? ? ? ((Statement)o).close();
          ? ? ? ? ? ? ? ? }catch(Throwable e){
          ? ? ? ? ? ? ? ? ? ? innerJob.add(e);
          ? ? ? ? ? ? ? ? }
          ? ? ? ? ? ? }
          ? ? ? ? ? ? elseif(o instanceof Connection)
          ? ? ? ? ? ? {
          ? ? ? ? ? ? ? ? try{
          ? ? ? ? ? ? ? ? ? ? ((Connection)o).close();
          ? ? ? ? ? ? ? ? }catch(Throwable e){
          ? ? ? ? ? ? ? ? ? ? innerJob.add(e);
          ? ? ? ? ? ? ? ? }
          ? ? ? ? ? ? }
          ? ? ? ? }


          ? ? ? ? if(innerJob.size() > 0)
          ? ? ? ? {
          ? ? ? ? ? ? throw (Throwable) innerJob.get(0);
          ? ? ? ? }
          ? ? }

          ? ? publicvoid addJob(Object o){
          ? ? ? ? customerJob.push(o);
          ? ? }
          }

          posted on 2006-04-30 20:41 chenhui 閱讀(287) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           

          導航

          統計

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          介紹 IOC

          友情鏈接

          最新隨筆

          搜索

          積分與排名

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 会理县| 郁南县| 介休市| 泉州市| 抚远县| 福泉市| 磴口县| 紫阳县| 黑河市| 衡南县| 德钦县| 博乐市| 湾仔区| 白银市| 南京市| 开阳县| 宣汉县| 大余县| 剑川县| 东阿县| 密山市| 秀山| 聂拉木县| 新龙县| 朝阳县| 洛南县| 洛宁县| 东丰县| 潼关县| 凌海市| 拉孜县| 梁平县| 印江| 五莲县| 昆明市| 西贡区| 宜兰市| 德清县| 青田县| 沂源县| 高唐县|