JDBC經(jīng)典攻堅學習筆記_第1頁
JDBC經(jīng)典攻堅學習筆記_第2頁
JDBC經(jīng)典攻堅學習筆記_第3頁
JDBC經(jīng)典攻堅學習筆記_第4頁
JDBC經(jīng)典攻堅學習筆記_第5頁
已閱讀5頁,還剩11頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、JDBC(Java Data Base Connectivity,java數(shù)據(jù)庫連接),由一些接口和類構成的API。JDBC是J2SE的一部分,由java.sql.javax.sql包組成。JDBC的核心是接口,Driver實現(xiàn)了JDBC的接口。SUN公司設計接口(或者規(guī)范、標準),生產(chǎn)廠商來實現(xiàn)這些接口,即它們各自的Driver。JAVA程序包括JAVA應用程序和小應用程序,主要是根據(jù)JDBC方法實現(xiàn)對數(shù)據(jù)庫的訪問和操作。完成的主要任務有:請求與數(shù)據(jù)庫建立連接;向數(shù)據(jù)庫發(fā)送SQL請求;為結果集定義存儲應用和數(shù)據(jù)類型;查詢結果;處理錯誤;控制傳輸、提交及關閉連接到呢個操作。JDBC管理器為我們

2、提供了一個“驅動程序管理器”,它能夠動態(tài)地管理和維護數(shù)據(jù)庫查詢所需要的所有驅動程序對象,實現(xiàn)JAVA程序與特定驅動程序的連接,從而體現(xiàn)JDBC的“與平臺無關”這一特點。它完成的主要任務有:為特定數(shù)據(jù)庫選擇驅動程序;處理JDBC初始化調用;為每個驅動程序提供JDBC功能的入口;為JDBC調用執(zhí)行參數(shù)等。驅動程序處理JDBC方法,想特定數(shù)據(jù)庫發(fā)送SQL請求,并為JAVA程序獲取結果。在必要的時候,驅動程序可以翻譯或優(yōu)化請求,使SQL請求符合DBMS支持的語言。驅動程序可以完成下列任務:建立與數(shù)據(jù)庫的連接;向數(shù)據(jù)庫發(fā)送請求;用戶程序請求時,執(zhí)行翻譯;將錯誤代碼格式化成標準的JDBC錯誤代碼等。JDB

3、C是獨立于數(shù)據(jù)庫管理系統(tǒng)的,而每個數(shù)據(jù)庫系統(tǒng)均有自己的協(xié)議與客戶機通信,因此,JDBC利用數(shù)據(jù)庫驅動程序來使用這些數(shù)據(jù)庫引擎。JDBC驅動程序有數(shù)據(jù)庫軟件商和第三方的軟件商提供,因此,根據(jù)編程所使用的數(shù)據(jù)庫系統(tǒng)不同,所需要的驅動程序也有所不同。應用程序JDBCDB2 DriverOracleDB2MySQL四類JDBC驅動程序盡管存在數(shù)據(jù)庫語言標準SQL-92,但由于數(shù)據(jù)庫技術發(fā)展的原因,各公司開發(fā)的SQL存在著一定的差異。因此,當我們想要連接數(shù)據(jù)庫并存取其中的數(shù)據(jù)時,選擇適當類型的JDBC驅動程序是非常重要的。目前JDBC驅動程序可細分為四種類型,如下圖所示。不同類型的JDBC驅動程序有著不

4、一樣的特性和使用方法。下面將說明不同類型的JDBC驅動程序之間的差異。類型1:JDBC-ODBC Bridge。這類驅動程序的特色是必須在我們的計算機上事先安裝好ODBC驅動程序,然后通過JDBC-ODBC Bridge的轉換,把JAVA程序中使用的JDBC API轉換成ODBC API,進而通過ODBC來存取數(shù)據(jù)庫。類型2:JDBC-Native API Bridge。同類型1一樣,這類驅動程序也必須在我們的計算機上先安裝好特定的驅動程序(類似ODBC),然后通過JDBC-Native API Bridge的轉換,把JAVA程序中使用的JDBC API轉換成Native API,進而存取數(shù)據(jù)

5、庫。類型3:JDBC-Middleware。必須在安裝數(shù)據(jù)庫管理系統(tǒng)的服務器端加裝軟件(Middleware),中介軟件會負責所有存取數(shù)據(jù)庫時必要的轉換。類型4:Pure JDBC Driver。使用這類驅動程序時無需安裝任何附加的軟件,所有存取數(shù)據(jù)庫的操作都直接有JDBC驅動來完成。用JDBC連接Oracle數(shù)據(jù)庫方法一:在Tomcat中配置Oracle的驅動程序Oracle JDBC驅動程序的位置:H:Oraclejdbclibclasses12.jar將此驅動程序拷貝到Tomcat的安裝目錄的lib文件之中:C:Program Filesapache-tomcat-6.0.14lib此時

6、Tomcat就可以連接到oracle驅動程序Oracle驅動名稱:使用Class.forName()方法加載相應的數(shù)據(jù)庫驅動程序:Class.forName(oracle.jdbc.driver.OracleDriver);oracle.jdbc.driver.OracleDriver我們不必死記,在Oracle驅動程序classes12.jar下面的oralce.jdbc.dreiver包中就可找到相應OracleDriver.class。Oracle連接地址:String URL=”jdbc:oracle:thin::1521:myOracle”; 或者:String U

7、RL=”jdbc:oracle:thin:localhost:1521:myOracle”;Connection ct=DriverManager.getConnection(URL);其中jdbc是協(xié)議,1521是Oracle默認的端口號,myOracle是數(shù)據(jù)庫的名稱與使用JDBC-ODBC類似,只是連接的驅動名稱和驅動地址改變。方法二:JDBC-ODBC Bridge方法Oracle驅動名稱:使用Class.forName()方法加載相應的數(shù)據(jù)庫驅動程序:Class.forName(sun.jdbc.odbc.JdbcOdbcDriver);Oracle連接地址:String URL=”

8、jdbc:odbc:odbcName”;Connection ct=DriverManager.getConnection(URL);其中odbcName是我們設置的要創(chuàng)建的數(shù)據(jù)源。連接數(shù)據(jù)庫的步驟:1、注冊驅動(只做一次)Class.forName(sun.jdbc.odbc.JdbcOdbcDriver);2、建立連接(Connection)String URL=”jdbc:odbc:odbcName”;Connection ct=DriverManager.getConnection(URL,”scott”,”tiger”);數(shù)據(jù)庫連接(Connection)是非常稀有的資源,用完后必須

9、馬上釋放,如果Connection不能及時正確的關閉或釋放將導致系統(tǒng)脫機。Connection的使用原則是盡量晚的創(chuàng)建,盡量早的釋放。3、創(chuàng)建執(zhí)行SQL的語句(Statement)Statement st=ct.createStatement();4、執(zhí)行語句(ResultSet)ResultSet rs=st.executeQuery(“select * from emp”);5、處理執(zhí)行結果While(rs.next()System.out.println(“用戶名:”+rs.getString(2);6、關閉和釋放資源rs.close();sm.close();ct.close();為了

10、確保JDBC資源不在出現(xiàn)異常或錯誤等情況下被不正常關閉,我們應該在用完JDBC資源之后關閉且釋放他們。JDBC連接池提供了JDBC連接定義和數(shù)目有限的連接,如果數(shù)量不夠,就需要長時間等待。不正常關閉JDBC連接會導致等待回收無效的JDBC連接。只有正常的關閉和釋放JDBC連接,JDBC資源才可以被快速的重用,使性能得到改善。為了確保構建的代碼在所有的情況下,甚至是異常和錯誤條件下,都能關閉和釋放JDBC資源。一下代碼顯示了JDBC資源的獲得和使用都封裝在“Try-Catch-Finally”結構中。其中,在finally子句中處理JDBC資源的關閉,使所有情況下關閉都將發(fā)生。為了簡潔,此代碼中

11、只把異常拋出并為對異常進行處理。public static void main(String args) throws ExceptionString url=jdbc:oracle:thin:localhost:1521:myOracle;Connection ct=null;Statement st=null;ResultSet rs=null;try /1.加載驅動Class.forName(oracle.jdbc.driver.OracleDriver);/2.得到連接ct=DriverManager.getConnection(url, scott,tiger);/創(chuàng)建執(zhí)行的SQL語

12、句st=ct.createStatement();/執(zhí)行語句rs=st.executeQuery(select * from emp);/處理執(zhí)行結果while(rs.next()/用戶名System.out.println(用戶名:+rs.getString(2); finallytryif(rs!=null)rs.close();finallytryif(st!=null)st.close();finallyif(ct!=null)ct.close();代碼優(yōu)化:新建一個(public final)工具類JdbcUtils,把優(yōu)化后的代碼都放在這個類里面。由于這個類不需要構造實例,因此我們

13、我們定義一個private的構造方法,這樣別人就無法new一個對象了。訪問這個類有兩種方式:一種是單例模式,但是比較復雜;另一種是提供一些靜態(tài)方法。1、由于驅動只需要注冊一次,我們知道靜態(tài)代碼塊只有類被裝載到虛擬機的時候才被執(zhí)行一次,因此,我們把注冊驅動語句放在一個靜態(tài)的代碼塊中。statictry Class.forName(jdbc:odbc:wanghao); catch (ClassNotFoundException e) throw new ExceptionInInitializerError(e);2、當我們的增、刪、改、查的操作很多時,如果程序中每個方法都有URL、用戶名和密碼

14、,我們修改起來就會很麻煩。我們也需要對這一塊優(yōu)化,把他們放到JdbcUtils中,這樣就可以實現(xiàn)“一改全改”。private static String url=sun.jdbc.odbc.JdbcOdbcDriver;private static String user=scott;private static String password=tiger;3、建立連接語句我們也可以把它放在JdbcUtils的一個靜態(tài)方法中,當我們需要鏈接時,我們就到JdbcUtils中去取。public static Connection getConnection() throws SQLExceptio

15、nreturn DriverManager.getConnection(url, user, password);4、對釋放資源部分進行優(yōu)化。public static void free(ResultSet rs,Statement st,Connection ct)tryif(rs!=null)rs.close();catch(SQLException e)e.printStackTrace();finallytryif(st!=null)st.close();catch(SQLException e)e.printStackTrace();finallyif(ct!=null)try c

16、t.close(); catch (SQLException e) e.printStackTrace();完整程序代碼如下所示:package com.wanghao.jdbc;import java.sql.Connection;import java.sql.ResultSet;import java.sql.Statement;public class Base /* * param args * throws Exception */public static void main(String args) throws Exception / TODO Auto-generated

17、method stubtest();static void test()throws ExceptionConnection ct=null;Statement st=null;ResultSet rs=null;try /2.得到連接ct=JdbcUtils.getConnection();/創(chuàng)建執(zhí)行的SQL語句st=ct.createStatement();/執(zhí)行語句rs=st.executeQuery(select * from emp);/處理執(zhí)行結果while(rs.next()/用戶名System.out.println(用戶名:+rs.getString(2); finallyJ

18、dbcUtils.free(rs, st, ct);/工具類JdbcUtilsimport java.sql.Statement;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;public final class JdbcUtils private JdbcUtils()/private static String url=jdbc:odbc:wanghao;private static String url=jdbc

19、:oracle:thin:localhost:1521:myOracle;private static String user=scott;private static String password=tiger;statictry /Class.forName(sun.jdbc.odbc.JdbcOdbcDriver);Class.forName(oracle.jdbc.driver.OracleDriver); catch (ClassNotFoundException e) throw new ExceptionInInitializerError(e);public static Co

20、nnection getConnection() throws SQLExceptionreturn DriverManager.getConnection(url, user, password);public static void free(ResultSet rs,Statement st,Connection ct)tryif(rs!=null)rs.close();catch(SQLException e)e.printStackTrace();finallytryif(st!=null)st.close();catch(SQLException e)e.printStackTra

21、ce();finallyif(ct!=null)try ct.close(); catch (SQLException e) e.printStackTrace();SQL注入,PreparedStatement和Statement 在SQL中包含特殊字符或SQL的關鍵字(如:or 1 or)時Statement將出現(xiàn)不可預料的結果(出現(xiàn)異常或查詢的結果不正確),可用PreparedStatement來解決。PreparedStatement(從Statement擴展而來)相對Statement的優(yōu)點:1、沒有SQL注入的問題。2、Statement會使數(shù)據(jù)庫頻繁編譯SQL,可能會造成數(shù)據(jù)庫緩

22、沖區(qū)溢出。3、數(shù)據(jù)庫和驅動可以對PreparedStatement進行優(yōu)化(只有在相關聯(lián)的數(shù)據(jù)庫連接沒有關閉的情況下有效)。為什么要始終使用PreparedStatement代替Statement?一.代碼的可讀性和可維護性.雖然用PreparedStatement來代替Statement會使代碼多出幾行,但這樣的代碼無論從可讀性還是可維護性上來說.都比直接用Statement的代碼高很多檔次,大家可以通過下面的例子:stmt.executeUpdate(insert into tb_name (col1,col2,col2,col4) values (+var1+,+var2+,+var3+

23、,+var4+);注意Statement和PreparedStatement語句上的區(qū)別:Statement是在執(zhí)行的時候才傳入SQL語句,而PreparedStatement在創(chuàng)建的時候就已經(jīng)傳入了SQL語句。perstmt = con.prepareStatement(insert into tb_name (col1,col2,col2,col4) values (?,?,?,?);perstmt.setString(1,var1);perstmt.setString(2,var2);perstmt.setString(3,var3);perstmt.setString(4,var4);

24、perstmt.executeUpdate();二.PreparedStatement盡最大可能提高性能.每一種數(shù)據(jù)庫都會盡最大努力對預編譯語句提供最大的性能優(yōu)化.因為預編譯語句有可能被重復調用.所以語句在被DB的編譯器編譯后的執(zhí)行代碼被緩存下來,那么下次調用時只要是相同的預編譯語句就不需要編譯,只要將參數(shù)直接傳入編譯過的語句執(zhí)行代碼中(相當于一個涵數(shù))就會得到執(zhí)行.這并不是說只有一個Connection中多次執(zhí)行的預編譯語句被緩存,而是對于整個DB中,只要預編譯的語句語法和緩存中匹配.那么在任何時候就可以不需要再次編譯而可以直接執(zhí)行.而statement的語句中,即使是相同一操作,而由于每次

25、操作的數(shù)據(jù)不同所以使整個語句相匹配的機會極小,幾乎不太可能匹配.比如:insert into tb_name (col1,col2) values (11,22);insert into tb_name (col1,col2) values (11,23);即使是相同操作但因為數(shù)據(jù)內容不一樣,所以整個語句本身不能匹配,沒有緩存語句的意義.事實是沒有數(shù)據(jù)庫會對普通語句編譯后的執(zhí)行代碼緩存.當然并不是所有預編譯語句都一定會被緩存,數(shù)據(jù)庫本身會用一種策略,比如使用頻度等因素來決定什么時候不再緩存已有的預編譯結果.以保存有更多的空間存儲新的預編譯語句.三.最重要的一點是極大地提高了安全性.即使到目前為

26、止,仍有一些人連基本的惡義SQL語法都不知道.String sql = select * from tb_name where name= +varname+ and passwd=+varpasswd+;如果我們把 or 1 = 1作為varpasswd傳入進來.用戶名隨意,看看會成為什么?select * from tb_name = 隨意 and passwd = or 1 = 1;因為1=1肯定成立,所以可以任何通過驗證.更有甚者:把;drop table tb_name;作為varpasswd傳入進來,則:select * from tb_name = 隨意 and passwd =

27、 ;drop table tb_name;有些數(shù)據(jù)庫是不會讓你成功的,但也有很多數(shù)據(jù)庫就可以使這些語句得到執(zhí)行.而如果你使用預編譯語句.你傳入的任何內容就不會和原來的語句發(fā)生任何匹配的關系.只要全使用預編譯語句,你就用不著對傳入的數(shù)據(jù)做任何過慮.而如果使用普通的statement,有可能要對drop,;等做費盡心機的判斷和過慮.JDBC中的數(shù)據(jù)類型與日期問題Java.util.Date.getTime()返回自1970年1月1日 00:00:00 GMT 以來此 Date 對象表示的毫秒數(shù)。public static void main(String args) throws SQLExcep

28、tion create(4,zhushidong,new Date(),5500.00f);static void create(int id,String name,Date birthday,float money) throws SQLException Util包里面的Date類型!Connection ct=null;PreparedStatement ps=null;ResultSet rs=null;tryct=JdbcUtils.getConnection();String sql=insert into wanghao(id,name,birthday,money)value

29、s (?,?,?,?);ps=ct.prepareStatement(sql);ps.setInt(1, id);ps.setString(2, name);ps.setDate(3, new java.sql.Date(birthday.getTime();ps.setFloat(4, money);int i=ps.executeUpdate(); System.out.println(i=+i);finallyJdbcUtils.free(rs, ps, ct);Util包里面的Date類型是sql包里Date類型的父類,由程序很容已看出我們企圖把一個父類賦值給一個子類,這是不允許的,反

30、過來一個子類賦值給一個父類則是可以的。因此我們需要做這樣的new java.sql.Date(birthday.getTime()一個轉換。J2EE 三層架構所謂的三層開發(fā)就是將系統(tǒng)的整個業(yè)務應用劃分為表示層業(yè)務邏輯層數(shù)據(jù)訪問層,這樣有利于系統(tǒng)的開發(fā)、維護、部署和擴展。分層是為了實現(xiàn)“高內聚、低耦合”。采用“分而治之”的思想,把問題劃分開來各個解決,易于控制,易于延展,易于分配資源。表示層:負責直接跟用戶進行交互,一般也就是指系統(tǒng)的界面,用于數(shù)據(jù)錄入,數(shù)據(jù)顯示等。意味著只做與外觀顯示相關的工作,不屬于他的工作不用做。 業(yè)務邏輯層:用于做一些有效性驗證的工作,以更好地保證程序運行的健壯性。如完成

31、數(shù)據(jù)添加、修改和查詢業(yè)務等;不允許指定的文本框中輸入空字符串,數(shù)據(jù)格式是否正確及數(shù)據(jù)類型驗證;用戶的權限的合法性判斷等等,通過以上的諸多判斷以決定是否將操作繼續(xù)向后傳遞,盡量保證程序的正常運行。 數(shù)據(jù)訪問層:顧名思義,就是用于專門跟數(shù)據(jù)庫進行交互。執(zhí)行數(shù)據(jù)的添加、刪除、修改和顯示等。需要強調的是,所有的數(shù)據(jù)對象只在這一層被引用,如System.Data.SqlClient等,除數(shù)據(jù)層之外的任何地方都不應該出現(xiàn)這樣的引用。表示層:1.基于WEB的JSP、Servlet、Struts、Webwork、Spring WEB MVC等;2.基于客戶端的Swing、SWT等(rmi,iiop);業(yè)務邏輯

32、層:Pojo(Service,Manager)、Domain、Session EJB、Spring用接口隔離,用Domain或DTO傳遞數(shù)據(jù)數(shù)據(jù)訪問層:JDBC、Ibatis、Hibernate、JDO、Entity Bean用接口隔離,用Domain或DTO傳遞數(shù)據(jù)數(shù)據(jù)訪問層是為業(yè)務邏輯層服務的,業(yè)務邏輯層操作的是對象而數(shù)據(jù)庫是關系型數(shù)據(jù)庫。我們需要在我們的數(shù)據(jù)訪問層把表和字段屏蔽掉,把它變成對象來傳遞給我們的業(yè)務邏輯。傳遞要通過Domain Object(域對象),Domain Object是一塊比較重要的知識,下面我們來講一下Domain Object。Domain Object(域對象

33、)的三種模型由于當前O/R Mapping, DAO開發(fā)結構的層次劃分,導致出現(xiàn)了大量的純粹數(shù)據(jù)對象。這些數(shù)據(jù)對象只帶有getter, setter屬性,而不具有屬于自己的方法,起著Data Transfer Object的作用。 Domain Object 則是重新提出并進一步探討純面向對象編程的概念:對象不僅應該具有數(shù)據(jù),而且應該具有自己的方法。第一種模型(貧血的Domain Object)只有getter/setter方法的純數(shù)據(jù)類,所有的業(yè)務邏輯完全由business object來完成(又稱TransactionScript),這種模型下的domain object被Martin F

34、owler稱之為“貧血的domain object”。下面用舉一個具體的代碼來說明一般情況下,Domain Object單獨放在一個domain包里面。一個Domain Object都會有一張表和他對應。例如下面的Domain 對象Staff就在數(shù)據(jù)庫中對應一張名叫STAFF的表。public class Staff private int id;private String name;private Date birthday;private float money;public int getId() return id;public void setId(int id) this.id

35、= id;public String getName() return name;public void setName(String name) = name;public Date getBirthday() return birthday;public void setBirthday(Date birthday) this.birthday = birthday;public float getMoney() return money;public void setMoney(float money) this.money = money;下面我們定義一個數(shù)據(jù)訪問層

36、的接口,這個接口是給業(yè)務邏輯層用的,最終業(yè)務邏輯層會用這個接口完成對數(shù)據(jù)的增、刪、改、查操作。接口我們一般也放在一個專門的包里面如:com.wanghao.jdbc.dao,在這個包中有一個StaffDao接口,是專門訪問Staff對象用的。package com.wanghao.jdbc.dao;import com.wanghao.jdbc.domain.Staff;public interface StaffDao public void addStaff(Staff staff);public Staff getStaff(int staffId);public Staff findS

37、taff(String loinName,String password);public void update(Staff staff);public void delete(Staff staff);三層架構這樣設計有一個好處就是:讓我們的業(yè)務邏輯層不依賴數(shù)據(jù)訪問層的具體實現(xiàn),業(yè)務邏輯層只使用接口,至于具體實現(xiàn)是什么,它并不關心。這樣的好處是:比如上面的StaffDaoJdbcImplement實現(xiàn),我們是用JDBC實現(xiàn)的。我們也可以把這個實現(xiàn)換成Hibernate來實現(xiàn),用的還是同一個接口。這種替換如果服從三層架構,就會在不影像到你的業(yè)務邏輯層的情況下,且換掉你的數(shù)據(jù)訪問層。接下來我們用

38、JDBC實現(xiàn)這個接口。接口的實現(xiàn)類我們也要轉本放一個包里面,如我們的例子就把接口的實現(xiàn)類StaffDaoJdbcImplement放在com.wanghao.jdbc.dao.implement里面。代碼如下所示:package com.wanghao.jdbc.dao.implement;import java.sql.*;import com.wanghao.jdbc.JdbcUtils;import com.wanghao.jdbc.dao.DaoException;import com.wanghao.jdbc.dao.StaffDao;import com.wanghao.jdbc.

39、domain.Staff;public class StaffDaoJdbcImplement implements StaffDaopublic void addStaff(Staff staff) Connection ct=null;PreparedStatement ps=null;ResultSet rs=null;tryct=JdbcUtils.getConnection();String sql=insert into staff(id,name,birthday,money) values(?,?,?,?);ps=ct.prepareStatement(sql);ps.setI

40、nt(1, staff.getId();ps.setString(2, staff.getName();ps.setDate(3, new java.sql.Date(staff.getBirthday().getTime();ps.setFloat(4, staff.getMoney();ps.executeUpdate();catch(SQLException e)throw new DaoException(e.getMessage(),e);finallyJdbcUtils.free(rs, ps, ct);public void delete(Staff staff) Connect

41、ion ct=null;PreparedStatement ps=null;ResultSet rs=null;tryct=JdbcUtils.getConnection();String sql=delete from staff where id=+staff.getId();ps=ct.prepareStatement(sql);ps.executeUpdate();catch(SQLException e)throw new DaoException(e.getMessage(),e);finallyJdbcUtils.free(rs, ps, ct);public Staff fin

42、dStaff(String loinName, String password) Connection ct=null;PreparedStatement ps=null;ResultSet rs=null;Staff staff=null;tryct=JdbcUtils.getConnection();String sql=select id,name,money,birthday from staff where name=?;ps=ct.prepareStatement(sql);ps.setString(1, loinName);rs=ps.executeQuery();while(r

43、s.next()staff = mappingStaff(rs);catch(SQLException e)throw new DaoException(e.getMessage(),e);finallyJdbcUtils.free(rs, ps, ct);return staff;public Staff getStaff(int staffId) Connection ct=null;PreparedStatement ps=null;ResultSet rs=null;Staff staff=null;tryct=JdbcUtils.getConnection();String sql=

44、select id,name,money,birthday from staff where id=?;ps=ct.prepareStatement(sql);ps.setInt(1, staffId);rs=ps.executeQuery();while(rs.next()staff = mappingStaff(rs);catch(SQLException e)throw new DaoException(e.getMessage(),e);finallyJdbcUtils.free(rs, ps, ct);return staff;private Staff mappingStaff(R

45、esultSet rs) throws SQLException Staff staff;staff=new Staff();staff.setId(rs.getInt(id);staff.setName(rs.getString(name);staff.setBirthday(rs.getDate(birthday);staff.setMoney(rs.getFloat(money);return staff;public void update(Staff staff) Connection ct=null;PreparedStatement ps=null;ResultSet rs=nu

46、ll;tryct=JdbcUtils.getConnection();String sql=update staff set money=? where id=?;ps=ct.prepareStatement(sql);ps.setFloat(1, staff.getMoney();ps.setInt(2, staff.getId();ps.executeUpdate();catch(SQLException e)throw new DaoException(e.getMessage(),e);finallyJdbcUtils.free(rs, ps, ct);在上面的代碼中我們遇到了一個比較

47、復雜的異常處理問題,再此我們插播一曲,講一下編譯時異常和運行時異常的轉換。1、是否可以捕獲即catch一個異常兒什么也不做?這是絕對不允許的,如果什么也不做,一旦出錯系統(tǒng)不會報任何錯誤,而后臺也沒有任何堆棧,但運行結果就是不正確。這樣的錯誤很難調試,所以不允許此種操作。2、初級程序員通常只在catch里面做一個簡單的打出堆棧操作e.printStackTrace(),但這樣處理還是不行的。比如一個用戶注冊程序,當添加完一個新用戶后,要給這個用戶發(fā)個emai雖然做一個簡單的打出堆棧操作,但是,這個異常我們的業(yè)務邏輯層并不知道,當業(yè)務邏輯層執(zhí)行到給用戶發(fā)送email找不到這個用戶的時候,就很難調試

48、了。因此,我們得讓業(yè)務邏輯層知道這個異常的存在。3、那我們直接把這個異常拋出執(zhí)行throw e;語句,這樣,上層業(yè)務邏輯代碼就知道有這個異常的存在,這個目的就達到了。但是現(xiàn)在有一個新的問題存在:上層業(yè)務邏輯代碼必須被catch(捕獲)。因為在這里SQLException是一個編譯時異常,即這個異常必須被處理否則不能通過編譯。但很多情況下,即使業(yè)務邏輯代碼被catch住也沒有什么用,因為是底層的數(shù)據(jù)訪問出錯,業(yè)務邏輯層也沒有解決的辦法,那么業(yè)務邏輯層得繼續(xù)拋出異常。這樣就沒有止境了,使我們的代碼變得相當?shù)脑愀狻A硗馑谠O計上還有一個重大的缺陷,我們用JDBC實現(xiàn)的接口不能在被替換為Hiberna

49、te。Hibernate不拋出SQLException?;蛘哒f,我們先在使用的是數(shù)據(jù)庫,以后我們要換成磁盤文件,即把數(shù)據(jù)放在文件中,文件中沒有SQLException但有IOException。這就相當于底層的數(shù)據(jù)訪問層換不掉了。因此,簡單的把異常拋出去是不合適的。4、結合以上分析,我們需要采取另外一種方式:把編譯時異常轉變成運行時異常,這樣,業(yè)務邏輯層可以選擇處理異?;虿惶幚懋惓?。如果想做的規(guī)范些,就在數(shù)據(jù)邏輯層加一個數(shù)據(jù)訪問異常。這樣即可以達到通知出錯的目的,又不污染我們的接口。代碼如下:package com.wanghao.jdbc.dao;public class DaoExcept

50、ion extends RuntimeException private static final long serialVersionUID=1L;public DaoException() public DaoException(String message) super(message);public DaoException(Throwable cause) super(cause);public DaoException(String message, Throwable cause) super(message, cause);5、上面程序中的陰影部分使用了,是重復的代碼做的一個優(yōu)

51、化,使用的是重構Refactor技術。這樣對我們以后的程序維護很有用處。6、下面使用工廠模式消除StaffDaoTest對StaffDaoJdbcImplement類的依賴。高內聚低耦合高內聚低耦合,是軟件工程中的概念,是判斷設計好壞的標準,主要是面向對象的設計,主要是看類的內聚性是否高,耦合性是否低。內聚就是一個模塊內各個元素彼此結合的程度。所謂的高內聚是指一個軟件模塊是有相關性很強的代碼組成,只負責一項任務,也就是常說的單一責任原則。耦合是一個軟件結構內不同模塊之間互聯(lián)程度的度量。模塊之間聯(lián)系越緊密,其耦合性越強,模塊的獨立性就越差,模塊間耦合的高低取決于模塊間接口的復雜性,調用的方式以及

52、傳遞的信息。對于低耦合,粗淺的理解就是:一個完整的系統(tǒng),模塊與模塊之間,盡可能的使其獨立。DAO工廠模式工廠模式專門負責將大量有共同接口的類實例化。工廠模式可以動態(tài)決定將哪一個類示例化,不必事先知道每次要實例化哪一個類。通過DAO的設計的確可以讓我們的軟件系統(tǒng)已經(jīng)將數(shù)據(jù)層和表現(xiàn)層進行了簡單的分離,讓我們系統(tǒng)各層次的功能更加的清晰。所以我們開始洋洋得意了,DAO的引入讓系統(tǒng)的耦合性更加的松散,表現(xiàn)層再也不需要關心后臺數(shù)據(jù)操作的變化了。于是我們開始高枕無憂了,我們肆無忌憚的在表現(xiàn)層通過調用DAO來實現(xiàn)我們的系統(tǒng)了。事實真的如此嗎?那我們就舉個例子來看看我們的系統(tǒng)是否真的具有解偶的能力了。 現(xiàn)在我們

53、有個員工管理系統(tǒng),在該系統(tǒng)中,Staff.java表示員工這個對象,它對應著數(shù)據(jù)庫中的staff表。還有用于操作Staff對象的DAO接口StaffDAO.java,還有一個StaffDAO的實現(xiàn)類StaffDAOImplement.java。在StaffDAOImplement.java中我們實現(xiàn)了操作Staff對象的所有的方法。我們很自豪的說,看我們已經(jīng)把操作封裝在StaffDAO中了,現(xiàn)在我們可以在表現(xiàn)層(jsp,或者VO操作類中)使用StaffDAO satffDAO=new StaffDAOImplement()來調用DAO操作我們的數(shù)據(jù)對象了。當我們陶醉于自己寫的優(yōu)美的代碼的時候,項目經(jīng)理來通知了,由于使用Hibernate的效率偏低,客戶

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論