上午:
一.JDBC原理概述
?
1,JDBC是一套協(xié)議,是JAVA開發(fā)人員和數(shù)據(jù)庫廠商達(dá)成的協(xié)議,也就是由Sun定義一組接口,由數(shù)據(jù)庫廠商來實(shí)現(xiàn),并規(guī)定了JAVA開發(fā)人員訪問數(shù)據(jù)庫所使用的方法的調(diào)用規(guī)范。
?
2,JDBC的實(shí)現(xiàn)是由數(shù)據(jù)庫廠商提供,以驅(qū)動(dòng)程序形式提供。
?
3,JDBC在使用前要先加載驅(qū)動(dòng)。
JDBC對(duì)于使用者要有一致性,對(duì)不同的數(shù)據(jù)庫其使用方法都是相同的。
?
驅(qū)動(dòng)開發(fā)必須要實(shí)現(xiàn)Driver接口。
數(shù)據(jù)庫驅(qū)動(dòng)的實(shí)現(xiàn)方式
JDBC-ODBC橋接式
JDBC網(wǎng)絡(luò)驅(qū)動(dòng),這種方式是通過中間服務(wù)器的協(xié)議轉(zhuǎn)換來實(shí)現(xiàn)的
JDBC+本地驅(qū)動(dòng),這種方式的安全性比較差。
JDBC驅(qū)動(dòng),由數(shù)據(jù)庫廠商實(shí)現(xiàn)。
?
二.JDBC的API
?
java.sql包和javax.sql包
Driver接口(驅(qū)動(dòng)),在加載某一 Driver 類時(shí),它應(yīng)該創(chuàng)建自己的實(shí)例并向 DriverManager 注冊該實(shí)例。這意味著用戶可以通過調(diào)用以下程序加載和注冊一個(gè)驅(qū)動(dòng)程序
Class.forName("oracle.jdbc.driver.OracleDriver")
DriverManager類(驅(qū)動(dòng)管理器),它可以創(chuàng)建連接,它本身就是一個(gè)創(chuàng)建Connection的工廠(Factory)。
Connection接口,會(huì)根據(jù)不同的驅(qū)動(dòng)產(chǎn)生不同的連接
Statement接口,發(fā)送sql語句
ResultSet接口(結(jié)果集),是用來接收select語句返回的查詢結(jié)果的。其實(shí)質(zhì)類似于集合。
?
下午:
三.JDBC應(yīng)用步驟
1,注冊加載一個(gè)driver驅(qū)動(dòng)
2,創(chuàng)建數(shù)據(jù)庫連接(Connection)
3,創(chuàng)建一個(gè)Statement(發(fā)送sql)
4,執(zhí)行sql語句
5,處理sql結(jié)果(select語句)
6,關(guān)閉Statement
7,關(guān)閉連接Connection。
?
注意:6,7兩個(gè)步驟勢必須要做的,因?yàn)檫@些資源是不會(huì)自動(dòng)釋放的,必須要自己關(guān)閉
?
訪問Oracle的數(shù)據(jù)庫的驅(qū)動(dòng)名字叫ojdbc14.jar,要使用這個(gè)驅(qū)動(dòng)程序,要先將他加到環(huán)境變量CLASSPATH中。
?
??? 注冊加載驅(qū)動(dòng)driver,也就是強(qiáng)制類加載
??? Class.forName(Driver包名.Driver類名)。
?
??? Driver d=new Driver類();//注意:這個(gè)方法不能用參數(shù)來構(gòu)造
??? DriverManager.registerDriver(d);
?
?
??? Oracle的Driver的全名oracle.jdbc.driver.OracleDriver
??? mysql的Driver的全名com.mysql.jdbc.Driver
??? SQLServer的Driver的全名com.microsoft.jdbc.sqlserver.SQLServerDriver
?
??? 創(chuàng)建連接
??? DriverManager.getConnection(String url,String username,String password);
??? Connection連接是通過DriverManager的靜態(tài)方法getConnection(.....)來得到的,這個(gè)方法的實(shí)質(zhì)是把參數(shù)傳到實(shí)際的Driver中的connect()方法中來獲得數(shù)據(jù)庫連接的。
??? Oracle的URL值是由連接數(shù)據(jù)庫的協(xié)議和數(shù)據(jù)庫的IP地址及端口號(hào)還有要連接的數(shù)據(jù)庫的庫名(DatebaseName)
??? Oracle URL的格式
??? jdbc:oracle:thin:(協(xié)議)@XXX.XXX.X.XXX:XXXX(IP地址及端口號(hào)):XXXXXXX(所使用的庫名)
??? 例:jdbc:oracle:thin:@192.168.0.20:1521:tarenadb
??? MySql URL的寫法
??? 例: jdbc:mysql://localhost:3306/tarena
??? SQLServer URL的寫法
??? 例:jdbc:microsoft:sqlserver://localhost:1433/test
?
??? java -Djdbc.drivers=驅(qū)動(dòng)的完整類名
?
??? 使用虛擬機(jī)參數(shù),加載驅(qū)動(dòng) -D表示為虛擬機(jī)參數(shù)賦值
??? java -Djdbc.drivers=oracle.jdbc.driver.OracleDriver:com.mysql.jdbc.Driver
??
四.JDBC基本方法
??? DriverManager:如果有多個(gè)驅(qū)動(dòng)可用的話,DriverManager會(huì)選擇其中一個(gè).?
???
??? Driver:可以選擇固定的驅(qū)動(dòng)
??? Driver driver = new oracle.jdbc.driver.OracleDriver();
??? String user = "sd0613";
?String password = "sd0613";
?Properties prop = new Properties();
?prop.setProperty("user",user);
?prop.setProperty("password",password);
??? driver.connect(url,properties);
???
??? executeQuery(sqlString);//返回結(jié)果集
??? executeUpdate(sqlString);//返回值為該次操作影響的記錄條數(shù),create table返回0
??? execute(sqlString);
??? //適用于不知道具體的操作是什么,返回值是boolean類型的
??? //如果返回值是true,代表執(zhí)行查詢操作;否則代表執(zhí)行更新操作.
???
??? ResultSet
??? next()方法:
??? 1.判斷是否存在下一條記錄
??? 2.將游標(biāo)移向下一條記錄??
??? getXXX(字段名或字段序號(hào))//注意:字段序號(hào)從1開始
???
??? 關(guān)閉問題:
??? 使用Connection對(duì)象獲得一個(gè)Statement,Statement中的executeQuery(String sql) 方法可以使用select語句查詢,并且返回一個(gè)結(jié)果集 ResultSet通過遍歷這個(gè)結(jié)果集,可以獲得select語句的查詢結(jié)果,ResultSet的next()方法會(huì)操作一個(gè)游標(biāo)從第一條記錄的前邊開始讀取,直到最后一條記錄。executeUpdate(String sql) 方法用于執(zhí)行DDL和DML語句,可以u(píng)pdate,delete操作。
注意:要按先ResultSet結(jié)果集,后Statement,最后Connection的順序關(guān)閉資源,因?yàn)镾tatement和ResultSet是需要連接時(shí)才可以使用的,所以在使用結(jié)束之后有可能其他的Statement還需要連接,所以不能先關(guān)閉Connection。
1.回憶下昨天的一些JDBC的配置
?(1) 驅(qū)動(dòng):??
??ojdbc14.jar (Oracle)?????????????????
??mysql-connector-java-3.1.11-bin.jar(MySql)
?(2) 實(shí)現(xiàn)了Driver接口的驅(qū)動(dòng)類(程序中要加載的類):
??jdbc.oracle.driver.OracleDriver? (Oracle)
??com.mysql.jdbc.Driver? (MySql)
?(3)連接數(shù)據(jù)庫的URL
??jdbc:oracle:thin:@192.168.0.24:1521:tarena?? (Oracle)
??jdbc:mysql://192.168.0.24:3306/test??? (MySql)
?????????
2.PreparedStatement概述
?SQL語句傳到數(shù)據(jù)庫后,數(shù)據(jù)庫會(huì)先對(duì)其編譯再執(zhí)行。在使用Statement時(shí),如果要執(zhí)行一組類似的SQL操作時(shí),這樣做效率很低,而且把不同類型的數(shù)據(jù)直接寫在SQL語句中是比較麻煩的。這時(shí)應(yīng)該用PreparedStatement來代替Statement,PreparedStatement 接口繼承 Statement,并和他在兩方面有所不同:
?(1)PreparedStatement 實(shí)例包含已編譯的 SQL 語句。這就是使語句先“準(zhǔn)備好”。包含于 PreparedStatement對(duì)象中的SQL 語句可具有一個(gè)或多個(gè) IN 參數(shù)。IN參數(shù)的值在 SQL 語句創(chuàng)建時(shí)未被指定。相反的,該語句為每個(gè) IN 參數(shù)保留一個(gè)問號(hào)(“?”)作為占位符。每個(gè)問號(hào)的值必須在該語句執(zhí)行之前,通過適當(dāng)?shù)膕etXXX 方法來提供。
?(2)由于 PreparedStatement 對(duì)象已預(yù)編譯過,所以其執(zhí)行速度要快于 Statement 對(duì)象。因此,多次執(zhí)行的 SQL 語句經(jīng)常創(chuàng)建為 PreparedStatement 對(duì)象,以提高效率。
??
?作為 Statement 的子類,PreparedStatement 繼承了 Statement 的所有功能。另外它還添加了一整套方法,用于設(shè)置發(fā)送給數(shù)據(jù)庫以取代 IN 參數(shù)占位符的值。同時(shí),三種方法 execute()、 executeQuery() 和 executeUpdate() 已被更改以使之不再需要參數(shù)。這些方法的 Statement 形式(接受 SQL 語句參數(shù)的形式)不應(yīng)該用于 PreparedStatement 對(duì)象。
3.創(chuàng)建 PreparedStatement 對(duì)象
?以下的代碼段(其中 con 是 Connection 對(duì)象)創(chuàng)建包含帶兩個(gè) IN 參數(shù)占位符的 SQL 語句的 PreparedStatement 對(duì)象:
?PreparedStatement pstmt = con.prepareStatement("UPDATE table4 SET m = ? WHERE x = ?");
?pstmt 對(duì)象包含語句 "UPDATE table4 SET m = ? WHERE x = ?",它已發(fā)送給DBMS,并編譯好為執(zhí)行作好了準(zhǔn)備。
?
4.傳遞 IN 參數(shù)
?在執(zhí)行 PreparedStatement 對(duì)象之前,必須設(shè)置每個(gè) ? 參數(shù)的值。這可通過調(diào)用 setXXX 方法來完成,其中 XXX 是與該參數(shù)相應(yīng)的類型。例如,如果參數(shù)具有Java 類型 long,則使用的方法就是 setLong。setXXX 方法的第一個(gè)參數(shù)是要設(shè)置的參數(shù)的序數(shù)位置(從1開始),第二個(gè)參數(shù)是設(shè)置給該參數(shù)的值。例如,以下代碼將第一個(gè)參數(shù)設(shè)為 123456789,第二個(gè)參數(shù)設(shè)為 100000000:
?pstmt.setLong(1, 123456789);
?pstmt.setLong(2, 100000000);
5.ResultSetMetaData
?元數(shù)據(jù)是用來描述數(shù)據(jù)的數(shù)據(jù),ResultSetMetaData就是來描述結(jié)果集的列的類型和屬性信息,比如可以通過它得到結(jié)果集的列數(shù),列名等。具體可在API中查閱java.sql.ResultSetMetaData。
?ResultSetMetaData對(duì)象可以通過ResultSet對(duì)象的getMetaData()來得到。
?ResultSetMetaData對(duì)象有以下三個(gè)方法比較常用:
?getColumnCount():獲得實(shí)際列數(shù)
?getColumnName(int colnum):獲得指定列的列名
?getColumnType(int colnum):獲得指定列的數(shù)據(jù)類型(Types里面的類型,存放的是整數(shù))
?
6.JDBC是持久層的技術(shù),是JAVA連接數(shù)據(jù)庫目前最通用的手段。其他的持久層技術(shù),比如接下來我們要學(xué)的Hibernate,底層也是由JDBC實(shí)現(xiàn)的。持久層是與業(yè)務(wù)無關(guān)的,具體的業(yè)務(wù)由業(yè)務(wù)層完成,當(dāng)業(yè)務(wù)層需要和數(shù)據(jù)庫進(jìn)行交互時(shí),就需要通過持久層來操作。
7.BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
?由于System.in是字節(jié)流,我們需要把他轉(zhuǎn)成字符流。并用BufferedReader包裝后方便我們的操作。
?
8.為了區(qū)分表中不同的數(shù)據(jù),我們要給放入表中持久化的每個(gè)對(duì)象都加上一個(gè)唯一的標(biāo)識(shí),這就是ID,ID是與業(yè)務(wù)無關(guān)的。ID的生成方法有很多,在Oracle數(shù)據(jù)庫中我們一半利用Sequence來生成。
9.讀取配置文件時(shí),我們采用Properties對(duì)象。它是HashTable的子類,它有個(gè)load(InputStream inStream) 的方法可以直接從輸入流中讀取屬性列表(鍵值對(duì))。getProperty(String key) 方法用指定的鍵在此屬性列表中搜索值。
1.Registering a driver
2.Establishing a connection to the datebase
3.Creating a statement
4.Executing a SQL
5.Processing the results
6.Closing down JDBC objects
JDBC第三天
上午:
一.事務(wù)(Transaction)
原子操作:不可再分的操作,一個(gè)操作不能再分成比它更細(xì)小的操作.
事務(wù)是針對(duì)原子操作的,要求原子操作不可再分,并且必須同時(shí)成功同時(shí)失敗。
事務(wù)就是把一些非原子操作,變成原子操作,由應(yīng)用服務(wù)器來提出要求,由數(shù)據(jù)庫服務(wù)器來執(zhí)行操作.
在JDBC中默認(rèn)是自動(dòng)提交的,如果要想使用事務(wù),需要按以下步驟執(zhí)行:
1.要調(diào)用con.setAutoCommite(false)方法(打開事務(wù)邊界),把自動(dòng)提交(commit)置為false。
2.進(jìn)行正常的數(shù)據(jù)庫操作
3.如果操作成功了可以選擇con.commit(),或者操作失敗時(shí)選擇con.roolback()------
?? (回滾:數(shù)據(jù)恢復(fù)到之前的情況)
? 注意:打開事務(wù)就要關(guān)閉自動(dòng)提交,當(dāng)不需要再使用事務(wù)的時(shí)候調(diào)用
setAutoCommite(true).
事務(wù)性資源(監(jiān)控完整性)
?
二.事務(wù)并發(fā)產(chǎn)生的問題
??? 三種并發(fā)產(chǎn)生的后果:
1,臟讀:一個(gè)事務(wù)讀取到了另外一個(gè)事務(wù)沒有提交的數(shù)據(jù)。(Dirty Read)
2,重復(fù)讀:一個(gè)事務(wù)讀取到了另外一個(gè)事務(wù)提交的數(shù)據(jù)。它是要保持在同一時(shí)間點(diǎn)上讀取到的數(shù)據(jù)相同,希望在一段時(shí)間內(nèi)的數(shù)據(jù)是不變的。
3,幻讀:一個(gè)事務(wù)讀取到了另外一個(gè)事務(wù)提交的數(shù)據(jù)。用同樣的操作讀取兩次,得到的記錄數(shù)不相同。
三.事務(wù)隔離級(jí)別
??? 五種控制級(jí)別:
TRANSACTION_NONE不使用事務(wù)。
TRANSACTION_READ_UNCOMMITTED 允許臟讀。
TRANSACTION_READ_COMMITTED防止臟讀,最常用的隔離級(jí)別,并且是大多數(shù)數(shù)據(jù)庫的默認(rèn)隔離級(jí)別----------------------
TRANSACTION_REPEATABLE_READ可以防止臟讀和不可重復(fù)讀,
TRANSACTION_SERIALIZABLE可以防止臟讀,不可重復(fù)讀取和幻讀,(事務(wù)串行化)會(huì)降低數(shù)據(jù)庫的效率
以上的五個(gè)事務(wù)隔離級(jí)別都是在Connection類中定義的靜態(tài)常量,使用setTransactionIsolation(int level) 方法可以設(shè)置事務(wù)隔離級(jí)別。
如:con.setTransactionIsolation(Connection.REPEATABLE_READ);
下午:
四.JDBC2.0新特性
1.可滾動(dòng)特性和可更新特性
JDBC1.0中是指游標(biāo)的移動(dòng)的方向和方式是單向,單步(相對(duì))移動(dòng),功能比較簡單.
JDBC2.0中游標(biāo)可以雙向,相對(duì)或者絕對(duì)移動(dòng).
可滾動(dòng)結(jié)果集:這種結(jié)果集不但可以雙向滾動(dòng),相對(duì)定位,絕對(duì)定位,并且還可以修改數(shù)據(jù)信息。
1)滾動(dòng)特性
定位函數(shù):aaa
boolean absolute(int row),定位到指定的記錄位置。定位成功返回true,不成功返回false。
void afterLast() ,把游標(biāo)移動(dòng)到最后一條記錄的后面(邏輯位置)。 一定會(huì)有的
void beforeFirst() ,把游標(biāo)移動(dòng)到第一條記錄的前面(邏輯位置)。
//由于第一條記錄的前面和最后一條記錄的后面這兩個(gè)位置肯定存在,所以無需判斷是否存在,返回值設(shè)為void.
boolean first(),把游標(biāo)定位到第一條記錄,相對(duì)定位;
boolean last(),把游標(biāo)定位到最后一條記錄?? 也是相對(duì)的概念。
//當(dāng)結(jié)果集為空的時(shí)候,這兩個(gè)方法會(huì)返回false.
boolean next(),此方法是使游標(biāo)向下一條記錄移動(dòng)。
boolean previous() ,此方法可以使游標(biāo)向上一條記錄移動(dòng),前提是前面還有記錄。
boolean relative(int rows) ,相對(duì)定位方法,參數(shù)值可正可負(fù),參數(shù)為正,游標(biāo)從當(dāng)前位置向后移動(dòng)指定值條記錄,參數(shù)為負(fù),游標(biāo)從當(dāng)前位置向前移動(dòng)指定值條記錄。
判斷函數(shù):
ifBeforeFirst()判斷是否在在第一條記錄之前.
ifAfterLast()判斷是否在在最后一條記錄之后.
ifFirst()判斷是否為第一條記錄.
ifLast()判斷是否為最后一條記錄.
要使用可滾動(dòng)結(jié)果集時(shí),需要一次設(shè)置更新特性與滾動(dòng)特性,不能分開.
1.更新特性常量:
CONCUR_READ_ONLY 只讀結(jié)果集???? (默認(rèn)的)
CONCUR_UPDATABLE 可更新結(jié)果集
2.滾動(dòng)特性常量:
TYPE_FORWARD_ONLY ,該常量表示指針只能向前移動(dòng)的 ResultSet 對(duì)象的類型。(默認(rèn))
雙向滾動(dòng):
?不敏感:TYPE_SCROLL_INSENSITIVE ,該常量指示可滾動(dòng)但通常不受其他更改影響的 ResultSet 對(duì)象的類型。
?敏感的:TYPE_SCROLL_SENSITIVE ,該常量指示可滾動(dòng)并且通常受其他更改影響的 ResultSet 對(duì)象的類型。
//敏感:數(shù)據(jù)庫改變,結(jié)果集改變.
語法:????????
Statement st=null;
st=con.createStatement(ReusltSet.TYPE_SCROLL_INSENSITIVE,ResuleSet.CONCUR_UPDATABLE)
在創(chuàng)建Statement的時(shí)候就要指定這兩個(gè)參數(shù),使用Statement,第一個(gè)參數(shù)代表滾動(dòng)特性常量,第二個(gè)代表更新特性常量
----------------------------------------
2)可更新特性
a.moveToInsertRow();記錄當(dāng)前游標(biāo)位置,將游標(biāo)移到和結(jié)果集結(jié)構(gòu)類似的緩沖區(qū);
b.使用updateXxx(int column,columnType value)方法來更新指定列數(shù)據(jù);
c.使用insertRow() 方法插入記錄,加信結(jié)果集,更新
d.將游標(biāo)指回原位,moveToCurrentRow() 。
?2,3步,可循環(huán)
-----------------------------------------------------
能否使用JDBC2.0 ResultSet的新特性,要看使用的數(shù)據(jù)庫驅(qū)動(dòng)是否支持.
還有只能用于單表且表中有主鍵字段(可能會(huì)是聯(lián)合主鍵),不能夠有表連接,會(huì)取
可更新操作必須滿足以下條件:
a.查詢只能引用一張表.
b.不能包含任何連接操作.
c.必須把完整的主鍵查到結(jié)果集里面;
d.保證所有字段為非空字段并且沒有默認(rèn)值。
五.數(shù)據(jù)庫元數(shù)據(jù):
DatabaseMetaData dbmd = con.getMetaData();//得到數(shù)據(jù)庫元數(shù)據(jù)
dbmd.supportsResultSetConcurrency(ResultSet.TYPE_FORWARD_ONLY,
??????????????????? ResultSet.CONCUR_UPDATABLE);//判斷是否支持可更新操作
六.批量更新
優(yōu)勢:
1.節(jié)省傳遞時(shí)間
2.并發(fā)處理
PreparedStatement:
1.addBatch() 將一組參數(shù)添加到 PreparedStatement對(duì)象內(nèi)部
2.executeBatch() 將一批參數(shù)提交給數(shù)據(jù)庫來執(zhí)行,如果全部命令執(zhí)行成功,則返回更新計(jì)數(shù)組成的數(shù)組。
Statement:
addBatch(String sql)方法會(huì)在批處理緩存中加入一條sql語句
executeBatch()執(zhí)行批處理緩存中的所有sql語句。
注意:PreparedStatement中使用批量更新時(shí),要先設(shè)置好參數(shù)后再使用addBatch()方法加入緩存。
批量更新中只能使用更新或插入語句
//
Statement stm=con.createStatement(int resultSetType,int resultSetConcurrency);創(chuàng)建的時(shí)候就要指明要什么樣的結(jié)果集。
??先可滾,后可更新
boolean absolute (int row)絕對(duì)定位,
afterLast()定位到最后一條記錄的后面
?
?
?
?
?
?
?
?
?
?
?
?
posted on 2007-03-21 16:14
sunny 閱讀(1018)
評(píng)論(0) 編輯 收藏