JDBC詳解

openkk 12年前發布 | 45K 次閱讀 JDBC Java開發

JDBC原理概述

 

1,JDBC是一套協議,是JAVA開發人員和數據庫廠商達成的協議,也就是由Sun定義一組接口,由數據庫廠商來實現,并規定了JAVA開發人員訪問數據庫所使用的方法的掉用規范。

 

2,JDBC的實現是由數據庫廠商提供,以驅動程序形式提供。

 

3,JDBC在使用前要先加載驅動。

JDBC對于使用者要有一致性,對不同的數據庫其使用方法都是相同的。

 

driver開發必須要實現Driver接口。

數據庫驅動的實現方式

JDBC-ODBC橋接式

JDBC網絡驅動,這種方式是通過中間服務器的協議轉換來實現的

JDBC+本地驅動,這種方式的安全性比較差

JDBC驅動,由數據庫廠商實現。

 

JDBC的API

 

java.sql包和javax.sql包

DriverManager類(驅動管理器),它可以創建連接,它本身就是一個創建Connection的工廠(Factory)。

Connection接口,會根據不同的驅動產生不同的連接

Statement接口,發送sql語句

ResultSet接口(結果集),是用來接收select語句返回的查尋結果的。其實質類似于集合。

 

JDBC應用步驟

1,注冊加載一個driver驅動

2,創建數據庫連接(Connection)

3,創建一個Statement(發送sql)

4,執行sql語句

5,處理sql結果(select語句)

6,關閉Statement

7,關閉連接Connection。

 

注意:6,7兩個步驟勢必須要做的,因為這些資源是不會自動釋放的,必須要自己關閉

 

訪問Oracle的數據庫的驅動名字叫ojdbc14.jar,這個jar文件中出訪的驅動程序的.class文件

要使用這個驅動程序,要先將他加到環境變量PATH中。

 

一,注冊加載驅動driver,也就是強制類加載

   Class.forName(Driver包名.Driver類名)。

 

   Driver d=new Driver類();

   DriverManager.registerDriver(d);

 

   Oracle的Driver的全名oracle.jdbc.driver.OracleDriver

   mysql的Driver的全名com.mysql.jdbc.Driver

   SQLServer的Driver的全名com.microsoft.jdbc.sqlserver.SQLServerDriver

 

二,創建連接

   DriverManager.getConnection(String url,String username,String password);

   Connection連接是通過DriverManager的靜態方法getConnection(.....)來得到的,這個方法的實質是把參數傳到實際的Driver中的connect()方法中來獲得數據庫連接的。

   Oracle的URL值是由連接數據庫的協議和數據庫的IP地址及端口號還有要連接的庫名(DatebaseName)

   Oracle URL的格式

   jdbc:oracle:thin:(協議)@XXX.XXX.X.XXX:XXXX(IP地址及端口號):XXXXXXX(所使用的庫名)

    例:jdbc:oracle:thin:@192.168.0.39:1521:TARENADB

   MySql URL的寫法

    例:jdbc:mysql://192.168.8.21:3306/test

   SQLServer URL的寫法

    例:jdbc:microsoft:sqlserver://192.168.8.21:1433

 

   java -Djdbc.drivers=驅動全名 類名

 

    使用系統屬性名,加載驅動 -D表示為系統屬性賦值

   

    使用Connection對象獲得一個Statement,Statement中的executeQuery(String sql) 方法可以使用select語句查詢,并且返回一個結果集 ResultSet通過遍歷這個結果集,可以獲得select語句的查尋結果,ResultSet的next()方法會操作一個游標從第一條記錄的前邊開始讀取,直到最后一條記錄。executeUpdate(Stringsql) 方法用于執行DDL和DML語句,可以update,delete操作。

注意:要按先ResultSet結果集,后Statement,最后 Connection的順序關閉資源,因為Statement和ResultSet是需要連接是才可以使用的,所以在使用結束之后有可能起他的 Statement還需要連接,所以不能現關閉Connection。

 

 

 

預編譯的Statement

 

PreparedStatement 可以使用參數替代sql語句中的某些參數使用 "?"代替,他先將帶參數的sql語句發送到數據庫,進行編譯,然后PreparedStatement會將參數發送給數據庫。

在使用PreparedStatement時,在設置相應參數時,要指明參數的位置和類型,以及給出參數值

根據不同的參數類型使用不同的setXXX(參數的位置,參數值)來設置參數

 

例:

public void insert(Student s){

              Connectioncon=ConnectionFactory.getConnection();//建立連接

              Stringsql="insert into student(id,name) values(?,?)";

              PreparedStatementps=null;

              try{

                     ps=con.prepareStatement(sql);//創建一個PreparedStatement

                        int index=1;

                     ps.setInt(index++,s.getStuId());

                     ps.setString(index++,s.getName());

                     ps.executeUpdate();

              }catch (SQLException e) {

                     e.printStackTrace();

              }finally{

                     if(ps!=null)

                            try{

                                   ps.close();

                            }catch (SQLException e) {

                                   e.printStackTrace();

                            }

                            if(con!=null)

                                   try{

                                          con.close();

                                   } catch (SQLException e) {

                                          e.printStackTrace();

                                   }

              }

       }

 

CallableStatement是可以用非sql語句來訪問數據庫,他是通過調用存儲過程(PL/SQL)來訪問數據庫的。可以直接使用連接來調用prepareCall(...)方法,來執行這個存儲過程,"..."是存儲過程的名字。

 

 

SQLException是檢查異常必須處理要么throws ,要么try{}catch(){}

getErrorCode()可以獲得錯誤碼,可以對錯誤進行查詢。

 

源數據

 

JDBC中有兩種源數據,一種是數據庫源數據,另一種是ResultSet源數據。

 

源數據就是描述存儲用戶數據的容器的數據結構。

 

ResultSet rs=ps.executeQuery(sql);

ResultSetMetaData m=rs.getMetaData();

 

getColumnCount(),獲得實際列數

getColumnName(int colnum),獲得指定列的列名

getColumnType(int colnum),獲得指定列的數據類型

getColumnTypeName(int colnum),獲得指定列的數據類型名

 

數據庫源數據

 

DatabaseMetaData

getURL(),獲得連接數據庫的URL

getDatabaseProductName() 獲得數據庫產品的名稱

getDriverVersion() 獲得JDBC驅動程序的String形式的版本號

getTables()獲得數據庫中該用戶的所有表

getUserName() 獲得數據庫用戶名。

 

事務(Transaction)

事務是針對原子操作的,要求原子操作不可再分,要求原子操作必須同時成功同時失敗。

事務是捆綁的原子操作的邊界。

JDBC中使用事務,先要使用連接調用setAutoCommite(false)方法,把自動提交(commit)置為false。打開事務就要關閉自動提交。不用事務是要把setAutoCommite(true)

 

在處理事務時,在發送sql語句后執行成功并確認時,就在try塊中使用連接調用commit()方法來發送提交信息,在發送sql語句后執行失敗時,會在catch語句塊中使用連接調用rollback()方法來發送回滾信息,也可以在需要時做回滾操作(主觀原因)。

 

 

 

JDBC事務并發產生的問題和事務隔離級別

 

1,臟讀(dirty read),讀取到了沒有提交的數據。

2,不可重復讀(UnPrpeatable Read),兩次讀取到了不同的數據,就是要保持在同一時間點上兩次讀取到的數據相同,不能夠使查詢數據時進行改變。

3,幻讀(phantom),在兩次查詢同一時間點數據時,數據數量發生改變,要保持在同一時間點上兩次讀取到的數據相同。

 

事務隔離級別

 

TRANSACTION_NONE不使用事務。

TRANSACTION_READ_UNCOMMITTED 可以讀取為提交數據。

TRANSACTION_READ_COMMITTED可以避免臟讀,不能夠讀取沒提交的數據,最常用的隔離級別  大部分數據庫的默認隔離級別

TRANSACTION_REPEATABLE_READ可以避免臟讀,重復讀取,

TRANSACTION_SERIALIZABLE可以避免臟讀,重復讀取和幻讀,(事務串行化)會降低數據庫效率

 

以上的五個事務隔離級別都是在Connection類中定義的靜態常量,使用setTransactionIsolation(intlevel) 方法可以設置事務隔離級別。

 

JDBC2.0新特性

 

可滾動結果集(可雙向滾動),這種結果集不但可以雙向滾動,相對定位,絕對定位,并且可以修改數據信息。

 

滾動特性

next(),此方法是使游標向下一條記錄移動。

previous() ,此方法可以使游標上一條記錄移動,前提前面還有記錄。

 

absolute(int row),可以使用此方法跳到指定的記錄位置。定位成功返回true,不成功返回false,返回值為false,則游標不會移動。

 

afterLast() ,游標跳到最后一條記錄之后,(結果集一回來時就有的位置)。

beforeFirst() ,游標跳到第一條記錄 之前,(結果集一回來時就有的位置)。(跳到游標初始位)

 

first(),游標指向第一條記錄。

last(),有彪指向最后一條記錄。

 

relative(int rows) ,相對定位方法,參數值可正可負,參數為正,游標從當前位置向下移動指定值,參數為負,游標從當前位置向上移動指定值。

 

TYPE_FORWARD_ONLY ,單向,該常量指示指針只能向前移動的 ResultSet 對象的類型。不可滾動。

 

TYPE_SCROLL_INSENSITIVE ,雙向,該常量指示可滾動但通常不受其他的更改影響的 ResultSet 對象的類型。

TYPE_SCROLL_SENSITIVE ,雙向,該常量指示可滾動并且通常受其他的更改影響的 ResultSet 對象的類型。該特性某些數據庫不支持。

         

要使用可滾動結果集時,要在Statement創建時指定參數,才可以使用

Statement st=null;

(int,int)(可滾動特性,可更新特性)

st=con.createStatement(ReusltSet.TYPE_SCROLL_INSENSITIVE,ResuleSet.CONCUR_UPDATABLE)

 

ResultSet結果集中,先使用moveToInsertRow(),將游標移到和結果集結構類似的緩沖區中

然后可以使用updateXxx(intcolumn,columnType value)方法來更新指定列數據,再使用insertRow() 方法插入記錄,最后將游標指回原位,moveToCurrentRow() 。

 

能否使用可更新結果集,要看使用的數據庫驅動是否支持,還有只能用于單表且表中有主鍵字段(可能會是聯合主鍵),不能夠有表連接,會取所有非空字段且沒有默認值。結果集用select * from t也不行,不能用*,不能排序

 

能否使用JDBC2.0ResultSet的新特性要看數據庫驅動程序是否支持。

 

批處理更新

Statement.

addBatch(String sql), 方法會在批處理緩存中加入一條sql語句

executeBatch() ,執行批處理緩存中的所有sql語句。

 

PreparedStatement.   先準備一組參數

addBatch() 將一組參數添加到此 PreparedStatement 對象的批處理命令中。

executeBatch() 將一批命令提交給數據庫來執行,如果全部命令執行成功,則返回更新計數組成的數組。

PreparedStatement中使用批量更新時,要先設置好參數后使用addBatch()方法加入緩存。

注意:批量更新中只能使用更新或插入語句

 

execute(String sql),這個方法的返回值是boolean類型,如果返回true就表示sql是一個select語句,可以通過getResultSet()獲得結果集,如果是false,sql就是DML語句或者是DDL語句。

 

 

SQL3.0中的行類型

 

Array,數組

Sturct,結構類似給該列類型起個描述性的別名

Blob,大的二進制數據文件       create table t_blob(idnumber(12) primary key,filename varchar(20),blobData blob);

                             ps=con.prepareStatement("insert intot_blob" +

                                          "values(?,?,empty_blob())");。

Clob,大文本文件對象。

在使用上述大對象的時候,在使用JDBC插入記錄時要先插入一個空的占位對象,然后使用

select blobdata from t_blob where id =" + id + " for update 這樣的語法來對獲得的大對象,進行實際的寫入操作 Blod通過getBinaryOutputStream()方法獲取流進行寫入。getBinaryStream()方法獲得流來獲取blob中存儲的數據。

clob的操作也和blob相同。getAsciiStream()方法用于讀取存儲的文本對象,getAsciiOutputStream()方法之獲得流用來向文件對象寫入的。

 

 

JDBC2.0擴展

 

JNDI和DataSourse

 

JNDI,(命名路徑服務)也用于存儲數據,但是他所存儲的是一寫零散的信息。

JNDI的方法是在javax.naming包下

 

bind(String name, Object obj) 將名稱綁定到對象資源,建立指定的字符串和對象資源的關聯

lookup(String name) ,通過指定的字符串獲得先前綁定的資源

以下是將資源和JNDI命名綁定的方法

 public static void bind(String context, Object obj) throwsNamingException

    {

        Properties pro = new Properties();

       //Weblogic的JNDI服務器參數

       pro.put(InitialContext.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory");

       pro.put(InitialContext.PROVIDER_URL, "t3://localhost:7001");

      

       Context ctx = new InitialContext(pro);

       ctx.bind(context, obj);//建立指定的字符串和對象資源的關聯

    }

 

 

DataSourse(數據源),包含了連接數據庫所需的信息,可以通過數據源或的數據庫連接,有時由于某些連接數據庫的信息會變更,所以經常使用包含數據庫連接信息的數據源。

 

通過JNDI獲得綁定的資源

 public static Object lookup(String context)throws NamingException

    {

        Properties pro = new Properties();

       //Weblogic的JNDI服務器參數

       pro.put(InitialContext.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory");

       pro.put(InitialContext.PROVIDER_URL, "t3://localhost:7001");

      

       Context ctx = new InitialContext(pro);

       return ctx.lookup(context);//通過指定的字符串獲得先前綁定的資源。

    }

 

連接池,保持連接池中有指定個數的連接,并在程序使用過之后不關閉連接,再放回連接池中等待其他的程序在需要時來取用,這樣可以大量的節省銷毀和創建連接的資源消耗。

 

JTA分布式的事務

 

分布式事務是針對多個不同數據庫同時操作,要保證原子操作的不可分,也不用再自己寫commit,和rollback,全部都交給中間服務器來處理。(兩階段提交),也就是在中間服務器發送sql語句等待數據庫回應,都回應操作成功才提交,否則同時回滾。

 

 

RowSet

 

行集,這是一個JavaBean(事件機制),它增強了ResultSet的功能,通過RowSet可以獲得數據源,設置隔離級別,也可以發送查尋語句,也實現了離線的操作遍歷,RowSet也支持預編譯的Statement。

RowSet中的方法大致上和ResultSet相同,當需要使用時請查閱JAVA API參考文檔。

 

面向對象的數據庫設計

 

Id通常是用來表示記錄的唯一性的,通常會使用業務無關的數字類型

Object id 對象的id,sequence只有Oracle才可用,對象id(OID)使用高低位算法先生成高位,在生成低位,通過運算獲得對象id。

 

類應當對象到表,屬性對應字段,對象對應記錄。

 

類繼承關系對應表,

 

1,每個類建一個表,為父子類每個類都對應的創建表,這種方法類關系清晰,但是如果類比較多就不適合了

 

2,只有具體類才建表,也就是把父類中的屬性均勻分配到子類的表中,也就是父類不建表,這種表關系不能使用多態

 

3,所有類對應一張表,這種方法是在標中加上一個字段來區分父子類,但是只能用于類屬性較少的情況下,而且數據會有冗余。

 

類關聯關系對應表

 

1,一對一關聯,類關系對應成表時有兩種做法,一是引用主鍵,也就是一方引用另一方的主鍵既作為外鍵有作為自身的主鍵。二是外鍵引用,一方引用另一方的主鍵作為自身的外鍵,并且自己擁有主鍵。

 

2,一對多關聯,也就是多端引用一端的主鍵當作外鍵,多端自身擁有主鍵。

 

3,多對多關系,多對多關系是通過中間表來實現的,中間表引用兩表的主鍵當作聯合主鍵,就可以實現多對多關聯。

 

JDCB應用的分層

 

分層就是對功能的隔離,降低層與層間的耦合性。

 本文由用戶 openkk 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!