📄 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 + -