JDBC note
JDBC部分
終端進入mysql: mysql -u root回車
終端進入oracle: telnet 192.168.0.23 然後sqlplus openlab/open123
MySQL常用命令: show databases; use databaseName; show tables;
一、概述JDBC
JDBC從物理結構上說就是Java語言訪問數據庫的一套接口集合。
從本質上來說就是調用者(程序員)和實現者(數據庫廠商)之間的協議。
JDBC API 使得開發人員可以使用純Java的方式來連接數據庫,並進行操作。
ODBC:基於C語言的數據庫訪問接口。
JDBC:是Java版的ODBC。
JDBC 特性:高度的一致性、簡單性(常用的接口只有4、5個)。
驅動程序按照工作方式分爲四類:
1、JDBC-ODBC bridge + ODBC 驅動
JDBC-ODBC bridge橋驅動將JDBC調用翻譯成ODBC調用,再由ODBC驅動翻譯成訪問數據庫命令。
優點:可以利用現存的ODBC數據源來訪問數據庫。
缺點:從效率和安全性的角度來說的比較差。不適合用於實際項目。
2、基於本地API的部分Java驅動
我們應用程序通過本地協議跟數據庫打交道。然後將數據庫執行的結果通過驅動程序中的Java部分返回給客戶端程序。
優點:效率較高。
缺點:安全性較差。
3、純Java的網絡驅動
(中間協議) (本地協議)
app JDBC 純Java 中間服務器 DB
缺點:兩段通信,效率比較差
優點:安全信較好
4、純Java本地協議:通過本地協議用純Java直接訪問數據庫。
特點:效率高,安全性好。
二、JDBC 編程的步驟
import java.sql.*;
0.參數化
String driverName = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/test"; //協議;庫或服務器名稱;服務器IP,端口
String username = "root";
String password="";
/* Oracle的連接
String driverName = "oracle.jdbc.driver.OracleDriver";
String url = "jdbc:oracle:thin:@192.168.0.23:1521:ora10g";
String username = "openlab";
String password="open123";*/
//以下這些都需要寫在有異常的代碼塊裏,所以需要提取出來。
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;//建議用PreparedStatement
1.加載和註冊數據庫驅動
Class.forName(driverName);//自動註冊;需要把驅動的jar包導進來;需處理異常
/*方法二:實例化具體的Driver驅動,這寫法一般不用(不能參數化驅動名,不夠靈活)
Driver driver = new com.mysql.jdbc.Driver();
DriverManager.registerDriver(driver); //將驅動交於DriverManager託管*/
/*方法三:Dos運行時,java -Djdbc.drives = oracle.jdbc.driver.OracleDriver; --可多個 */
2.連接數據庫
conn = DriverManager.getConnection(url, username, password);//需處理異常
//Connection返回數據庫連接,如:“com.mysql.jdbc.Connection@1ffb8dc”;連接不成功則返回 null
3.創建Statement對象 //爲了類型安全和批量更新的效率,改用PreparedStatement
stmt = conn.createStatement();//需處理異常
//返回其生成結果的對象"oracle.jdbc.driver.OracleStatement@198dfaf"
4.操作數據庫,執行SQL語句
String sql = "select * from tableName";//SQL語句裏不需要寫分號
rs = stmt.executeQuery(sql); //executeQuery(sqlString) 查詢 返回查詢結果集
/* String sql = "insert into tableName values(?,?)"; // ?佔位符
int number = stmt.executeUpdate(sql);//更新,再返回int(更新、修改影響的條數) */
5.處理數據(遊標)
StringBuffer sb = new StringBuffer(); //緩存;用它可提高讀取速度。當然,不用也可以。
ResultSetMetaData md = rs.getMetaData(); //ResultSetMetaData可獲取列的類型和屬性信息
int col = md.getColumnCount(); //獲取列的數目
while(rs.next()){ //rs.next()使遊標下移一位,返回boolean,沒有下一個結果則返回false
for(int i=1; i<=col;i++){ // index(JDBC 的下標從1開始)
sb.append(md.getColumnName(i)+"="+rs.getString(i)+" ");
} sb.append("\n");
}System.out.println(sb);
//1.遊標的初始位置在第一條記錄的前面,使第一次調用next()後,剛好拿到第一個結果。
//2.遊標的最終位置在最後一條記錄的後面(結果集的前面和後面留空,真正存在)
6.釋放資源,斷開與數據庫的連接
//先判斷是否有引用資源,再釋放(釋放空資源會拋異常);注意順序
if(rs!=null)try{rs.close();}catch(Exception e){e.printStackTrace();}
if(stmt!=null)try{stmt.close();}catch(Exception e){e.printStackTrace();}
if(conn!=null)try{conn.close();}catch(Exception e){e.printStackTrace();}
//這些異常沒法處理,處理只爲方便調試。所以這些異常處理也只是打印。
/*要按先ResultSet結果集,後Statement,最後Connection的順序關閉資源,
因爲ResultSet需要Statement和Connection連接時纔可以用的;Statement也需要Connection纔可用;
結束Statement之後有可能其它的Statement還需要連接,因此不能先關閉Connection。ResultSet同理。*/
步驟 1、2、6 每次都一樣,可以重構。
因爲加載驅動是個一次性工作,所以可以採用靜態初始化塊來加載驅動;
連接數據庫的方法應該自己負責,獲取數據庫連接信息和驅動的信息,並處理相關異常;
釋放數據庫資源的方法要考慮到ResultSet、Statement、Connection的不同情況,並處理相關異常。
三、JDBC幾個重要接口重點講解
在JDBC 中包括了兩個包:java.sql和javax.sql。
① java.sql 基本功能。
這個包中的類和接口主要針對基本的數據庫編程服務,如生成連接、執行語句以及準備語句和運行批處理查詢等。
同時也有一些高級的處理,比如批處理更新、事務隔離和可滾動結果集等。
② javax.sql 擴展功能。
它主要爲數據庫方面的高級操作提供了接口和類。
如爲連接管理、分佈式事務和舊有的連接提供了更好的抽象,它引入了容器管理的連接池、分佈式事務和行集等。
API 說明
Connection 與特定數據庫的連接(會話)。能夠通過getMetaData方法獲得數據庫提供的信息、
所支持的SQL語法、存儲過程和此連接的功能等信息。代表了數據庫。
Driver 每個驅動程序類必需實現的接口,每個數據庫驅動程序也都應該提供一個實現Driver接口的類。
DriverManager(Class) 管理一組JDBC驅動程序的基本服務。作爲初始化的一部分,此接口會嘗試加載
在”jdbc.drivers”系統屬性中引用的驅動程序。只是一個輔助類,是工具。
Statement 用於執行靜態SQL語句並返回其生成結果的對象。
PreparedStatement 繼承Statement接口,表示預編譯的SQL語句的對象,SQL語句被預編譯並且存儲
在PreparedStatement對象中。然後可以使用此對象高效地多次執行該語句。
CallableStatement 用來訪問數據庫中的存儲過程。它提供了一些方法來指定語句所使用的輸入/輸出參數。
ResultSet 指的是查詢返回的數據庫結果集。
ResultSetMetaData 可用於獲取關於ResultSet對象中列的類型和屬性信息的對象。
注:除了標出的Class,其它均爲接口。每個都是“java.sql.”包下的。
1. Statement —— SQL語句執行接口
代表了一個數據庫的狀態,在向數據庫發送相應的SQL語句時,都需要創建Statement接口或PreparedStatement接口。
在具體應用中,Statement主要用於操作不帶參數(可以直接運行)的SQL語句,比如刪除語句、添加或更新。
2. PreparedStatement:預編譯的Statement
第一步:通過連接獲得PreparedStatement對象,用帶佔位符(?)的sql語句構造。
PreparedStatement pstm = con.preparedStatement(“select * from test where id=?”);
第二步:設置參數
pstm.setString(1,“ganbin”);//第一個字段是“ganbin”;需一個個字段寫
第三步:執行sql語句
Rs = pstm.excuteQuery();
statement發送完整的Sql語句到數據庫不是直接執行而是由數據庫先編譯,再運行。每次都需要編譯。
而PreparedStatement是先發送帶參數的Sql語句,由數據庫先編譯,再發送一組組參數值。(同構時不需重複編譯)
如果是同構的sql語句,PreparedStatement的效率要比statement高。而對於異構的sql則兩者效率差不多。
一般都用PreparedStatement代替Statement,因爲它是類型安全的。Statement對參數類型不作檢查,故不夠安全。
同構:兩個Sql語句可編譯部分是相同的,只有參數值不同。
異構:整個sql語句的格式是不同的
注意點:1、使用預編譯的Statement編譯多條Sql語句一次執行
2、可以跨數據庫使用,編寫通用程序
3、能用預編譯時儘量用預編譯
4、如果第二個SQL語句與前一個是異構的,需要再次編譯“ps = con.prepareStatement(sql);“
3. ResultSet —— 結果集操作接口
ResultSet接口是查詢結果集接口,它對返回的結果集進行處理。ResultSet是程序員進行JDBC操作的必需接口。
4. ResultSetMetaData —— 元數據操作接口
ResultSetMetaData是對元數據進行操作的接口,可以實現很多高級功能。
Hibernate運行數據庫的操作,大部分都是通過此接口。可以認爲,此接口是SQL查詢語言的一種反射機制。
ResultSetMetaData接口可以通過數組的形式,遍歷數據庫的各個字段的屬性,對於開發者來說,此機制的意義重大。
JDBC通過元數據(MetaData)來獲得具體的表的相關信息,例如,可以查詢數據庫中有哪些表,表有哪些字段,以及字段的
屬性等。MetaData中通過一系列getXXX將這些信息返回給我們。
數據庫元數據 Database MetaData 用connection.getMetaData()獲得;包含了關於數據庫整體元數據信息。
結果集元數據 ResultSet MetaData 用resultSet.getMetaData()獲得;比較重要的是獲得表的列名,列數等信息。
結果集元數據對象:ResultSetMetaData meta = rs.getMetaData();
字段個數:meta.getColomnCount();
字段名字:meta.getColumnName();
字段JDBC類型:meta.getColumnType();
字段數據庫類型:meta.getColumnTypeName();
數據庫元數據對象:DatabaseMetaData dbmd = con.getMetaData();
數據庫名:dbmd.getDatabaseProductName();
數據庫版本號:dbmd.getDatabaseProductVersion();
數據庫驅動名:dbmd.getDriverName();
數據庫驅動版本號:dbmd.getDriverVersion();
數據庫Url:dbmd.getURL();
該連接的登陸名:dbmd.getUserName();
四、JDBC 中使用Transaction編程(事務編程)
1. 事務是具備以下特徵(ACID)的工作單元:
原子性(Atomicity)—— 如果因故障而中斷,則所有結果均被撤消;
一致性(Consistency)—— 事務的結果保留不變;
孤立性(Isolation)—— 中間狀態對其它事務是不可見的;
持久性(Durability)—— 已完成的事務結果上持久的。
原子操作,也就是不可分割的操作,必須一起成功一起失敗。
2. 事務處理三步曲:(事務是一個邊界)
① connection.setAutoCommit(false); //把自動提交關閉;在創建Statement對象之前。
② 正常的DB操作 //若有一條SQL語句失敗了,自動回滾
③ connection.commit() //主動提交
和 connection.rollback() //主動回滾,一般寫在catch語句裏,而前三個都寫在try語句裏
/*********事務的代碼片段:*************/
try{
con.setAutoCommit(false); //step① 把自動提交關閉
Statement stm = con.createStatement(); //step② 正常的DB操作
stm.executeUpdate("insert into person(id, name, age) values(520, 'X-Man', 18)");
stm.executeUpdate("insert into Person(id, name, age) values(521, 'Super', 19)");
con.commit(); //step③ 成功主動提交
} catch(SQLException e){
try{con.rollback(); //如果中途發生異常,則roolback;這語句也會拋異常
}catch(Exception e){e.printStackTrace();} //step③ 失敗則主動回滾
/************************************/
3.JDBC事務併發產生的問題和事務隔離級別(難,建議用例子學習)
JDBC事務併發產生的問題:
① 髒讀(Dirty Reads) 一個事務讀取了另一個並行事務還未提交的數據。(產生原因:讀-寫)
② 不可重複讀(UnPrpeatable Read)一個事務前後兩次讀取數據時,得到的數據不一致,被另一個已提交的事務修改。
③ 幻讀(Phantom Read) 一個事務再次查詢,記錄中的量變化了。(僅對統計有影響)
爲了避免以上三種情況的出現,則採用事務隔離級別:
TRANSACTION_NONE 不使用事務(不可能用,只是理論的)
TRANSACTION_READ_UNCOMMITTED 可以讀取未提交數據(允許髒讀,也不可能)
TRANSACTION_READ_COMMITTED 只讀提交的數據:可防止髒讀;大部分數據庫的默認隔離級別
TRANSACTION_REPEATABLE_READ 重複讀取;只可以避免髒讀
TRANSACTION_SERIALIZABLE 事務串行化:可以避免髒讀,重複讀取和幻讀,但會降低數據庫效率(最常用)
以上的五個事務隔離級別都是在Connection類中定義的靜態常量。隔離級別越高,數據越安全,併發能力越差。
使用setTransactionIsolation(int level) 方法可以設置事務隔離級別。
比如:con.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
五、JDBC 2.0新特性:
1、 Scrollability 結果集可滾動
滾動:可雙向支持絕對與相對滾動,對結果集可進行多次迭代。
Con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
//上句的 SCROLL 再到 CONCUR;不可以寫反,編譯器無法檢測到,因爲他們都是int類型的。
TYPE_FORWARD_ONLY:(單向,一般不用)該常量指示指針只能向前移動的 ResultSet 對象的類型。
TYPE_SCROOL_INSENSITIVE:(雙向、不敏感)可滾動但不受其他更改影響的 ResultSet 對象的類型。
TYPE_SCROLL_SENSITIVE:(雙向、敏感)該常量指示可滾動並且通常受其他的更改影響的 ResultSet 對象的類型。
CONCUR_READ_ONLY:(只讀)該常量指示只可以讀取的 ResultSet 對象的併發模式。
CONCUR_UPDATABLE:(可更新)該常量指示可以更新的 ResultSet 對象的併發模式。
絕對定位:boolean absolute(int row)將遊標移動到指定位置。(row指記錄的序號,沒有這位置則返回false)
void afterLast() 將遊標指向最後一條記錄的後一位(有這位置,但記錄爲空)。
void beforeFirst()將遊標指向最前一條記錄的前一位。
boolean first()將遊標移動到結果集最前。
boolean last()將遊標移動到結果集末尾。
相對定位:boolean next()指向下一個。
boolean previous()指向前一個。
boolean relative(int) 向next()方向移動 int 位(int 可負)。
判位函數:boolean isAfterLast() 是否在最後一條的後一位。
boolean isBeforeFirst() 是否最前一條記錄的前一位。
boolean isFirst() 是否最前位置。
boolean isLast() 是否最後位置。
2、 Updatability 結果集可更新。(主要應用於桌面應用)
更新:rs.updateString(“name”,”Tony”);//前面一個是字段的名字或者序號
rs.updateInt(1,”122323”);修改
rs.deleteRow();刪除
rs.updateRow();
注:只有在必要的時候(如桌面應用)才用結果集更新數據庫,因爲使用結果集更新數據庫效率低下。
可更新結果集還要看數據庫驅動程序是否支持,如Oracle就支持,MySql不支持。
並且只能針對一張表做結果集更新(不能子查詢)。而且不能有join操作。
必須有主健,必須把所有非空沒有默認值的字段查出。
處理可更新結果集時不能用select *來查詢語句,必須指出具體要查詢的字段。(不能使用通配符)
3、 Batch updates 可批量更新。
將多組對數據庫的更新操作發送到數據庫統一執行(數據庫支持併發執行操作),以提高效率。
主要是通過減少數據(Sql語句或參數)在網絡上傳輸的次數來節省時間。//數據有兩組以上都應該用這批量更新
(1)對於Statement的批量更新處理:
stm.addBatch(Sql);
int[] ResultSet=stm.executeBatch();
`
(2)對於PreparedStatement的批量跟新處理
pstm.setInt(1,12);pstm.setString(2,”gaga”);……..
pstm.addBatch();
if(i%100==0) int[] ResultSet=pstm.executeBatch();//每個包50~200組數據,包太大也影響速度
注:int[] 中每一個數表示該Sql語句影響到的記錄條數。
PreparedStatement的更新操作比Statement的更新操作多了一個設置參數的過程。
六、SQL 3.0規範中的新類型:
Blob,大的二進制數據文件,最多存儲2G。
Clob,大文本文件對象,最多存儲2G。
在使用上述大對象的時候,在使用JDBC插入記錄時要先插入一個空的佔位對象,
"insert into tableName valuse(?,?,empty_blob())"//在數據庫製造一個空的blob對象字段值
然後使用"select blobdata from t_blob where id = ? for update"對獲得的大對象進行實際的寫入操作
Blod通過getBinaryOutputStream()方法獲取流進行寫入。
getBinaryStream()方法獲得流來獲取Blob中存儲的數據。
Clob的操作也和、Blob相同。
getAsciiStream()用於讀取存儲的文本對象,getAsciiOutputStream()方法之獲得流用來向文件對象寫入的。
BLOB與CLOB的異同點:
① 都可以存儲大量超長的數據;
② BLOB (Binary Large Object) 以二進制格式保存,特別適合保存圖片、視頻文件、音頻文件、程序文件等;
③ CLOB (Character Large Object) 以Character格式保存於數據庫中,適合保存比較長的文本文件。
七、JDBC 2.0擴展
(一)JNDI(命名目錄服務器):
定義:是Java的命名目錄服務器。而JDBC是Java的數據庫訪問接口。
跟JDBC是平級的關係,是兩個獨立的JNDI;JDBC存儲的數據都是以二維表的接口來大規模存儲數據。
而JNDI存儲的是差異性比較大的Java對象。JDBC取數據時用Sql語言訪問數據。JNDI只用lookup和bind讀寫
JDBC API依賴於驅動程序,而JNDI依賴於服務提供者。
JDBC一般把數據存儲到關係型數據庫,而JNDI一般把數據存儲到小型數據庫、文件、甚至是註冊表中。
JNDI相當於一個電話本。允許程序將一個對象和一個命名綁定到目錄樹上。
(JNDI的方法是在javax.naming包下,接口是Context實現類是InitialContext)
bind(String name, Object obj) 將名稱綁定到對象資源,建立指定的字符串和對象資源的關聯
lookup(String name) ,通過指定的字符串獲得先前綁定的資源
/*********以下是將資源和JNDI命名綁定的方法**************/
public static void bind(String context, Object obj) 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);//連接服務器
ctx.bind(context, obj);//存儲
}
(二)DataSourse(數據源)
1、包含了連接數據庫所需的信息,可以通過數據源獲得數據庫連接,
有時由於某些連接數據庫的信息會變更,所以經常使用包含數據庫連接信息的數據源。
2、一個標準的數據庫連接工廠,作爲DriverManager的替代項,保存與數據庫相關的信息,
可以將數據庫的連接信息放在一個共享的空間進行提取,不用在本地安裝。
支持JNDI的綁定,支持連接池,支持分佈式服務,用getConnection方法可獲得與數據庫的連接。
數據源應該由管理員創建(目的是爲了保證數據庫的安全)。所以數據源對象一般放在JNDI服務器中。
/*********通過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);//查找;通過指定的字符串獲得先前綁定的資源。
}
(三)連接池:
在內存中用來保存一個個數據庫連接的對象。
訪問數據庫時,建立連接和拆連接需要花費較長時間,通過以連接池直連的方式獲取連接,不需要註冊驅動程序,可以大量
的節省銷燬和創建連接的資源消耗,提高訪問數據庫的效率。
注:通過連接池獲得的Connection,當執行con.close()時,不是關閉連接,而是表示將連接釋放回連接池。
連接池是一個很複雜的算法,由服務器廠商實現。
(四)分佈式的事務管理器JTA
分佈式事務是通過多個異地數據庫執行一組相關的操作,要保證原子操作的不可分,
也不用再自己寫commit,和rollback,全部都交給中間服務器(TM)來處理。
(兩階段提交),也就是在中間服務器發送sql語句等待數據庫迴應,都回應操作成功才提交,否則同時回滾。
---------------- commit
con1 ------->| TM(事務管理器) | -----------> DB1
con2 ------->| commit | -----------> DB2
---------------- commit
1、regester
2、TM->execute()
3、commit->TM
4、TM->commit->DB
//不要(五)RowSet
行集,這是一個JavaBean(事件機制),它增強了ResultSet的功能,包裝了Connection、Statement、
ResultSet、DriverManage。通過RowSet可以獲得數據源,設置隔離級別,也可以發送查尋語句,也實現了離線的操
作遍歷,RowSet也支持預編譯的Statement。是結果集的子接口,爲快速開發而設(目前還不夠成熟,沒人用)。
RowSet中的方法大致上和ResultSet相同,當需要使用時請查閱JAVA API參考文檔。
八、JDBC應用的分層(DAO)
分層就是對功能的隔離,降低層與層之間的耦合性。
軟件的分層初步:
JSP Struts
View(界面) --> Controlle --> Atio ---> Service/Biz --> DAO ----> DB
重新封裝 可複用 封裝信息 懂業務邏輯 數據訪問層 數據層
調業務 無技術難度 與業務無關
誰依賴誰就看誰調用誰。
軟件的分層設計,便於任務的劃分、降低層間的耦合。
結合PMS的設計方法,思考這樣分層的好處。
並且,使代碼儘量減少重複,可複用性好,擴展餘地加大,而且儘量減少硬編碼。
需求:實現對Person類的數據庫持久化基本操作(CRUD)。
BS架構和CS架構:
C-S架構:兩層體系結構,主要應用於局域網中。
B-S架構:三層體系結構,表現層+業務邏輯層+數據存儲層
注:層面越多,軟件越複雜,但更靈活。分層是必須的但是要有個度。
層次一但確定,數據必須按層訪問,不能跨層訪問。
層與層之間最好時單向依賴(單向調用)。
縱向劃分:按功能劃分。分成三層體系結構(也有兩層的)。
橫向劃分:按抽象劃分。分成抽象部分和實現部分。
/***以下老師沒講的內容******/
一、JDBC異常處理:
JDBC中,和異常相關的兩個類是SQLException和SQLWarning。
1.SQLException類:用來處理較爲嚴重的異常情況。
比如:① 傳輸的SQL語句語法的錯誤;
② JDBC程序連接斷開;
③ SQL語句中使用了錯誤的函數。
SQLException提供以下方法:
getNextException() —— 用來返回異常棧中的下一個相關異常;
getErrorCode() —— 用來返回代表異常的整數代碼 (error code);
getMessage() —— 用來返回異常的描述信息 (error message)。
2.SQLWarning類:用來處理不太嚴重的異常情況,也就是一些警告性的異常。
其提供的方法和使用與SQLException基本相似。
結合異常的兩種處理方式,明確何時採用哪種。
A. throws 處理不了,或者要讓調用者知道;
B. try … catch 能自行處理,就進行異常處理。
二、JavaBean的定義:
1、是一個普通的Java類
2、在結構上沒有預先的規定,不需要容器,不需要繼承類或實現接口
3、要求必須放在包中,要求實現Serializable接口
4、要求有一個無參的構造方法.
5、屬性的類型必須保持唯一,get方法返回值必須和set方法參數類型一致
6、對每個屬性要有對應的get和set方法。注:隱藏屬性可以沒有
7、可以有外觀作爲顯示控制,事件機制。
三、SQL數據類型及其相應的Java數據類型
SQL數據類型 ? ? ? ? ? ? Java數據類型 ? ? ? ? ? ? ?說明
??---------------------------------------------------------------------------------------
? ?INTEGER或者INT ? ? ? ? ? int ? ? ? ? ? ? ? 通常是個32位整數
? ?SMALLINT ? ? ? ? ? ? ? short ? ? ? ? ? ? 通常是個16位整數
? ?NUMBER(m,n) ? ? ? Java.sql.Numeric ? ?合計位數是m的定點十進制數,小數後面有n位數
DECIMAL(m,n) 同上
? ?DEC(m,n) ? ? ? ? ? ? ? Java.sql.Numeric ? ?合計位數是m的定點十進制數,小數後面有n位數
? ?FLOAT(n) ? ? ? ? ? ? ? double ? ? ? ? ? 運算精度爲n位二進制數的浮點數
? ?REAL ? ? ? ? ? ? ? ? ? float ? ? ? ? ? ?通常是32位浮點數
? ?DOUBLE ? ? ? ? ? ? ? ? double ? ? ? ? ? 通常是64位浮點數
? CHAR(n) ? ? ? ? ? String ? ? ? ? ? 長度爲n的固定長度字符串
CHARACTER(n) 同上
? ?VARCHAR(n) ? ? ? ? ? ?String ? ? ? ? ? 最大長度爲n的可變長度字符串
? ?BOOLEAN ? ? ? ? ? ? ? ?boolean ? ? ? ? ?布爾值
? ?DATE ? ? ? ? ? ? ? ? ? Java.sql.Date ? ? 根據具體設備而實現的日曆日期
? ?TIME ? ? ? ? ? ? ? ? ? Java.sql.Time ? ? ? 根據具體設備而實現的時戳
? ?TIMESTAMP ? ? ? ? ? ?? Java.sql.Timestamp ?根據具體設備而實現的當日日期和時間
? ?BLOB ? ? ? ? ? ? ? ? Java.sql.Blob ? ?? 二進制大型對象
? ?CLOB ? ? ? ? ? ? ? ? ?Java.sql.Clob ? ?? 字符大型對象
? ?ARRAY ? ? ? ? ? ? ? ?? Java.sql.Array
四、 面向對象的數據庫設計
類的關聯,繼承在數據庫中的體現:
類定義―――>表定義
類屬性―――>表字段
類關係―――>表關係
對 象―――>表記錄
注: Oid(對象id)―――>業務無關
在數據庫中每一條記錄都對應一個唯一的id;
Id通常是用來表示記錄的唯一性的,通常會使用業務無關的數字類型
字段的個數不會影響數據庫的性能,表則越多性能越低。
(一)類繼承關係對應表,
1、 爲每一個類建一張表。通過父類的Oid來體現繼承關係。
特點:在子類表中引用父類表的主建作爲自己的外建。
優點:方便查詢。屬性沒有冗餘。支持多態。
缺點:表多,讀寫效率低。生成報表比較麻煩。
2、 爲每一個具體實現類建一個表
特點:父類的屬性被分配到每一個子類表中。
優點:報表比較容易
缺點:如果父類發生改變會引起所有子類表隨之更改。並且不支持多態。數據有少量冗餘。
3、 所有的類在一張表中體現,加一個類型辨別字段
特點:效率高,查詢不方便,用於字段不多時。
優點:支持多態,生成報表很簡單。
缺點:如果任何一個類發生變化,必須改表。字段多,難以維護。
(二)類關聯關係對應表
1、 一對一關聯,類關係對應成表時有兩種做法:
一是引用主鍵,也就是一方引用另一方的主鍵既作爲外鍵有作爲自身的主鍵。
二是外鍵引用,一方引用另一方的主鍵作爲自身的外鍵,並且自己擁有主鍵。
2、 一對多關聯,也就是多端引用一端的主鍵當作外鍵,多端自身擁有主鍵。
3、 多對多關係,多對多關係是通過中間表來實現的,中間表引用兩表的主鍵當作聯合主鍵,就可以實現多對多關聯。
終端進入mysql: mysql -u root回車
終端進入oracle: telnet 192.168.0.23 然後sqlplus openlab/open123
MySQL常用命令: show databases; use databaseName; show tables;
一、概述JDBC
JDBC從物理結構上說就是Java語言訪問數據庫的一套接口集合。
從本質上來說就是調用者(程序員)和實現者(數據庫廠商)之間的協議。
JDBC API 使得開發人員可以使用純Java的方式來連接數據庫,並進行操作。
ODBC:基於C語言的數據庫訪問接口。
JDBC:是Java版的ODBC。
JDBC 特性:高度的一致性、簡單性(常用的接口只有4、5個)。
驅動程序按照工作方式分爲四類:
1、JDBC-ODBC bridge + ODBC 驅動
JDBC-ODBC bridge橋驅動將JDBC調用翻譯成ODBC調用,再由ODBC驅動翻譯成訪問數據庫命令。
優點:可以利用現存的ODBC數據源來訪問數據庫。
缺點:從效率和安全性的角度來說的比較差。不適合用於實際項目。
2、基於本地API的部分Java驅動
我們應用程序通過本地協議跟數據庫打交道。然後將數據庫執行的結果通過驅動程序中的Java部分返回給客戶端程序。
優點:效率較高。
缺點:安全性較差。
3、純Java的網絡驅動
(中間協議) (本地協議)
app JDBC 純Java 中間服務器 DB
缺點:兩段通信,效率比較差
優點:安全信較好
4、純Java本地協議:通過本地協議用純Java直接訪問數據庫。
特點:效率高,安全性好。
二、JDBC 編程的步驟
import java.sql.*;
0.參數化
String driverName = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/test"; //協議;庫或服務器名稱;服務器IP,端口
String username = "root";
String password="";
/* Oracle的連接
String driverName = "oracle.jdbc.driver.OracleDriver";
String url = "jdbc:oracle:thin:@192.168.0.23:1521:ora10g";
String username = "openlab";
String password="open123";*/
//以下這些都需要寫在有異常的代碼塊裏,所以需要提取出來。
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;//建議用PreparedStatement
1.加載和註冊數據庫驅動
Class.forName(driverName);//自動註冊;需要把驅動的jar包導進來;需處理異常
/*方法二:實例化具體的Driver驅動,這寫法一般不用(不能參數化驅動名,不夠靈活)
Driver driver = new com.mysql.jdbc.Driver();
DriverManager.registerDriver(driver); //將驅動交於DriverManager託管*/
/*方法三:Dos運行時,java -Djdbc.drives = oracle.jdbc.driver.OracleDriver; --可多個 */
2.連接數據庫
conn = DriverManager.getConnection(url, username, password);//需處理異常
//Connection返回數據庫連接,如:“com.mysql.jdbc.Connection@1ffb8dc”;連接不成功則返回 null
3.創建Statement對象 //爲了類型安全和批量更新的效率,改用PreparedStatement
stmt = conn.createStatement();//需處理異常
//返回其生成結果的對象"oracle.jdbc.driver.OracleStatement@198dfaf"
4.操作數據庫,執行SQL語句
String sql = "select * from tableName";//SQL語句裏不需要寫分號
rs = stmt.executeQuery(sql); //executeQuery(sqlString) 查詢 返回查詢結果集
/* String sql = "insert into tableName values(?,?)"; // ?佔位符
int number = stmt.executeUpdate(sql);//更新,再返回int(更新、修改影響的條數) */
5.處理數據(遊標)
StringBuffer sb = new StringBuffer(); //緩存;用它可提高讀取速度。當然,不用也可以。
ResultSetMetaData md = rs.getMetaData(); //ResultSetMetaData可獲取列的類型和屬性信息
int col = md.getColumnCount(); //獲取列的數目
while(rs.next()){ //rs.next()使遊標下移一位,返回boolean,沒有下一個結果則返回false
for(int i=1; i<=col;i++){ // index(JDBC 的下標從1開始)
sb.append(md.getColumnName(i)+"="+rs.getString(i)+" ");
} sb.append("\n");
}System.out.println(sb);
//1.遊標的初始位置在第一條記錄的前面,使第一次調用next()後,剛好拿到第一個結果。
//2.遊標的最終位置在最後一條記錄的後面(結果集的前面和後面留空,真正存在)
6.釋放資源,斷開與數據庫的連接
//先判斷是否有引用資源,再釋放(釋放空資源會拋異常);注意順序
if(rs!=null)try{rs.close();}catch(Exception e){e.printStackTrace();}
if(stmt!=null)try{stmt.close();}catch(Exception e){e.printStackTrace();}
if(conn!=null)try{conn.close();}catch(Exception e){e.printStackTrace();}
//這些異常沒法處理,處理只爲方便調試。所以這些異常處理也只是打印。
/*要按先ResultSet結果集,後Statement,最後Connection的順序關閉資源,
因爲ResultSet需要Statement和Connection連接時纔可以用的;Statement也需要Connection纔可用;
結束Statement之後有可能其它的Statement還需要連接,因此不能先關閉Connection。ResultSet同理。*/
步驟 1、2、6 每次都一樣,可以重構。
因爲加載驅動是個一次性工作,所以可以採用靜態初始化塊來加載驅動;
連接數據庫的方法應該自己負責,獲取數據庫連接信息和驅動的信息,並處理相關異常;
釋放數據庫資源的方法要考慮到ResultSet、Statement、Connection的不同情況,並處理相關異常。
三、JDBC幾個重要接口重點講解
在JDBC 中包括了兩個包:java.sql和javax.sql。
① java.sql 基本功能。
這個包中的類和接口主要針對基本的數據庫編程服務,如生成連接、執行語句以及準備語句和運行批處理查詢等。
同時也有一些高級的處理,比如批處理更新、事務隔離和可滾動結果集等。
② javax.sql 擴展功能。
它主要爲數據庫方面的高級操作提供了接口和類。
如爲連接管理、分佈式事務和舊有的連接提供了更好的抽象,它引入了容器管理的連接池、分佈式事務和行集等。
API 說明
Connection 與特定數據庫的連接(會話)。能夠通過getMetaData方法獲得數據庫提供的信息、
所支持的SQL語法、存儲過程和此連接的功能等信息。代表了數據庫。
Driver 每個驅動程序類必需實現的接口,每個數據庫驅動程序也都應該提供一個實現Driver接口的類。
DriverManager(Class) 管理一組JDBC驅動程序的基本服務。作爲初始化的一部分,此接口會嘗試加載
在”jdbc.drivers”系統屬性中引用的驅動程序。只是一個輔助類,是工具。
Statement 用於執行靜態SQL語句並返回其生成結果的對象。
PreparedStatement 繼承Statement接口,表示預編譯的SQL語句的對象,SQL語句被預編譯並且存儲
在PreparedStatement對象中。然後可以使用此對象高效地多次執行該語句。
CallableStatement 用來訪問數據庫中的存儲過程。它提供了一些方法來指定語句所使用的輸入/輸出參數。
ResultSet 指的是查詢返回的數據庫結果集。
ResultSetMetaData 可用於獲取關於ResultSet對象中列的類型和屬性信息的對象。
注:除了標出的Class,其它均爲接口。每個都是“java.sql.”包下的。
1. Statement —— SQL語句執行接口
代表了一個數據庫的狀態,在向數據庫發送相應的SQL語句時,都需要創建Statement接口或PreparedStatement接口。
在具體應用中,Statement主要用於操作不帶參數(可以直接運行)的SQL語句,比如刪除語句、添加或更新。
2. PreparedStatement:預編譯的Statement
第一步:通過連接獲得PreparedStatement對象,用帶佔位符(?)的sql語句構造。
PreparedStatement pstm = con.preparedStatement(“select * from test where id=?”);
第二步:設置參數
pstm.setString(1,“ganbin”);//第一個字段是“ganbin”;需一個個字段寫
第三步:執行sql語句
Rs = pstm.excuteQuery();
statement發送完整的Sql語句到數據庫不是直接執行而是由數據庫先編譯,再運行。每次都需要編譯。
而PreparedStatement是先發送帶參數的Sql語句,由數據庫先編譯,再發送一組組參數值。(同構時不需重複編譯)
如果是同構的sql語句,PreparedStatement的效率要比statement高。而對於異構的sql則兩者效率差不多。
一般都用PreparedStatement代替Statement,因爲它是類型安全的。Statement對參數類型不作檢查,故不夠安全。
同構:兩個Sql語句可編譯部分是相同的,只有參數值不同。
異構:整個sql語句的格式是不同的
注意點:1、使用預編譯的Statement編譯多條Sql語句一次執行
2、可以跨數據庫使用,編寫通用程序
3、能用預編譯時儘量用預編譯
4、如果第二個SQL語句與前一個是異構的,需要再次編譯“ps = con.prepareStatement(sql);“
3. ResultSet —— 結果集操作接口
ResultSet接口是查詢結果集接口,它對返回的結果集進行處理。ResultSet是程序員進行JDBC操作的必需接口。
4. ResultSetMetaData —— 元數據操作接口
ResultSetMetaData是對元數據進行操作的接口,可以實現很多高級功能。
Hibernate運行數據庫的操作,大部分都是通過此接口。可以認爲,此接口是SQL查詢語言的一種反射機制。
ResultSetMetaData接口可以通過數組的形式,遍歷數據庫的各個字段的屬性,對於開發者來說,此機制的意義重大。
JDBC通過元數據(MetaData)來獲得具體的表的相關信息,例如,可以查詢數據庫中有哪些表,表有哪些字段,以及字段的
屬性等。MetaData中通過一系列getXXX將這些信息返回給我們。
數據庫元數據 Database MetaData 用connection.getMetaData()獲得;包含了關於數據庫整體元數據信息。
結果集元數據 ResultSet MetaData 用resultSet.getMetaData()獲得;比較重要的是獲得表的列名,列數等信息。
結果集元數據對象:ResultSetMetaData meta = rs.getMetaData();
字段個數:meta.getColomnCount();
字段名字:meta.getColumnName();
字段JDBC類型:meta.getColumnType();
字段數據庫類型:meta.getColumnTypeName();
數據庫元數據對象:DatabaseMetaData dbmd = con.getMetaData();
數據庫名:dbmd.getDatabaseProductName();
數據庫版本號:dbmd.getDatabaseProductVersion();
數據庫驅動名:dbmd.getDriverName();
數據庫驅動版本號:dbmd.getDriverVersion();
數據庫Url:dbmd.getURL();
該連接的登陸名:dbmd.getUserName();
四、JDBC 中使用Transaction編程(事務編程)
1. 事務是具備以下特徵(ACID)的工作單元:
原子性(Atomicity)—— 如果因故障而中斷,則所有結果均被撤消;
一致性(Consistency)—— 事務的結果保留不變;
孤立性(Isolation)—— 中間狀態對其它事務是不可見的;
持久性(Durability)—— 已完成的事務結果上持久的。
原子操作,也就是不可分割的操作,必須一起成功一起失敗。
2. 事務處理三步曲:(事務是一個邊界)
① connection.setAutoCommit(false); //把自動提交關閉;在創建Statement對象之前。
② 正常的DB操作 //若有一條SQL語句失敗了,自動回滾
③ connection.commit() //主動提交
和 connection.rollback() //主動回滾,一般寫在catch語句裏,而前三個都寫在try語句裏
/*********事務的代碼片段:*************/
try{
con.setAutoCommit(false); //step① 把自動提交關閉
Statement stm = con.createStatement(); //step② 正常的DB操作
stm.executeUpdate("insert into person(id, name, age) values(520, 'X-Man', 18)");
stm.executeUpdate("insert into Person(id, name, age) values(521, 'Super', 19)");
con.commit(); //step③ 成功主動提交
} catch(SQLException e){
try{con.rollback(); //如果中途發生異常,則roolback;這語句也會拋異常
}catch(Exception e){e.printStackTrace();} //step③ 失敗則主動回滾
/************************************/
3.JDBC事務併發產生的問題和事務隔離級別(難,建議用例子學習)
JDBC事務併發產生的問題:
① 髒讀(Dirty Reads) 一個事務讀取了另一個並行事務還未提交的數據。(產生原因:讀-寫)
② 不可重複讀(UnPrpeatable Read)一個事務前後兩次讀取數據時,得到的數據不一致,被另一個已提交的事務修改。
③ 幻讀(Phantom Read) 一個事務再次查詢,記錄中的量變化了。(僅對統計有影響)
爲了避免以上三種情況的出現,則採用事務隔離級別:
TRANSACTION_NONE 不使用事務(不可能用,只是理論的)
TRANSACTION_READ_UNCOMMITTED 可以讀取未提交數據(允許髒讀,也不可能)
TRANSACTION_READ_COMMITTED 只讀提交的數據:可防止髒讀;大部分數據庫的默認隔離級別
TRANSACTION_REPEATABLE_READ 重複讀取;只可以避免髒讀
TRANSACTION_SERIALIZABLE 事務串行化:可以避免髒讀,重複讀取和幻讀,但會降低數據庫效率(最常用)
以上的五個事務隔離級別都是在Connection類中定義的靜態常量。隔離級別越高,數據越安全,併發能力越差。
使用setTransactionIsolation(int level) 方法可以設置事務隔離級別。
比如:con.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
五、JDBC 2.0新特性:
1、 Scrollability 結果集可滾動
滾動:可雙向支持絕對與相對滾動,對結果集可進行多次迭代。
Con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
//上句的 SCROLL 再到 CONCUR;不可以寫反,編譯器無法檢測到,因爲他們都是int類型的。
TYPE_FORWARD_ONLY:(單向,一般不用)該常量指示指針只能向前移動的 ResultSet 對象的類型。
TYPE_SCROOL_INSENSITIVE:(雙向、不敏感)可滾動但不受其他更改影響的 ResultSet 對象的類型。
TYPE_SCROLL_SENSITIVE:(雙向、敏感)該常量指示可滾動並且通常受其他的更改影響的 ResultSet 對象的類型。
CONCUR_READ_ONLY:(只讀)該常量指示只可以讀取的 ResultSet 對象的併發模式。
CONCUR_UPDATABLE:(可更新)該常量指示可以更新的 ResultSet 對象的併發模式。
絕對定位:boolean absolute(int row)將遊標移動到指定位置。(row指記錄的序號,沒有這位置則返回false)
void afterLast() 將遊標指向最後一條記錄的後一位(有這位置,但記錄爲空)。
void beforeFirst()將遊標指向最前一條記錄的前一位。
boolean first()將遊標移動到結果集最前。
boolean last()將遊標移動到結果集末尾。
相對定位:boolean next()指向下一個。
boolean previous()指向前一個。
boolean relative(int) 向next()方向移動 int 位(int 可負)。
判位函數:boolean isAfterLast() 是否在最後一條的後一位。
boolean isBeforeFirst() 是否最前一條記錄的前一位。
boolean isFirst() 是否最前位置。
boolean isLast() 是否最後位置。
2、 Updatability 結果集可更新。(主要應用於桌面應用)
更新:rs.updateString(“name”,”Tony”);//前面一個是字段的名字或者序號
rs.updateInt(1,”122323”);修改
rs.deleteRow();刪除
rs.updateRow();
注:只有在必要的時候(如桌面應用)才用結果集更新數據庫,因爲使用結果集更新數據庫效率低下。
可更新結果集還要看數據庫驅動程序是否支持,如Oracle就支持,MySql不支持。
並且只能針對一張表做結果集更新(不能子查詢)。而且不能有join操作。
必須有主健,必須把所有非空沒有默認值的字段查出。
處理可更新結果集時不能用select *來查詢語句,必須指出具體要查詢的字段。(不能使用通配符)
3、 Batch updates 可批量更新。
將多組對數據庫的更新操作發送到數據庫統一執行(數據庫支持併發執行操作),以提高效率。
主要是通過減少數據(Sql語句或參數)在網絡上傳輸的次數來節省時間。//數據有兩組以上都應該用這批量更新
(1)對於Statement的批量更新處理:
stm.addBatch(Sql);
int[] ResultSet=stm.executeBatch();
`
(2)對於PreparedStatement的批量跟新處理
pstm.setInt(1,12);pstm.setString(2,”gaga”);……..
pstm.addBatch();
if(i%100==0) int[] ResultSet=pstm.executeBatch();//每個包50~200組數據,包太大也影響速度
注:int[] 中每一個數表示該Sql語句影響到的記錄條數。
PreparedStatement的更新操作比Statement的更新操作多了一個設置參數的過程。
六、SQL 3.0規範中的新類型:
Blob,大的二進制數據文件,最多存儲2G。
Clob,大文本文件對象,最多存儲2G。
在使用上述大對象的時候,在使用JDBC插入記錄時要先插入一個空的佔位對象,
"insert into tableName valuse(?,?,empty_blob())"//在數據庫製造一個空的blob對象字段值
然後使用"select blobdata from t_blob where id = ? for update"對獲得的大對象進行實際的寫入操作
Blod通過getBinaryOutputStream()方法獲取流進行寫入。
getBinaryStream()方法獲得流來獲取Blob中存儲的數據。
Clob的操作也和、Blob相同。
getAsciiStream()用於讀取存儲的文本對象,getAsciiOutputStream()方法之獲得流用來向文件對象寫入的。
BLOB與CLOB的異同點:
① 都可以存儲大量超長的數據;
② BLOB (Binary Large Object) 以二進制格式保存,特別適合保存圖片、視頻文件、音頻文件、程序文件等;
③ CLOB (Character Large Object) 以Character格式保存於數據庫中,適合保存比較長的文本文件。
七、JDBC 2.0擴展
(一)JNDI(命名目錄服務器):
定義:是Java的命名目錄服務器。而JDBC是Java的數據庫訪問接口。
跟JDBC是平級的關係,是兩個獨立的JNDI;JDBC存儲的數據都是以二維表的接口來大規模存儲數據。
而JNDI存儲的是差異性比較大的Java對象。JDBC取數據時用Sql語言訪問數據。JNDI只用lookup和bind讀寫
JDBC API依賴於驅動程序,而JNDI依賴於服務提供者。
JDBC一般把數據存儲到關係型數據庫,而JNDI一般把數據存儲到小型數據庫、文件、甚至是註冊表中。
JNDI相當於一個電話本。允許程序將一個對象和一個命名綁定到目錄樹上。
(JNDI的方法是在javax.naming包下,接口是Context實現類是InitialContext)
bind(String name, Object obj) 將名稱綁定到對象資源,建立指定的字符串和對象資源的關聯
lookup(String name) ,通過指定的字符串獲得先前綁定的資源
/*********以下是將資源和JNDI命名綁定的方法**************/
public static void bind(String context, Object obj) 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);//連接服務器
ctx.bind(context, obj);//存儲
}
(二)DataSourse(數據源)
1、包含了連接數據庫所需的信息,可以通過數據源獲得數據庫連接,
有時由於某些連接數據庫的信息會變更,所以經常使用包含數據庫連接信息的數據源。
2、一個標準的數據庫連接工廠,作爲DriverManager的替代項,保存與數據庫相關的信息,
可以將數據庫的連接信息放在一個共享的空間進行提取,不用在本地安裝。
支持JNDI的綁定,支持連接池,支持分佈式服務,用getConnection方法可獲得與數據庫的連接。
數據源應該由管理員創建(目的是爲了保證數據庫的安全)。所以數據源對象一般放在JNDI服務器中。
/*********通過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);//查找;通過指定的字符串獲得先前綁定的資源。
}
(三)連接池:
在內存中用來保存一個個數據庫連接的對象。
訪問數據庫時,建立連接和拆連接需要花費較長時間,通過以連接池直連的方式獲取連接,不需要註冊驅動程序,可以大量
的節省銷燬和創建連接的資源消耗,提高訪問數據庫的效率。
注:通過連接池獲得的Connection,當執行con.close()時,不是關閉連接,而是表示將連接釋放回連接池。
連接池是一個很複雜的算法,由服務器廠商實現。
(四)分佈式的事務管理器JTA
分佈式事務是通過多個異地數據庫執行一組相關的操作,要保證原子操作的不可分,
也不用再自己寫commit,和rollback,全部都交給中間服務器(TM)來處理。
(兩階段提交),也就是在中間服務器發送sql語句等待數據庫迴應,都回應操作成功才提交,否則同時回滾。
---------------- commit
con1 ------->| TM(事務管理器) | -----------> DB1
con2 ------->| commit | -----------> DB2
---------------- commit
1、regester
2、TM->execute()
3、commit->TM
4、TM->commit->DB
//不要(五)RowSet
行集,這是一個JavaBean(事件機制),它增強了ResultSet的功能,包裝了Connection、Statement、
ResultSet、DriverManage。通過RowSet可以獲得數據源,設置隔離級別,也可以發送查尋語句,也實現了離線的操
作遍歷,RowSet也支持預編譯的Statement。是結果集的子接口,爲快速開發而設(目前還不夠成熟,沒人用)。
RowSet中的方法大致上和ResultSet相同,當需要使用時請查閱JAVA API參考文檔。
八、JDBC應用的分層(DAO)
分層就是對功能的隔離,降低層與層之間的耦合性。
軟件的分層初步:
JSP Struts
View(界面) --> Controlle --> Atio ---> Service/Biz --> DAO ----> DB
重新封裝 可複用 封裝信息 懂業務邏輯 數據訪問層 數據層
調業務 無技術難度 與業務無關
誰依賴誰就看誰調用誰。
軟件的分層設計,便於任務的劃分、降低層間的耦合。
結合PMS的設計方法,思考這樣分層的好處。
並且,使代碼儘量減少重複,可複用性好,擴展餘地加大,而且儘量減少硬編碼。
需求:實現對Person類的數據庫持久化基本操作(CRUD)。
BS架構和CS架構:
C-S架構:兩層體系結構,主要應用於局域網中。
B-S架構:三層體系結構,表現層+業務邏輯層+數據存儲層
注:層面越多,軟件越複雜,但更靈活。分層是必須的但是要有個度。
層次一但確定,數據必須按層訪問,不能跨層訪問。
層與層之間最好時單向依賴(單向調用)。
縱向劃分:按功能劃分。分成三層體系結構(也有兩層的)。
橫向劃分:按抽象劃分。分成抽象部分和實現部分。
/***以下老師沒講的內容******/
一、JDBC異常處理:
JDBC中,和異常相關的兩個類是SQLException和SQLWarning。
1.SQLException類:用來處理較爲嚴重的異常情況。
比如:① 傳輸的SQL語句語法的錯誤;
② JDBC程序連接斷開;
③ SQL語句中使用了錯誤的函數。
SQLException提供以下方法:
getNextException() —— 用來返回異常棧中的下一個相關異常;
getErrorCode() —— 用來返回代表異常的整數代碼 (error code);
getMessage() —— 用來返回異常的描述信息 (error message)。
2.SQLWarning類:用來處理不太嚴重的異常情況,也就是一些警告性的異常。
其提供的方法和使用與SQLException基本相似。
結合異常的兩種處理方式,明確何時採用哪種。
A. throws 處理不了,或者要讓調用者知道;
B. try … catch 能自行處理,就進行異常處理。
二、JavaBean的定義:
1、是一個普通的Java類
2、在結構上沒有預先的規定,不需要容器,不需要繼承類或實現接口
3、要求必須放在包中,要求實現Serializable接口
4、要求有一個無參的構造方法.
5、屬性的類型必須保持唯一,get方法返回值必須和set方法參數類型一致
6、對每個屬性要有對應的get和set方法。注:隱藏屬性可以沒有
7、可以有外觀作爲顯示控制,事件機制。
三、SQL數據類型及其相應的Java數據類型
SQL數據類型 ? ? ? ? ? ? Java數據類型 ? ? ? ? ? ? ?說明
??---------------------------------------------------------------------------------------
? ?INTEGER或者INT ? ? ? ? ? int ? ? ? ? ? ? ? 通常是個32位整數
? ?SMALLINT ? ? ? ? ? ? ? short ? ? ? ? ? ? 通常是個16位整數
? ?NUMBER(m,n) ? ? ? Java.sql.Numeric ? ?合計位數是m的定點十進制數,小數後面有n位數
DECIMAL(m,n) 同上
? ?DEC(m,n) ? ? ? ? ? ? ? Java.sql.Numeric ? ?合計位數是m的定點十進制數,小數後面有n位數
? ?FLOAT(n) ? ? ? ? ? ? ? double ? ? ? ? ? 運算精度爲n位二進制數的浮點數
? ?REAL ? ? ? ? ? ? ? ? ? float ? ? ? ? ? ?通常是32位浮點數
? ?DOUBLE ? ? ? ? ? ? ? ? double ? ? ? ? ? 通常是64位浮點數
? CHAR(n) ? ? ? ? ? String ? ? ? ? ? 長度爲n的固定長度字符串
CHARACTER(n) 同上
? ?VARCHAR(n) ? ? ? ? ? ?String ? ? ? ? ? 最大長度爲n的可變長度字符串
? ?BOOLEAN ? ? ? ? ? ? ? ?boolean ? ? ? ? ?布爾值
? ?DATE ? ? ? ? ? ? ? ? ? Java.sql.Date ? ? 根據具體設備而實現的日曆日期
? ?TIME ? ? ? ? ? ? ? ? ? Java.sql.Time ? ? ? 根據具體設備而實現的時戳
? ?TIMESTAMP ? ? ? ? ? ?? Java.sql.Timestamp ?根據具體設備而實現的當日日期和時間
? ?BLOB ? ? ? ? ? ? ? ? Java.sql.Blob ? ?? 二進制大型對象
? ?CLOB ? ? ? ? ? ? ? ? ?Java.sql.Clob ? ?? 字符大型對象
? ?ARRAY ? ? ? ? ? ? ? ?? Java.sql.Array
四、 面向對象的數據庫設計
類的關聯,繼承在數據庫中的體現:
類定義―――>表定義
類屬性―――>表字段
類關係―――>表關係
對 象―――>表記錄
注: Oid(對象id)―――>業務無關
在數據庫中每一條記錄都對應一個唯一的id;
Id通常是用來表示記錄的唯一性的,通常會使用業務無關的數字類型
字段的個數不會影響數據庫的性能,表則越多性能越低。
(一)類繼承關係對應表,
1、 爲每一個類建一張表。通過父類的Oid來體現繼承關係。
特點:在子類表中引用父類表的主建作爲自己的外建。
優點:方便查詢。屬性沒有冗餘。支持多態。
缺點:表多,讀寫效率低。生成報表比較麻煩。
2、 爲每一個具體實現類建一個表
特點:父類的屬性被分配到每一個子類表中。
優點:報表比較容易
缺點:如果父類發生改變會引起所有子類表隨之更改。並且不支持多態。數據有少量冗餘。
3、 所有的類在一張表中體現,加一個類型辨別字段
特點:效率高,查詢不方便,用於字段不多時。
優點:支持多態,生成報表很簡單。
缺點:如果任何一個類發生變化,必須改表。字段多,難以維護。
(二)類關聯關係對應表
1、 一對一關聯,類關係對應成表時有兩種做法:
一是引用主鍵,也就是一方引用另一方的主鍵既作爲外鍵有作爲自身的主鍵。
二是外鍵引用,一方引用另一方的主鍵作爲自身的外鍵,並且自己擁有主鍵。
2、 一對多關聯,也就是多端引用一端的主鍵當作外鍵,多端自身擁有主鍵。
3、 多對多關係,多對多關係是通過中間表來實現的,中間表引用兩表的主鍵當作聯合主鍵,就可以實現多對多關聯。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.