?? day03.txt
字號:
JDBC_day03 langna 2007-9-10 星期一
一、事務并發:
事務并發:事務和事務之間有時間重合的地方;
并發:
1、必須的;
2、產生某些不良的后果;
3、某些手段來控制;
從效率上來說,并發是必須的;但是不良的后果得消除;
三種后果:
1、臟讀(dirty read):
dirty data;修改了一半的數據,還沒有提交;
一個事務讀到了另一個事務沒有提交的數據;
事務a:存100;1000 + 100 --> 1100(未提交)--> rollback; --->1000
事務b: 1100+200---> 1300----> commit; 造成數據不一致;
后果很嚴重;大多數數據庫將防止臟讀,作為默認的控制級別;
2、不可重復讀(UnRepeatable Read):
一個事務在事務期間,前后對同一組數據進行讀操作,讀到的結果不一致;
原因是:在這個事務兩次讀的中間,有其他事務提交了數據;
與臟讀不同的是 :讀的是已提交的數據;
(update)
事務a: 存100;1000+100--> 1100--> 提交時先讀一下,跟1000不同了,不能存1100了;
如果仍存上1100,就是更新(1200)丟失;
在a持續的期間:事務b: 存200;1000+200--> 提交 :1200
對于即時改變的東西(天氣預報)沒關系,但是對于累加的東西(銀行帳戶)不能出現更新丟失的情況;
3、幻讀(phantom read):
在一個事務的執行期間,前后兩次讀同一組數據,數據量不一致;記錄個數增加或減少;
(insert)
銀行統計:
10萬個帳戶,--> 余額 :10億
存的時候又變成:100100個帳戶;
商場盤點:關門進行;
二、事務隔離級別:
TRANSACTION_NONE 不使用事務。沒有什么用;只是理論上的,實際無意義;
TRANSACTION_READ_UNCOMMITTED 沒有控制;可以讀取未提交數據。也無實際意義;
TRANSACTION_READ_COMMITTED 可以避免臟讀,不能夠讀取沒提交的數據,
最常用的隔離級別,大部分數據庫的默認隔離級別;
TRANSACTION_REPEATABLE_READ 可以避免臟讀,和不可重復讀;
TRANSACTION_SERIALIZABLE 可以避免臟讀,重復讀取和幻讀,
(事務串行化)會降低數據庫效率
后兩種在很多數據庫中是沒有區別的;防止提交別的數據,即不讓別的事務操作,
一個事務一個事務串行執行;小范圍內沒有并發;效率低;
用的不多;一般是在代碼中控制;
Oracle:就支持兩種,防止臟讀和串行化;
以上的五個事務隔離級別都是在Connection類中定義的靜態常量,
使用setTransactionIsolation(int level) 方法可以設置事務隔離級別。
三、JDBC新特性:
四、五、六章是2.0的擴展;
對resultset的擴展
對statement的增強(批處理)
sql3.0類型(blob/clob)
datasource(jndi)
rowset
1、JDBC2.0 ResultSet 可滾動結果集(可雙向滾動),這種結果集不但可以雙向滾動,
相對定位,絕對定位,并且可以修改數據信息。
滾動特性
next(),boolean,此方法是使游標向下一條記錄移動。(向最后一條記錄的方向移動)
previous() ,此方法可以使游標上一條記錄移動,前提前面還有記錄。(向第一條記錄的方向移動)
absolute(int row),boolean ,可以使用此方法跳到指定的記錄位置。
定位成功返回true,不成功返回false,返回值為false,則游標不會移動。
afterLast() ,void 游標跳到最后一條記錄之后。
beforeFirst() ,void 游標跳到第一條記錄之前。(跳到游標初始位)
first(),boolean,游標指向第一條記錄。
last(),boolean ,游標指向最后一條記錄。
relative(int rows) ,相對移動的位置個數,參數值可正可負,參數為正,
游標從當前位置向下移動指定值,參數為負,
游標從當前位置向上移動指定值。
TYPE_FORWARD_ONLY ,該常量指示指針只能向前移動的 ResultSet 對象的類型。
TYPE_SCROLL_INSENSITIVE ,該常量指示可滾動但通常不受其他的更改影響的 ResultSet 對象的類型。
TYPE_SCROLL_SENSITIVE ,該常量指示可滾動并且通常受其他的更改影響的 ResultSet 對象的類型。
有的數據庫支持,有的不支持;
我們用哪個都可以,只要支持可滾動的
CONCUR_READ_ONLY ;//只讀結果集
CONCUR_UPDATABLE; //可更新結果集,可以通過結果集來更新數據庫;用在小應用中;快速開發;
在驅動程序支持2.0特性的情況下,會給你一個你要的結果集類型:
要使用可滾動結果集時,要在Statement創建時指定兩個參數,才可以使用
Statement st=null;
st=con.createStatement(ReusltSet.TYPE_SCROLL_INSENSITIVE,ResuleSet.CONCUR_UPDATABLE);
PreparedStatement ps-null;
ps=con.PrepareStatement("select * from t_test",ResultSet.TYPE_SCROLL_INSENSITIVE,
ResuleSet.CONCUR_READ_ONLY);//順序不能顛倒,否則編譯可過,運行會報錯;
rs=ps.executeQuery();
JdbcUtil.printRs(rs);//這時候游標已經指向最后一條記錄的后邊了;
if(rs.isAfterLast()){sysout("最后一條記錄的后邊 ");}
rs.beforeFirst();//移動到前邊
sysout("-----------------------");
JdbcUtil.printRs(rs);
CONCUR_UPDATABLE; //增刪改都可以;
1) 更新
移到要更新的記錄處:rs.absolute(3);
rs.updateInt(1,"1243535");
rs.updateString("name","tony");
rs.updateRow();//提交一下
2) 刪除
rs.absolute(10);
rs.deleteRow();
3) 插入
a. rs.moveToInsertRow();//1、先把游標移動到插入緩沖區;跟結果集結構一樣;并且把游標本來的位置記住;
-----------------插入數據,b,c 可以重復
b. rs.updateInt(1,"1243535");//2、填充緩沖區
rs.updateString("name","tony");
c. rs.insertRow();//3、將緩沖區的內容放到數據庫中;
-----------------
b. rs.updateInt(1,"1243535");
rs.updateString("name","tony");
c. rs.insertRow();//3、將緩沖區的內容放到數據庫中;
----------------
d. rs.moveToCurrentRow();//4、將游標移回到原來的位置;
支持不支持可更新結果集 得看數據庫的驅動;
還有別的限制:下午講;
1)對于Oracle用可更新的結果集:
select id,name from t_test;//不能用通配符select * from t_test;
2)查詢只能引用一張表;
3)不能有join操作;不能用order by 等其他操作;
4)會取所有非空字段且沒有默認值;
5)插入結果集是無序的;
記住做完修改的操作后,要提交后再從數據庫中讀一次結果集才能看到修改的結果;
2、批處理更新
一般是20~50~100,會提高效率;
1) Statement
addBatch(String sql), 方法會在批處理緩存中加入一條sql語句
executeBatch() ,執行批處理緩存中的所有sql語句。
2) PreparedStatement
ps = con.prepareStatement(
"insert into t_test values(?,?)");
for(int i=0;i<50;i++){
ps.setInt(1,999801+i);
ps.setString(2,"batch");
ps.addBatch();
}
ps.executeBatch();
con.commit();
addBatch() 將一組參數添加到此 PreparedStatement 對象的批處理命令中。
executeBatch() 將一批命令提交給數據庫來執行,如果全部命令執行成功,則返回更新計數組成的數組。
PreparedStatement中使用批量更新時,要先設置好參數后使用addBatch()方法加入緩存。
注意:批量更新中只能使用更新或插入語句
execute(String sql),這個方法的返回值是boolean類型,
如果返回true就表示sql是一個select語句,
可以通過getResultSet()獲得結果集,
如果是false,sql就是DML語句或者是DDL語句。
3、 SQL3.0 (SQL99)中的類型
Array,數組 創建一個數組名為ints的有10個元素的數組,元素的類型為number(4);
create type ints as Array(10) of number(4);
create table numbers(values ints);
數據庫類型:ARRAY; 數據庫中的類型;ARRAY a=((OracleResultSet)rs.getARRAY(1));//這種基本不用了;
1) jdbc類型:java.sql.Array;Array a=rs.getArray(1);//
2) java類型:BigDecimal[] values=(BigDecimal[])a.getArray();//將Object[]轉成你想要的類型;
Sturct,結構
create type money as numberic(10,2);
Ref, 引用;用的很少;
Blob,大的二進制數據文件。Binary large object
Clob,大文本文件對象。 Character large object
以前處理大對象:有大小上限;是固定的,雖然可調大小;
讀的方式:一次性讀取,要么全讀走,要么不讀;rs;
Blob:
1)理論上大小不限;
2)流式讀取;(是引用)讀的時候才傳過來;
往數據庫中存blob數據:
con.setAutoCommit(false);
//1、委托oracle替我們制造一個空的Blob字段,empty_blob();是oracle的函數
ps=con.prepareStatement("insert into t_blob values(?,?,empty_blob())");
//2、將空的Blob對象讀回來;
JdbcUtil.close(ps);//釋放資源
ps=con.prepareStatement("select blobData from t_blob where id=? for update");
//for update,加一個讀鎖;防止別的事務修改;
//游標變成可寫的,普通的結果集的sql加for update 就可以改字段的值;
rs=ps.executeQuery();
rs.next();
Blob blob=rs.getBlob(1);
//3、打開一個文件輸入流(讀),打開一個blob上的輸出流(寫),將文件內容寫入blob對象;
InputStream in=new FileInputStream(fname);
OutputStream out=blob.setBinaryStream(0);//0是下標,設置從流的第一個字節寫;
byte[] content =new byte[in.available()];//將文件中的所有字節寫到一個字節數組里
in.read(content);
out.write(content);
in.close();
out.close();
//4、將寫滿數據的blob對象更新回數據庫
ps=con.prepareStatement("update t_blob set blobData=? where id=?");
ps.setBlob(1,blob);
ps.setInt(2,100);
ps.executeUpdate();
con.commit();
create table ln_blob(id number(10) primary key,filename varchar2(20),blobData blob);
insert into ln_blob values(100,null,null);
不能用sqlplus檢索blob字段;select * from ln_blob;//是不能用的;
從數據庫中讀blob數據:
//1.讀blob值
ps = con.prepareStatement(
"select blobdata from t_blob where fname=?");
ps.setString(1,fname);
rs = ps.executeQuery();
rs.next();
blob = rs.getBlob(1);
//2.將blob值寫入文件
OutputStream out = new FileOutputStream(fname);
InputStream in = blob.getBinaryStream();
int b = 0; int c = 0;int x=0;
while((b=in.read())!=-1){
if((++c%1024)==0){
System.out.println("here we go ..."+(++x)+"kb");
}
out.write(b);
}
in.close();out.close();
}catch (Exception ex){
ex.printStackTrace();
}finally{
JdbcUtil.close(rs,ps,con);
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -