一.JDBC原理概述
1,JDBC是一套協議,是JAVA開發人員和數據庫廠商達成的協議,也就是由Sun定義一組接口,由數據庫廠商來實現,并規定了JAVA開發人員訪問數據庫所使用的方法的調用規范。
2,JDBC的實現是由數據庫廠商提供,以驅動程序形式提供。
3,JDBC在使用前要先加載驅動。
JDBC對于使用者要有一致性,對不同的數據庫其使用方法都是相同的。
driver開發必須要實現Driver接口。
四種數據庫驅動的實現方式
JDBC-ODBC橋接式
JDBC網絡驅動,這種方式是通過中間服務器的協議轉換來實現的
JDBC+本地驅動,這種方式的安全性比較差
JDBC驅動,由數據庫廠商實現。
二.JDBC的API
java.sql包和javax.sql包
1.Driver接口 代表驅動程序
2.DriverManager類(驅動管理器),它可以創建連接,它本身就是一個創建Connection的工廠(Factory)。
3.Connection接口,代表數據庫連接,會根據不同的驅動產生不同的連接
4.Statement接口,執行sql語句
5. PreparedStatement接口執行sql語句(預編譯)
6.CallableStatement接口 發送sql語句
7.ResultSet接口(結果集),是用來接收select語句返回的查尋結果的。其實質類似
于集合。
8.DatabaseMetaData 數據庫元數據
9.ResultSetMetaData 結果集元數據
10.Types:特殊的類。只包含靜態的常量,代表JDBC類型。JDBC類型是標準SQL類型的子集
三、事務
1).原子性,一致性,隔離性,持久性
事務是一個數據操作單元,能夠保證在該單元內執行的多個SQL語句,或者一起成
功,或者一起失敗.
2).事務的并發控制:
(dirty)臟讀:一個事務能讀到另外一個事務沒有提交的數據
不可重復讀:在同一個事務的兩次查詢中,發現值不同,叫做不可重復讀.這是因為在
兩次查詢之間,另外一個事務修改了數據并提交了.
(phantom)幻影讀:在同一個事務的兩次查詢中,發現記錄的數目不同,叫做幻影讀.
這是因為在兩次查詢之間,另外一個事務增加或者刪除了數據并提交了.
3).隔離級別
Connection 類中的五個靜態常量
A.不使用事務 TRANSACTION_NONE
B.允許臟讀 TRANSACTION_READ_UNCOMMITTED
C.不允許臟讀 TRANSACTION_READ_COMMITTED
D.防止不可重復讀,臟讀 TRANSACTION_REPEATABLE_READ
F.事務串行化 TRANSACTION_SERIALIZABLE
四、JDBC編程步驟
1,注冊加載一個driver驅動
2,創建數據庫連接(Connection)
3,創建一個Statement(發送sql)
4,執行sql語句
5,處理sql結果ResultSet(select語句)
6,關閉sql結果ResultSet (如果有)
7,關閉Statement
8,關閉連接Connection
注意:6,7,8兩個步驟必須要做的,因為這些資源是不會自動釋放的,必須要自己關閉
1,注冊加載驅動driver,也就是強制類加載
一般來說我們使用方法1
方法1) Class.forName(Driver包名.Driver類名)。
eg:加載oracle
Class.forName("oracle.jdbc.driver.OracleDriver");
方法2)Driver d=new oracle.jdbc.driver.OracleDriver();
DriverManager.registerDriver(d);
方法3)java -Djdbc.drivers=驅動全名 類名
Oracle的Driver的全名:oracle.jdbc.driver.OracleDriver
mysql的Driver的全名:com.mysql.jdbc.Driver 或 org.gjt.mm.mysql.Driver
SQLServer的Driver的全名:com.microsoft.jdbc.sqlserver.SQLServerDriver
2,創建連接
DriverManager.getConnection(String url,String username,String
password);
Connection連接是通過DriverManager的靜態方法getConnection(.....)來得到
的,這個方法的實質是把參數傳到實際的Driver中的connect()方法中來獲得數
據庫連接的。
Oracle的URL值是由連接數據庫的協議和數據庫的IP地址及端口號還有要連接的
庫名(DatebaseName)
Oracle URL的格式
jdbc:oracle:thin:@數據庫IP地址:端口號:數據庫名(sid)
如:oracle所在服務器地址為192.168.0.254,而端口號為默認的1521,數據
庫名為tarena,那么URL就應寫成
jdbc:oracle:thin:@192.168.0.254:1521:tarena
MySql URL的格式
jdbc:mysql://數據庫IP地址:端口號/數據庫名
例: jdbc:mysql://localhost:3306/test
訪問本機時IP地址用localhost和127.0.0.1都可以
SQLServer URL的寫法
例:jdbc:microsoft:sqlserver://localhost:1433
3、創建Statement
使用Connection對象獲得一個Statement
Statement中的方法:
1) executeQuery(String sql) 方法可以使用select語句查詢,并且返回一個結
果集ResultSet,通過遍歷這個ResultSet,可以獲得select語句的查尋結果。
ResultSet rs = stmt.executeQuery(“select * from person”);
2)executeUpdate(String sql) 方法用于執行DDL和DML語句,可以update,
delete操作。
此方法返回一個int類型的值,表示此條sql語句影響的記錄條數
Int count = stmt.executeUpdate(“delete from person where pid=1”);
Int count = stmt.executeUpdate(“update person set name=’jack’,age=’20’
where pid=1”);
3)execute(String sql) 這個方法的返回值是boolean類型
如果返回true就表示sql是一個select語句,然后通過getResultSet()獲得結果
集
如果返回false ,sql就是DML語句或者是DDL語句,即沒有結果集,
然后通過getUpdateCount()方法 獲得更新的記錄條數。
在不能明確傳入sql是何種類型的操作時使用此方法。
if (stmt.execute(sql)) {
ResultSet rs = stmt.getResultSet();
} else {
int count = stmt.getUpdateCount();
}
4)getUpdateCount() 返回更新的記錄條數
4.處理結果集ResultSet(結果集里存儲的是二維的結構,相當于一張表)
ResultSet rs = stmt.executeQuery(“select pid, name, age from person”);
Person person = null;
while(rs.next) {
person = new Person();
person.setPid(rs.getInt(1));//jdbc下標是從1開始
person.setName(rs.getString(“name”));//也可使用列名來得到數據
person.setAge(rs.getInt(3));
}
1) next()方法會操作一個游標從第一條記錄的前邊開始讀取,直到最后一條記錄。
由于結果集返回來之后游標的位置在第一條記錄的前面,所以調用next()方
法不會丟失數據。
2) getXXX(int index)其中XXX代表數據庫中存儲的數據類型相對應的java數據
類型,
此方法可以根據指定順序獲得字段值,注:順序是從1開始的。
eg: int cid = rs.getInt(1);
String cname = rs.getString(2);
3) getXXX(String columnName):此方法可以根據指定字段的名字獲取字段的值
eg: int cid = rs.getInt("cid");
String cname = rs.getString("cname");
4)updateXXX() XXX代表的是相應的類型,無返回值
5) isXXXX() XXXX代表的是游標的位置First,Last。。。返回布爾值
5.資源的關閉順序:
要按先ResultSet結果集,然后Statement,最后Connection的順序關閉資源。
因為Statement和ResultSet是需要連接是才可以使用的,所以在使用結束之后
有可能起他的Statement還需要連接,
所以不能現關閉Connection。
//關閉結果集
if (rs != null) try {rs.close()} catch (SQLException e) { e.printStackTrace();}
//關閉Statement
if (stmt != null) try { stmt.close()} catch (SQLException e) {
e.printStackTrace();}
//關閉鏈接
if (conn != null) try { conn.close()} catch (SQLException e) {
e.printStackTrace();}
6.PreparedStatement(預編譯的Statement)
PreparedStatement 用來執行同構的SQL,它的創建方式:
PreparedStatement pstmt = con.prepareStatement("insert into clazz values(?,?)");
可以使用參數替代sql語句中的某些參數使用"?"代替,他先將帶參數的sql語句發送到數據庫,
進行編譯,然后PreparedStatement會將參數發送給數據庫。
在使用PreparedStatement時,設置相應參數要指明參數的位置和類型,以及給出參數值
根據不同的參數類型使用不同的setXXX(參數的位置,參數值)來設置參數
結構跟此方法類似:setInt(int parameterIndex, int x)
pstmt.setInt(1,i);
pstmt.setString(2,"xxx"+i)
7.CallableStatement
CallableStatement是可以用非sql語句來訪問數據庫,他是通過調用存儲過程(PL/SQL)來訪問數據
庫的。
可以直接使用連接來調用 prepareCall(...)方法,來執行這個存儲過程,"..."是存儲過程的名字。
8.SQLException是檢查異常必須處理,要么throws ,要么try{}catch(){}
getErrorCode()可以獲得錯誤碼,可以對錯誤進行查詢。
五、元數據
元數據就是描述數據庫或其組成部分的數據。(區別于存儲在數據庫中的實際數據)
它用來輔助我們更好的處理數據庫的用戶數據[通俗的講就是指容器的結果的信息]
JDBC中有兩種元數據,一種是數據庫元數據(DatabaseMetaData),另一種是結果集元數據(ResultSetMetaData)
1.數據庫元數據
如果要想了解數據庫的更多信息。可以從數據庫連接中獲取一個DatabaseMetaData
DatabaseMetaData dmd=conn.getMetaData();
然后可以調用如下的方法獲得數據庫相關的信息
getURL(),獲得連接數據庫的URL
getDatabaseProductName() 獲得數據庫產品的名稱
getDriverVersion() 獲得JDBC驅動程序的String形式的版本號
getTables()獲得數據庫中該用戶的所有表
getUserName() 獲得數據庫用戶名。
2.結果集元數據
ResultSet rs=ps.executeQuery();
ResultSetMetaData m=rs.getMetaData();
getColumnCount(),獲得實際列數
getColumnName(int colnum),獲得指定列的列名
getColumnType(int colnum),獲得指定列的數據類型
getColumnTypeName(int colnum),獲得指定列的數據類型名
例如:ResultSetMetaData md = rs.getMetaData();
// 得到字段個數
int cols = md.getColumnCount();
// 根據字段個數遍歷和打印結果集
StringBuffer sb = new StringBuffer();
for (int i = 0; i < cols; i++) {
sb.append(md.getColumnName(i + 1) + " ");
}
動態獲得表結構
六、JDBC2.0新特性
默認方式獲得的結果集都是1.0的結果集
能否使用JDBC2.0 ResultSet的新特性要看數據庫驅動程序是否支持。
1.可滾動結果集(可雙向滾動),(了解 能說出結果集滾動的方法即可)
這種結果集不但可以雙向滾動,相對定位,絕對定位,并且可以修改數據信息。
要使用可滾動結果集時,要在Statement創建時指定參數,才可以使用
Statement st=null;(int,int)(可滾動特性,可更新特性)
st=con.createStatement(ReusltSet.TYPE_SCROLL_INSENSITIVE,ResuleSet.CONCUR_UPDATABLE)
PreparedStatement
ps=con.createPrepareStatement(sql,ReusltSet.TYPE_SCROLL_INSENSITIVE,ResuleSet.CONCUR_
UPDATABLE);
ResultSet rs=ps.executeQuery(sql);
滾動特性
next(),此方法是使游標向下一條記錄移動。
previous() ,此方法可以使游標向上一條記錄移動,前提前面還有記錄。
absolute(int row),絕對定位函數可以使用此方法跳到指定的記錄位置。定位成功返回true,不成功返
回false,返回值為false,則游標不會移動。
afterLast() ,游標跳到最后一條記錄 之后,(結果集一回來時就有的位置)。無返回值。
beforeFirst() ,游標跳到第一條記錄 之前,(結果集一回來時就有的位置)。(跳到游標初始位)無返回
值
first(),游標指向第一條記錄。
last(),有彪指向最后一條記錄。
relative(int rows),相對定位方法,參數值可正可負,參數為正,
游標從當前位置向下移動指定值,參數為負,游標從當前位置向上移動指定值。
ResultSet可滾動性的屬性值:
TYPE_FORWARD_ONLY ,單向,該常量指示指針只能向前移動的 ResultSet 對象的類型。不可滾動。
TYPE_SCROLL_INSENSITIVE ,雙向,對數據庫的變化不敏感
TYPE_SCROLL_SENSITIVE ,雙向,對數據庫的變化敏感
ResultSet 對象的類型。該特性某些數據庫不支持。
ResultSet可更新性的屬性值:
CUNCUR_READ_ONLY,不可更新的結果集
CUNCUR_UPDATEABLE,可更新的結果集
2.可更新的結果集:(不常用,也不推薦使用)(了解)
如果你想能夠編輯結果集中的數據,并且將結果集上的數據自動反應到數據庫中,
那么就必須使用可更新的結果集,可更新結果集不一定是可滾動的,獲得可更新結果集的方法:
Statement
stat=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATE
ABLE);
這樣,調用executeQuery()方法返回的結果集就是可更新的結果集。
例如:
String query="SELECT * FROM books";
ResultSet rs=stat.executeQuery(query);
While(rs.next){
If(.......){
Double inscrease=.......;
Double price=rs.getDouble("Price");
rs.updateDouble("Price",price+inscrease);
rs.updateRow();
}
}
所有的對應于SQL類型的數據類型都配有updateXXX方法。與getXXX方法類似。使用updateXXX方法是必須指定列的名稱或序列號。
然后,可以給 該字段設置新的值。
updateXXX方法改變的只是結果集中的行值,而非數據庫中的值。當更新完行中的字段值后,必須調用
updateRow方法,這個方法將當前的行中所有更新信息發送給數據庫。如果沒有調用updateRow方法就將
游標移動到其他行上。那么所以的更新信息就將被丟棄,而且永遠不會被傳遞給數據庫。還可以調用cancelRowUpates方法來取消對當前行的更新。
以上是更新數據庫中的一行記錄,如果想在數據庫中添加一條新的記錄,首先需要使用moveToInsertRow
()方法將游標移動到特定的位置。然后調用updateXXX()方法在插入行的位置上創建一個新的行。然后調用
insertRow()方法將新建的行發送給數據庫。完成插入操作后在調用moveToCurrentRow()方法講游標移回到調用moveToInsertRow方法之前的位置:
例子:
rs.moveToInsertRow();
rs.updateString("Title",title);
rs.updateString("Price",price);
..........
rs.insertRow();
rs.moveToCurrentRow();
如果要刪除一行調用rs.deleteRow()即可刪除結果集和數據庫中的一行
能否使用可更新結果集,要看使用的數據庫驅動是否支持,還有只能用于單表且表中有主鍵字段(可能會是
聯合主鍵),不能夠有表連接,會取所有非空字段且沒有默認值。結果集用select * from t也不行,不能用
*,不能排序
3,批處理更新 (熟記于心)
Statement.
addBatch(String sql), 方法會在批處理緩存中加入一條sql語句
executeBatch() ,執行批處理緩存中的所有sql語句。
PreparedStatement. 先準備一組參數
addBatch() 將一組參數添加到此 PreparedStatement 對象的批處理命令中。
executeBatch() 將一批命令提交給數據庫來執行,如果全部命令執行成功,則返回更新計數組成的數組。
PreparedStatement中使用批量更新時,要先設置好參數后使用addBatch()方法加入緩存。
注意:批量更新中用更新或插入語句
面向對象的數據庫設計
Id通常是用來表示記錄的唯一性的,通常會使用業務無關的數字類型
Object id 對象的id,sequence只有Oracle才可用,對象id(OID)使用高低位算法先生成高位,在生成低位,通過運算獲得對象id。
類應當對象到表,屬性對應字段,對象對應記錄。
類繼承關系對應表,
1,每個類建一個表,為父子類每個類都對應的創建表,這種方法類關系清晰,但是如果類比較多就不適合了
2,只有具體類才建表,也就是把父類中的屬性均勻分配到子類的表中,也就是父類不建表,這種表關系不能使用多態
3,所有類對應一張表,這種方法是在表中加上一個字段來區分父子類,但是只能用于類屬性較少的情況下,而且數據會有冗余。
類關聯關系對應表
1,一對一關聯,類關系對應成表時有兩種做法,一是引用主鍵,也就是一方引用另一方的主鍵既作為外鍵又作為自身的主鍵。
二是外鍵引用,一方引用另一方的主鍵作為自身的外鍵,并且自己擁有主鍵。
2,一對多關聯,也就是多端引用一端的主鍵當作外鍵,多端自身擁有主鍵。
3,多對多關系,多對多關系是通過中間表來實現的,中間表引用兩表的主鍵當作聯合主鍵,就可以實現多對多關聯。
posted on 2009-03-31 19:41
faye 閱讀(709)
評論(0) 編輯 收藏