??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲AV永久无码精品一百度影院 ,国产精品亚洲mnbav网站,亚洲国产综合第一精品小说http://www.tkk7.com/juhongtao/category/6845.htmlzh-cnFri, 02 Mar 2007 03:34:03 GMTFri, 02 Mar 2007 03:34:03 GMT60JDBC高应用?/title><link>http://www.tkk7.com/juhongtao/archive/2006/01/09/27258.html</link><dc:creator>javaGrowing</dc:creator><author>javaGrowing</author><pubDate>Mon, 09 Jan 2006 07:01:00 GMT</pubDate><guid>http://www.tkk7.com/juhongtao/archive/2006/01/09/27258.html</guid><wfw:comment>http://www.tkk7.com/juhongtao/comments/27258.html</wfw:comment><comments>http://www.tkk7.com/juhongtao/archive/2006/01/09/27258.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/juhongtao/comments/commentRss/27258.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/juhongtao/services/trackbacks/27258.html</trackback:ping><description><![CDATA[JDBC高应用?BR><BR>再谈JDBCq结<BR><BR>Z么要反复谈JDBCq结,因ؓ(f)所以JDBC的性能,最主要的就是JDBCq结,而SQL语句?BR>优化,和JAVA~程无关,你的一个查询语句的效率,是你对于SQL语法的用技?q一?BR>面你可hDBA,而不是来看我q种E序设计者的文章.<BR><BR>我们已经知道,取得数据库连l?有几U层ơ的实现Ҏ(gu),一是直接得到物理连l?而是?BR>q传l的q结?没有多大区别),三是通过java的扩展包javax.sql.DataSource得到q结<BR>句柄,对于上面两种,没有什么可以多说的,对于DataSource,我们再深入一?<BR>一般来?DataSource是容器本w作Z个JDNI查找的对象返回出来的,也就是说要依?BR>容器q行配置,而如果一?00%的应用程?Application),比如Zswing的App,我根?BR>不需要运行容?那我如何取得DataSource对象?q时可能要你自己写基于DataSource?BR>q结池了(是不是有些太深入?要做做高手,SUN能做我们p?.<BR>如果自己要实现DataSource,要清楚几个关p?即DataSource中返回的Connection是一个连<BR>l的句柄,它要和实际的物理q结兌,q些实际的物理连l就是PooledConnection,我们<BR>叫它池中的连l?可以通过实现ConnectionPoolDataSource,从中得到PooledConnection,<BR>q部分本来是厂商实现?但这部䆾实现和传l的q结池没有什么大的区?主要是从<BR>ConnectionPoolDataSource中得到PooledConnection的物理连l?但如何从PooledConnection<BR>中getConnection(),q回l用?q部分实现就是DataSource实现的性能高低的关?一?BR>来说,我们可以先把一个物理连lPooledConnection和多个客戯l相兌来增加性能,?BR>是一个PooledConnection本n再作Z个工场的U子,通过一个PooledConnection再返?BR>多个Connection,说白了就是多个Connection的请求通过一个PooledConnection传递给数据?<BR>只要用户调用Connection的close()Ҏ(gu),打断这个Connetion与PooledConnection的关联?BR>让PooledConnection可以和新的Connectionq行兌.<BR><BR>JDBC事务<BR><BR>JDBC1开?支持本C?所谓要C?是在一个连l中的多个操作可以作Z个事?BR>q程来提?注意,只要你用conn.setAutoCommit(false);Ҏ(gu)隐式地打开了一个事??BR>事务被commit或abort?隐含的是打开了一个新的事?<BR>另外,当一ơ事务被commit或abort,PreparedSattement和CallableStatementl定的结果集?BR>部被关闭,而普通的Statementl一的结果集被l持.<BR>在处理多个操作时:<BR>conn.setAutoCommit(false);<BR>Statement st1 = conn.createSatatement(sql1);<BR>Statement st2 = conn.createSatatement(sql2);<BR>Statement st3 = conn.createSatatement(sql3);<BR>Statement st4 = conn.createSatatement(sql4);<BR>st1.executeXXXXX();<BR>st2.executeXXXXX();<BR>st3.executeXXXXX();<BR>st4.executeXXXXX();<BR>在这?我们要么把四个操作一起回?或一h?但如果我们认?1-3的操作是要求一致完<BR>??的操作在一至三完成时再完成.在经前的版本中我们要把它们分开在两ơ事务中,但在<BR>JDBC3.0以后,我们可以利用conn.setSavepoint() 来得C个SavePoint来对同一事务中不同阶<BR>D进行断点保?然后可以在Q何断点上q行提交和回?同时我们q可以利?BR>conn.setTransactionIsolation()来设|隔ȝ?<BR>要注意的?对事务的支持要看数据库的具体实现.如果数据库本w不支持事务,那么以上的操?BR>都是无效?可以?nbsp;DatabaseMetaData中查询数据库对事务的支持情况.<BR><BR>毕竟,本地事务功能q不是很?而如果不是编Eh员对SQL语句传入错误,那么在一ơ连l中<BR>多个操作只完成部份的机率q不Ҏ(gu)发生(当然有时q会(x)发生?要不本地事务׃?x)生?.<BR>其实,JDBC事务最重要的是分布式事?卛_时操作不同的q结,可能是同物理库的不同I间,?BR>可能是同一L的不同数据库或不同主机的多个数据?q就很难保证每个操作都是成功??BR>生操作不一致的Z(x)太多?可以说如果不在事务中试你就无法怿操作的一致?所以分?BR>式事务是JDBC的重要技?<BR>在下一节我们重点介lJDBC分布式事? <img src ="http://www.tkk7.com/juhongtao/aggbug/27258.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/juhongtao/" target="_blank">javaGrowing</a> 2006-01-09 15:01 <a href="http://www.tkk7.com/juhongtao/archive/2006/01/09/27258.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBC高应用?http://www.tkk7.com/juhongtao/archive/2006/01/09/27221.htmljavaGrowingjavaGrowingMon, 09 Jan 2006 02:08:00 GMThttp://www.tkk7.com/juhongtao/archive/2006/01/09/27221.htmlhttp://www.tkk7.com/juhongtao/comments/27221.htmlhttp://www.tkk7.com/juhongtao/archive/2006/01/09/27221.html#Feedback0http://www.tkk7.com/juhongtao/comments/commentRss/27221.htmlhttp://www.tkk7.com/juhongtao/services/trackbacks/27221.html本来想l谈JDBC的高U连l方?事务模式.但发现关于大对象存储有很多h在问,所?BR>先来插入一节关于大对象存储的内?然后再接着原来的思\写下?

JDBC的大对象存储听v来复?其实如果你明白了原理以后,非常简?|上有关q方面的
教材很少,而SUN的文档中,我从1.2开始看C在仍然是错误?不知道写文档的h长脑子没
?那几行代码你试试不q道了,q么多次重抄下来q是错误?


大对象分c?一般来?大对象分?大的文本对象,比如一个很长的文本(请你要注意什么是
文本文g,什么是二进制文?文g,或者是你定义的一个长字符?比如你定义了:
String s = "我们要去吃饭?.....................然后睡觉!";
从吃饭到睡觉中间省略了实际的10000000000000?虽然你不?x)真的定义这么称的String,?BR>有时?x)从什么地方得到这L(fng)String,要写到数据库?
另一U就是大的二q制对象,象执行文?图象文g{?注意,word,excel,pptq些"带格?的文
档都应该以二q制对象存储.

一般来?数据库如果支持大对象存储,?x)有q几U类型的SQL数据cd:
BLOB,CLOCB,NLOB,也有的数据数只有一UBLOB,基本上是q样?BLOB用来存放二进制文??BR>CLOB用来存放文本文g,NLOB是对多字节文本文件支?假如你的文本文g是纯英文?攑֜
BLOB中当然可?也就是说它是以byte格式存储?而多字节是以CHAR格式存储?

同样对于q几U类型的文档,有几U相对应的存取方?
setter:
利用PreparedStatement的setXXXҎ(gu),
setAsciiStream()Ҏ(gu)用于写入一般的文本?setBinaryStream()Ҏ(gu)用于写入二进制流
而setUnicodeStream()用于写好UNICODE~码的文?与此相对应的ResultSet中三个getterҎ(gu)
用于取回:getAsciiStream(),getBinaryStream(),getBinaryStream().
对于文g本n,要把它作Z个流,只要new InputStream(new FileInputStream("文g路径"))
可以了,但对于大的String对象,你不?x)写入文件再转换成输入流?
new StringBufferInputStream(String s),C?
JDBC2以后提供了java.sql.BLOB对象,我不大家使用?一是很ȝ,二是Ҏ(gu)出错,要先?BR>入一个空的BLOB对象,然后再填充它,实在没有必要,直接setXXXp?我试q?臛_mysql,
oracle,sql server是可以直接set?
好了,我们先看一个例子如何写入文件到数据?
数据l构:
create table test(
  name varchar(200),
  content BLOB
);
File f = new File("a.exe");//先生成File对象是ؓ(f)了取得流的长?FileInputStram可以直接
                           //传入文g路径
InputStream in = new InputStream(new FileInputStream(f));
PreparedStatement ps = conn.prepareStatement("insert into test (?,?)");
ps.setString(1,"a.exe");
ps.setBinaryStream(2,in,(int)f.length());
ps.executeUpdate();
f的长度一定要做从long到int的{?SUN的文档中好几版都没有改过?p么简?当然,不同?BR>数据库存本n要设|它允许的最大长?MYSQL默认只能?M的文?要修改参数原能存更大的文?
如果要从数库中取得文?
PreparedStatement ps = conn.prepareStatement("select * from test where name=?");
ps.setString(1,"a.exe");
ResultSet rs = ps.executeQuery();
if(rs.next()){
 InputStream in = rs.getBinaryStream("content");
}
得到in对象?你可以进行Q何处?写向文g和写向页面只是out对象不同而已:
写向文g:
DateOutputStream out = new DateOutputStream(new FileOutputStream("b.exe"));
写向面:
response.reset();
response.setContType("cd");
ServletOutputSreamt out = response.getOutputSream();
得到out对象?可以输Z:
byte[] buf = new byte[1024];
int len = 0;
while((len = in.read(buf)) >0)
  out.write(buf,0,len);
in.close();
out.close();
对于向页面输?要设|什么样的ContType,要看你想如何输出,如果你想让对方下?p?BR>"application/octet-stream",q样即是文?图象都会(x)下蝲而不?x)在览器中打开.如果你要?BR>在浏览器中打开,p讄相应的类?q要在容器的配置文g中设|支持这U文档类型的输出,?BR>对于很多格式的文?到底要输Z么类?其实是HTTP的MIME?比如囄:image/gif,当然你如
果你的文件扩展名(ext)不确?你也不要用if(ext.equals("gif"))......q样来判?我教你一?BR>技?我之所以说是技?是我没有在别的地方发现有人用q种Ҏ(gu),Ҏ(gu)来说我是l对不会(x)把别人的
Ҏ(gu)拿来说是我的技巧的:
构造一个filecd的URL,我们知道URL目前JAVA可以支持HTTP,FTP,MAILTO,FILE,LDAP{?从FILEcd
的URL可以得到它的MIME:

URL u = new URL("file://a.exe");
String mime = u.openConnection().getContentType();
q样你就可以直接response.setContType(mime);而不用一个一个类型判断了.
好了,大对象存储就说到q儿,不同的数据仍然和些特D的规定,不在此一一列D?

javaGrowing 2006-01-09 10:08 发表评论
]]>
JDBC的高U应用一 http://www.tkk7.com/juhongtao/archive/2006/01/09/27220.htmljavaGrowingjavaGrowingMon, 09 Jan 2006 02:07:00 GMThttp://www.tkk7.com/juhongtao/archive/2006/01/09/27220.htmlhttp://www.tkk7.com/juhongtao/comments/27220.htmlhttp://www.tkk7.com/juhongtao/archive/2006/01/09/27220.html#Feedback0http://www.tkk7.com/juhongtao/comments/commentRss/27220.htmlhttp://www.tkk7.com/juhongtao/services/trackbacks/27220.html
关于数据库连l?BR>
我们所说有JDBC高应用,q不是说它的技术含量很?也许JAVAq_上不存在什?技术含?的说
?因ؓ(f)JAVA是给大家用的而不是给某些人用?.说它是高U应?是因为它是对于JDBC基础应用?BR>说的扩展,也就是可以优化你的应用性能,或方便于应用的实?所以说它是一U高U应用而不叫高U?BR>技?

    JDBC?java.sql包是基础?也是核心的功?javax.sql包则是高U的,扩展的功?所?BR>Z交流的方?我们把它们区分ؓ(f)core API和optional API.

    但是仍然然有一些core API中的功能,我把它归U_高应用?象存储过E的调用,多结果集
的处?我之所以要把这些东西拿出来说明,是目前你在网上找不到M一份详l的文档和例E?可以
说有95%以上的开发h员都不知道真正如何处理这些工?所以我?x)在回上后详细写这一D늚内容.
现在我们q是来看看optional APIl我们带来的好处:

    我们已经了解,执行一个SQL语句,要经q如下几?
    1.Connction
    2.Statement
    3.Statement.executeXXXXX();
    4.可选的对结果集的处?BR>    5.必要的Connction的关?(再次提醒如果你想成ؓ(f)中水^以上的程序员,请你把关闭语
    句写在finally块中,在通过下面的介l后我介l一个方法可以用来验证你的程序是否有q结
    泄漏)
    
    q其?生成Connction对象是最最重要的工?也是最消耗资源的,因ؓ(f)q结对象要驱动底?BR>的SOCKET,调用物理q结和数据库q行通信,所以生?关闭,再生成这U连l对象就相当于我们在二十
世纪八十q代(1980q以后出w的不了解吧?)喝易拉罐饮料一?你买一瓉料是一块二角钱,你可知道
那罐?Connection)g块零八分.而你喝下ȝ东西只g角二分钱,q是我们那儿一个饮料厂的真?BR>数据.
    在javax.sql包出来以?我们只能买这L(fng)饮料来喝,除非你不?也有一些h不服气自q
产饮?poolman),可是消费者很快发?它只是把原来单卖的易拉罐现在打包卖给了我?因ؓ(f)它还?BR>用原来的包装原料来生产的,poolmanq种cd的连l池,其根本是从DriverManager中getConnection
出来?真正的效率如果不是你心理作用的话,也许比单个连l还要低!!!以及一些江湖好汉的"C",
都无法蟩个框?我自己在那一D|间也N心于研究q些"q结?,因ؓ(f)谁都可以把别人的原码
读过?再加上其他h的优点写Z个更好的?可是,大家可以看到,我写Z好用的Upload,DownLoad,
HtmlUtil,Encoder,Decoder{一pd工具.可是我没有写出成功的q结?......

    我们再来深入一?Z么DriverManager生成的连l和Z它的q结池不能真正提高性能.
DriverManager对象?l大多数的JDBC是封装了一个物理连l?也就是它抓住了一个和数据库通信?BR>Socket,当你使用DriverManager.getConnection()时也是有一个和数据库连l的Socket让你占用?
而且q个Ҏ(gu)是同步的.大家知道q样的物理连l对于Q何系l是有限制的,比如一个WEB服务器一?BR>最大ƈ发是150?50之间,数据库服务器也是q样的道?你不仅要考虑你的E序不能用光q结,q要
考虑不同Runtime中或其它应用E序也在同时和你一起用这些物理连l?如果一台服务器上有JAVA 
WEB SERVER,q有一个C的应用程序也讉K数据?你不能那么无C地要求人家CE序员他的程序必?BR>{你的JAVA调用I闲才能讉K数据库吧.所以物理连l是极其宝贵?
    ZDriverManager.getConnection()的连l池只不q是预先生成q样的物理连l放在一?BR>pool?然后~号{你调用,它省略的是生成这L(fng)q结的时?注意你得到的q结在你没有释放之前,
它无法处理别的工?因ؓ(f)q结句柄在用h?另外q种q结池调用时是由E序调用者初始化?
每一ơ调用都必须有初始化工作,而调用者是否以优化的方法去q行?完成q要看每个h的编E水
q?另一斚w,如果q种q结池是如果用于WEB容器理,那简单是垃圾,因ؓ(f)它强q用静态变量来
保持q结,容器Ҏ(gu)无法做到讉K控制.而且它不能在不同Runtime中被调用.

    而javax.sql的实现采用了在用戯l和物理q结中间加一个缓冲的中间?它虽然也只生
?0个物理连l?但用hw不能访问它,DataSourceq回l用L(fng)是一个JAVA抽象对象,客户E序?BR>q结h攑֛~冲中由DataSourcel一调度物理q结来处?q样可以最大程序利用宝늚物理q结
也许现在?0个物理连l仍然不够负?你仍焉要修改实际连l数,但我们知?我们现在的这U连
l方式已l不是DriverManager.getConnection()能比的了.也就是说,在同样多的物理连l下,
DataSource可以l我们更?是多得多?的调用机?其实,正常情况下一个从DriverManager?BR>getConnection()出来物理q结的负载量只有癑ֈ之几,是因ؓ(f)你的调用抓住了它的句柄而不能让
它很好地工作.另外E序员只能返回它而不能关闭它,因ؓ(f)传统q结池中q结对象一旦由用户关闭,
p再次重新生成物理新的q结,所以用户只能释?对于非连l池和连l池得到的连l对?
要用不同的代码编E?单是一U痛?一旦没有注?在处理完数据后不是释放而是关闭,q个错误
到底是谁的过?????????????

    我上面说java.sql实现l大多数是得到物理连l?也有例外,但不是那些以前的q结?而是
OSE,是oracle的servlet环境,它是把servlet服务器实现在数据库的地址I间?servlet服务去调
用数据库Ҏ(gu)没有通过传统的连l?因ؓ(f)数据?敞开"?q就象通过|络讉K其它计算机文件和讉K
本地文g的区? 虽然它也提供标准的JDBC接口让你调用,但它底层Ҏ(gu)不是用JDBC装?

    DataSource的另外一个优点就是它完全实现数据库和应用E序的分?如何配置服务器生?BR>DataSource的引用和E序开发无?你在E序开发中,只要通过JDNI查找DataSource的逻辑名称p.
而DriverManager.getConnection()?你不得不把数据库驱动E序?讉K地址,用户,密码写在你的
应用E序?即可以从配|文件中dq些属性串,而不同的服务器配|文件的路径你都要修??BR>DataSource提供了标准的配置.

    说来说去,如何用DataSource来连l数据库?

    非常?

    DataSource ds = (DataSource)new InitialContext().lookup("jdbc/mydb");
    Connection conn = ds.getConnection();

    当然我是Z说明它简单故意把它的异常l忽略了.实际应用?你应该捕获它的异?

    如果你还不明白什么是JDNI,我劝你先找一些这斚w的资料看?q可以是|编E方面的
基础协议?

    关于DataSource ds = (DataSource)new InitialContext().lookup("jdbc/mydb");有几?BR>需要说明的?你只要配|好你的服务?tomcat,resin,weblogic)q些服务器中都有一个例?如果
你不是很?你先把那个例子改动几个字p?用一D|间你׃(x)慢慢理解它们代表什么了.
然后你在容器环境下调用new InitialContext().lookup("jdbc/mydb")容器׃(x)自动扑ֈ那个
DataSource对象l你调用,q个q程对用h说是透明?
    那边那个聪明的朋友已l问?因ؓ(f)DataSource的属性是已经配置好的攑֜容器中的,那我
不在容器环境?比如一个独立的application,我如何能取到DataSource?
    其实,如果你能知道new InitialContext()?容器调用了哪些默认的配置,你就可以?BR>q些配置参数手工加进去而不依赖容器环境?好在InitialContext可以getEnvironment() ,在生
成这个对象后你可以get一下看?把这些参数记下来,以后在没有这些参数的环境下putq去.
    q里多几句话,谈一下学?fn)方?我在国内L几个论坛(不多,两三?,从没有问q别Z
么问?java技术又不是我发明的,不可能我什么都?一是问了好象有损于"高手"风范(哈哈,其实
真正的高手还是要问别人的,只有我这U假高手才不?x)问别h).另一斚w是我Ҏ(gu)不必问别?比如
象application?q结不同厂家的DataSource要put什么东西进d?一是去他们的网站看资料,虽然
我的p水^只有大家?0%,但我上英文网站的ơ数可能比你们多.二是看有没有什么共用的API?BR>得到,好在可以getEnvironment(),但假如没有这个方法呢?q就要看你的学习(fn)态度?有h?x)这论?BR>?高手球命",q有什?急用,在线{待"什么的.而我,?x)把new InitialContext()反编译出来看?BR>它调用了什?孔子?Z学习(fn)的目?反编译是允许?甚至说是伟大?光明?正确的思想,是有
道d?q了低U趣味的,有益于h民的行ؓ(f)!!!----孔子语录补集W?23늬4?1989q?0月版)
如果一个对象在构造时要求有参?而它又有一个没有参数的重蝲的构造方?你想惛_肯定在没?BR>参数的构造方法中调用了默认参?你要做的是把它们打印出?有多h是这样做?

    jdbc optional API的其它扩展功?
    javax.sql不仅仅是在性能上的提高,而且它还支持分布式事?在传l的q结q程?我们
可以在一个连l过E中,setAutoCommit()为fasle,然后通过rollback()或commit()那回滚和提交?BR>?q种在一个连l过E中的事务称为本C?但假如在一个事务中要对多个数据库操?或多q?BR>Servlet参与操作,那就必须使用分布式事?

    关于JDBC的事务我?x)放在下面来介?一个值得庆贺的功能出来了,是事务保存点已l?BR>JDBC3.0中实?以前,如果我们把事务原子A,B,C攑֜一个事务中,如果A,B执行?Cp|,我们只能
把A,B都回滚了,但现在我们可以先把A,B保存Z个点,然后以这个点为回滚或提交,q就象在用WORD
~写文章时我们可以在不同的时候保存一个副?而不?x)要么一字没有了,要么是当前~辑的状?

    现在我们来优化我们在基础知识中实现的Bean,今天在家,没法上论?上次写的q结部分
叫什么名字忘C,现在我们叫它PooledDB?
    当时我们已经把那个Bean分ؓ(f)三个部分,把生成连l部分独立出来了,而业务方法部份和?BR>展部分根本不要动?q就是承的好处:)


package com.inmsg.beans;

import javax.naming.*;
import javax.sql.*;

public class PooledDB {
 
      Connection con = null;
      private String source = "";
      public PooledDB() throws Exception {//默认构造方?如果构造时不加参数,q结jdbc/office
            source = "java:comp/env/jdbc/office";
            Context ct = new InitialContext();
            DataSource ds = (DataSource) ct.lookup(source);
          con = ds.getConnection();
    }
    
    //然后增加重蝲Ҏ(gu),用来q结其它的数据源    
    public PooledDB(String source) throws Exception {
            this.source = source;
            Context ct = new InitialContext();
            DataSource ds = (DataSource) ct.lookup(source);
          con = ds.getConnection();
    }
    //注意一定要先把source赋给成员变量this.source,因ؓ(f)下面q有一个makeConnection()
    //辅助Ҏ(gu),如果不把source赋给this.source,则makeConnection()调用默认的source字符?BR>
    private void makeConnection() throws Exception {
            Context ct = new InitialContext();
            DataSource ds = (DataSource) ct.lookup(source);
            con = ds.getConnection();
    }
    
    //现在我们把close()Ҏ(gu)拿到父类来实?q是l过l合考虑?它是一个业务方?无论是什?BR>    //方式取得q结,它本w不?x)修?但ؓ(f)什么还装到父cM?因ؓ(f)q样可以用一个独立的父类?BR>    //做连l测?如果我只惌一下数据库能不能连l?我就不必再引用子c?直接用这个父cd行了
    public void close() throws Exception{
        if(con != null && !con.isClosed()) con.close();
    }
}

    一般来?构造方法尽量捕获异常处理而不要抛出异?但作为Bean的实?捕获异常调用者不Ҏ(gu)
看到异常信息,所以抛l调用者处?另外q个cd要在应用E序中调?又要考虑作ؓ(f)Bean调用,所以一?BR>要有一个无参数的构造方?否则不能作ؓ(f)javaBean调用.把异常抛出给调用者的另一目的,我在设计时是q?BR>栯虑?是你一定在使用try{}catch(){}?q样你就?x)想到再加一个finally{},再次提醒,一定要
以下面的形式来调用你数据库连l的Bean或封装类:
    PooledDB pd = null;
    try{
        pd = new PooledDB();
        ....................
    }
    catch(Exception e){}
    finally{try{pd.close();}catch(Exception ex){}}
    
    如果要测试你的数据库q结是否有泄?请你把DataSource中最大连l数设ؓ(f)1,只用一个连l的?BR>况下,如果你的E序中哪一处没有关闭连l?则下面的E序׃能再讉K,然后从头到尾试你的E序?一?BR>发现不能讉K数据库了,查看刚才访问的代码,q样所有程序测试后,可以放心了,一般来说我是不用这?BR>试?因ؓ(f)我在写数据库q结时是没有生成对象写好close:

    PooledDB pd = null;
    try{}
    catch(Exception e){}
    finally{try{pd.close();}catch(Exception ex){}}
    然后原在try{}的花括号中回车加上pd = PooledDB();和业务代码的 :)当然,你们都比我聪明用?BR>着q样d也不?x)忘记close()?
    不要太高?到目前ؓ(f)止你仍然q没得到一个最好的解决Ҏ(gu),以下我们q会(x)对这个数据库q结?BR>Bean(c?不断优化?.................................

    好了,javax.sql的连l先说到q儿?今天是周?出去玩一?x)?q州街头上没有什么美?)

javaGrowing 2006-01-09 10:07 发表评论
]]>
JDBC基础http://www.tkk7.com/juhongtao/archive/2006/01/09/27218.htmljavaGrowingjavaGrowingMon, 09 Jan 2006 02:04:00 GMThttp://www.tkk7.com/juhongtao/archive/2006/01/09/27218.htmlhttp://www.tkk7.com/juhongtao/comments/27218.htmlhttp://www.tkk7.com/juhongtao/archive/2006/01/09/27218.html#Feedback0http://www.tkk7.com/juhongtao/comments/commentRss/27218.htmlhttp://www.tkk7.com/juhongtao/services/trackbacks/27218.htmlJDBC基础(一)

本来不想写这部䆾入门U的内容,但既然栏目定为JDBC专栏,q是单写一些吧.
JDBC基础(一)

    ?我们认识一?
    JDBC,JAVAq_的DATABASE的连通?白话一?什么意思啊?
    是JAVAq_上和数据库进行连l的"工具".

    q是先一h回顾一下接口吧:从下向上,接口是对"案例"的抽?׃个案例抽象出一些规?
反过?从上向下,被抽象出来的接口是对案例的一U承诺和U束.
    也就是说,只要你实现我规定的接?你的cd已经h了接口对外承诺的Ҏ(gu),只要"客户"?BR>操作接口,不需要重新学?fn)就会(x)操作实C该接口的新类!
    好了,用行话来?
    1.通过接口可以实现不相关的cȝ相同行ؓ(f).
    2.通过接口可以指明多个c需要实现的Ҏ(gu).
    3.通过接口可以了解对象的交互方法而不需要了解对象所对应的类蓝本.
    q几句话很明白吧?好象有一本什么模式的书把q段话用?0多页写出?l果别h看了q不?BR>我这几句话明?不过我明白了Z么有些h要写书了.

    搞懂了以上这东西,JDBC好明白?
    Z通用,JAVA中要求有一U机?在操作不同厂商数据库时有相同的方法去操作,而不是每?BR>触一U数据库p学习(fn)新的Ҏ(gu).完成q种机制?东西"叫"JDBC"?
    单地?JDBC有两部分l成,JDBC API和JDBC Driver Interface.
    JDBC API是提供l?客户"(是象你我这U菜鸟E序员来用的,如果是高手都自己写JDBC?
哈哈)的一l独立于数据库的API,对Q何数据库的操?都可以用q组API来进?那么要把q些通用的API
译成特定数据库能懂?指o",p由JDBC Driver Interface来实C,所以这部䆾是面向JDBC驱动E?BR>序开发商的编E接?它会(x)把我们通过JDBC API发给数据库的通用指o译l他们自q数据?


    q是通过实际操作来看看JDBC如何工作的吧.

    因ؓ(f)JDBC API是通用接口,那么E序是如何知道我要连l的是哪U数据库?所以在和数据库q?BR>l时先要加蝲(或注册可用的Driver),其实是JDBC{֐.加蝲驱动E序和好多方?最常用的就是先把驱
动程序类溶解到内存中,作ؓ(f)"当前"驱动E序.注意"当前"是说内存中可以有多个驱动E序,但只有现在加
载的q个作ؓ(f)首选连l的驱动E序.
    Class.forName("org.gjt.mm.mysql.Driver");
    Class.forNameҎ(gu)是先在内存中溶解{֐?org.gjt.mm.mysql.Driver"的Driverc?Driverc?BR>׃(x)把相应的实现cd应到JDBC API的接口中.比如把org.gjt.mm.mysql.Connection的实例对象赋l?BR>java.sql.Connection接口句柄,以便"客户"能通过操作java.sql.Connection句柄来调用实际的
org.gjt.mm.mysql.Connection中的Ҏ(gu).之于它们是如果映的,q是厂商~程?"客户"只要调用
Class.forName("org.gjt.mm.mysql.Driver");Ҏ(gu)可以顺利地操作JDBC API?

    一个普通数据库的连l过Eؓ(f):
    1.加蝲驱动E序.
    2.通过DriverManager到得一个与数据库连l的句柄.
    3.通过q结句柄l定要执行的语句.
    4.接收执行l果.
    5.可选的对结果的处理.
    6.必要的关闭和数据库的q结.
JDBC基础(?

因ؓ(f)是基?所以还是对每一步骤单说明一下吧:

    前面说是,注册驱动E序有多Ҏ(gu),Class.forName();是一U显式地加蝲.当一个驱
动程序类被Classloader装蝲?在溶解的q程?DriverManager?x)注册这个驱动类的实?
q个调用是自动发生的,也就是说DriverManager.registerDriver()Ҏ(gu)被自动调用了,当然
我们也可以直接调用DriverManager.registerDriver()来注册驱动程?但是,以我的经?
MS的浏览中APPLET在调用这个方法时不能成功,也就是说MS在浏览器中内|的JVM对该Ҏ(gu)?BR>实现是无效的.
    另外我们q可以利用系l属性jdbc.drivers来加载多个驱动程?
System.setProperty("jdbc.drivers","driver1:driver2:.....:drivern");多个驱动E序?BR>间用":"隔开,q样在连l时JDBC?x)按序搜?直到扑ֈW一个能成功q结指定的URL的驱?BR>E序.
    在基里我们先不介绍DataSourceq些高Ҏ(gu)?

    在成功注册驱动程序后,我们可以用DriverManager的静态方法getConnection来得
到和数据库连l的引用:
    Connection conn = DriverManager.getConnection(url);
    如果q结是成功的,则返回Connection对象conn,如果为null或抛出异?则说明没?BR>和数据库建立q结.
    对于getConnection()Ҏ(gu)有三个重载的Ҏ(gu),一U是最单的只给出数据源?
getConnection(url),另一U是同时l出一些数据源信息即getConnection(url,Properties),
另外一U就是给出数据源,用户名和密码:getConnection(url,user,passwod),对于数据源信?
如果我们惛_q结时给出更多的信息可以把这些信息压入到一个Properties,当然可以直接?BR>入用户名密码,别外q可以压入指定字W集,~码方式或默认操作等一些其它信?
    
    在得C个连l后,也就是有了和数据库找交道的通道.我们可以做我们惌的操
作了.
    q是先来介绍一些一般性的操作:
    如果我们要对数据库中的表q行操作,要先~故l定一个语?
    Statement stmt = conn.createStatement();
    然后利用q个语句来执行操?Ҏ(gu)操作目的,可以有两U结果返?如果执行的查?BR>操作,q回为结果集ResultSet,如果执行更新操作,则返回操作的记录数int.
    注意,SQL操作严格区分只有两个,一U就是读操作(查询操作),另一U就是写操作(?BR>新操?,所?create,insert,update,drop,delete{对数据有改写行为的操作都是更新操作.

    ResultSet rs = stmt.executeQuery("select * from table where xxxxx");
    int x = stmt.executeUpdate("delete from table where ......");
    如果你硬要用executeQuery执行一个更新操作是可以?但不要把它赋l一个句?
当然E微有些l验的程序员是不?x)这么做?
    至于对结果集的处?我们攑֜下一节讨?因ؓ(f)它是可操作的可选项,只有查询操作
才返回结果集,对于一ơ操作过E的完成,一个非常必要的步骤是关闭数据库q结,在你没有?BR>解更多的JDBC知识q前,你先把这一步骤作ؓ(f)JDBC操作中最最重要的一?在以后的介绍中我?BR>不断地提醒你d闭数据库q结!!!!!!!!!!!

    按上面介l的步骤,一个完成的例子是这L(fng):(注意,Z按上面的步骤介绍,q个?BR>子不是最好的)
    try{
        Class.forName("org.gjt.mm.mysql.Driver");
    }catch(Exception e){
        System.out.println("没有成功加蝲驱动E序:"+e.toString());
        return;
    }//对于象我q样的经?可以直接从e.toString()的简单的几个字判断出异常原因,
     //如果你是一个新手应该选捕获它的子c?如何知道要捕获哪几个异常?一个简?BR>     //的方法就是先不加try{},直接Class.forName("org.gjt.mm.mysql.Driver");,~?BR>     //译器׃(x)告诉你要你捕获哪几个异常?当然q是h取y的方?最好还是自?BR>     //ȝJDK文档,它会(x)告诉你每个方法有哪些异常要你捕获.
    Connection conn = null;
    try{
        conn = DriverManager.getConnection(
                        "jdbc:mysql://host:3306/mysql",
                        "user",
                        "passwd");
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery("select * from table");
        //rs 处理
        [rs.close();]
        [stmt.close();]
    }
    catch(Exception e){
        System.out.println("数据库操作出现异?"+e.toString());
    }
    finally{
        try{conn.close();}catch(Exception){}
    }//不管你以前是学习(fn)到的关于数据库流E是如何操作?如果你相信我,从现在开?
     //请你一定要把数据库关闭的代码写到finally块中,切切!
JDBC基础(?

关于Statement对象:
    前面说过,Statement对象是用来绑定要执行的操作的,在它上面有三U执行方?
即用来执行查询操作的executeQuery(),用来执行更新操作的executeUpdate()和用来执?BR>动态的未知的操作的execute().
    JDBC在编译时q不对要执行的SQL语句?只是把它看着一个String,只有在驱?BR>E序执行SQL语句时才知道正确与否.
    一个Statement对象同时只能有一个结果集在活?q是宽容性的,是说即使没?BR>调用ResultSet的close()Ҏ(gu),只要打开W二个结果集隐含着对上一个结果集的关?所?BR>如果你想同时对多个结果集操作,p创徏多个Statement对象,如果不需要同时操?那么?BR>以在一个Statement对象上须序操作多个结果集.
    
    q里我不得不特别说明一?很多Z(x)用一个Statementq行嵌套查询,然后来?BR>我说Z么不能@?道理上面已经说清楚了.我们来详l分析一下嵌套查?
    Connection conn = null;
    Statement stmt = null;
    conn = .......;
    stmt = conm.createStatement(xxxxxx);
    ResultSet rs = stmt.executeQuery(sql1);
    while(rs.next()){
        str = rs.getString(xxxxx);
        ResultSet rs1 = stmt.executeQuery("select * from ?nbsp;where 字段=str");
    }
当stmt.executeQuery("select * from ?nbsp;where 字段=str");赋给rs1?q时隐含的操?BR>是已l关闭了rs,你还能@环下d?
所以如果要同时操作多个l果集一定要让它他绑定到不同的Statement对象?好在一个connection
对象可以创徏L多个Statement对象,而不需要你重新获取q结.

    关于获取和设|Statement的选项:只要看看它的getXXXҎ(gu)和setXXXҎ(gu)明白了,q儿
作ؓ(f)基础知识只提一下以下几?
    setQueryTimeout,讄一个SQL执行的超旉?
    setMaxRows,讄l果集能容纳的行?
    setEscapeProcessing,如果参数为true,则驱动程序在把SQL语句发给数据库前q行转义?BR>?否则让数据库自己处理,当然q些默认值都可以通过getҎ(gu)查询.

    Statement的两个子c?
    PreparedStatement:对于同一条语句的多次执行,Statement每次都要把SQL语句发送给数据
?q样做效率明显不?而如果数据库支持预编?PreparedStatement可以先把要执行的语句一ơ发
l它,然后每次执行而不必发送相同的语句,效率当然提高,当然如果数据库不支持预编?
PreparedStatement?x)象Statement一样工?只是效率不高而不需要用户工手干?
    另外PreparedStatementq支持接收参?在预~译后只要传输不同的参数可以执?大大
提高了性能.
        
    PreparedStatement ps = conn.prepareStatement("select * from ?nbsp;where 字段=?");
    ps.setString(1,参数);
    ResultSet rs = ps.executeQuery();
    
    CallableStatement:是PreparedStatement的子c?它只是用来执行存储过E的.
    CallableStatement sc = conn.prepareCall("{call query()}");
    ResultSet rs = cs.executeQuery();
    
    关于更高U的知识我们在JDBC高应用中介l?
JDBC基础(?

    作ؓ(f)基础知识的最后部?我们来说一说结果集的处?当然是说对一般结果集的处?
至于存储q程q回的多l果?我们仍然攑֜高应用中介l?
    SQL语句如何执行的是查询操作,那就要返回一个ResultSet对象,要想把查询结果最?BR>明白地显C给用户,必须对ResultSetq行处理.ResultSetq回的是一个表中符合条件的记录,?BR>ResultSet的处理要逐行处理,而对于每一行的列的处理,则可以按L序(注意,q只是JDBC?BR>范的要求,有些JDBC实现时对于列的处理仍然要求用h序处理,但这是极数?.事实??BR>然你可以在处理列的时候可以按L序,但如果你按从左到右的序则可以得到较高的性能.

    q儿从底层来讲解一下ResultSet对象,在Q何介lJDBC的书上你是不?x)获得这L(fng)?BR>识的,因ؓ(f)那是数据库厂商的?ResultSet对象实际l护的是一个二l指?W一l是指向当前
?最初它指向的是l果集的W一行之?所以如果要讉KW一?p先next(),以后每一行都
要先next()才能讉K,然后W二l的指针指向?只要当你去rs.getXXX(??才通过
Connection再去数据库把真实的数据取出来,否则没有什么机器能真的把要取的数据都放在内
存中.
    所?千万要记?如果Connection已经关闭,那是不可能再从ResultSet中取到数据的.
有很多h问我,我可不可以取C个ResultSet把它写到Session中然后关闭Connection,q样?BR>不要每次都连l了.我只能告诉你,你的x非常??是错误的!当然在javax.sql包中JDBC?BR>U应用中有CacheRow和W(xu)ebCacheRow可以把结果集~存下来,但那和我们自己开一个数据结构把
ResultSet的行集中所有gơ取出来保存h没有什么两?
    讉K行中的列,可以按字D名或烦引来讉K.下面是一个简单的索结果的E序:

    ResultSet rs = stmt.executeQuery("select a1,a2,a3 from table");
    while(rs.next()){
        int i = rs.getInt(1);
        String a = rs.getString("a2");
        ..............
    }

    对于用来昄的结果集,用while来进行next()是最普通的,如果next()q回false,?BR>说明已经没有可用的行?但有时我们可能连一行都没有,而如果有记录又不知道是多行,q时
如果要对有记录和没有记录q行不同的处?应该用以下流E进行判?

    if(rs.next()){
        //因ؓ(f)已经先next()?所l对记录应该用do{}while();来处?BR>        do{
            int i = rs.getInt(1);
            String a = rs.getString("a2");
        }while(rs.next());
    }
    esle{
        System.out.println("没有取得W合条g的记?");
    }

    cd转换:
    ResultSet的getXXXҎ(gu)努力把l果集中的SQL数据cd转换为JAVA的数据类?事实
大多数类型是可以转换?但仍然有不少p弄是不能{换的,如你不能一个SQL的float转换?BR>JAVA的DATE,你无法将 VARCHAR "我们"转换成JAVA的Int.

    较大的?
    对于大于Statement中getMaxFieldSizeq回值的?用普通的getBytes()或getString()
是不能读取的,好在JAVA提供了读取输入浪的方?对于大对?我们可以通过rs.getXXXStream()
来得C个InputStream,XXX的类型包括Ascii,Binay,Unicode.Ҏ(gu)你存储的字段cd来用不
同的类?一般来?二进制文件用getBinayStream(),文本文g用getAsciiStyream(),对于
Unicode字符的文本文件用getUnicodeStream(),相对应的数据库字D늱型应该ؓ(f):Blob,Clob?BR>Nlob.

    获取l果集的信息:
    大多数情况下~程人员Ҏ(gu)据库l构是了解的,可以知道l果集中各列的情?但有时ƈ
不知道结果集中有哪些?是什么类?q时可以通过getMetaData()来获取结果集的情?

    ResulSetMetaData rsmd = rs.getMetaData();
    rsmd.getColumnCount()q回列的个数.
    getColumnLabel(int)q回该int所对应的列的显C标?BR>    getColumnName(int)q回该int所对应的列的在数据库中的名U?
    getColumnType(int)q回该int所对应的列的在数据库中的数据类?
    getColumnTypeName(int)q回该int所对应的列的数据类型在数据源中的名U?
    isReadOnly(int)q回该int所对应的列是否只读.
    isNullable(int)q回该int所对应的列是否可以为空


javaGrowing 2006-01-09 10:04 发表评论
]]>
վ֩ģ壺 ˳ӰԺ| ް߹ۿ| AVһ | ҹƵ| ƷѾƷ| ƷAò| Ƭѹۿȫ| ޾Ʒþþþþο| Ѿþþþþþ| Ļר| ˮwww| ĻþþƷAPP| 9i9ƷѾþ| gvС߹ۿ| պ伤Ƶ߲| 18gay̨ͬͬ| µĻ| ޳aƬ߹ۿ| ѹۿĻƷ| 뾫Ʒþþþ| 91鶹ƷԲ߹ۿ| Ļϵ| ۺС˵þ| 弶ëƬѲ| һëƬȫ| þþƷҹɫav| һëƬ| ޾Ʒ| þþƷAVվ| ҹѸ| 3pˬִƵ| ޾Ʒ߲| һëƬһëƬaa| òƵѹۿ| kkk4444߹ۿ| պ߹ۿ| ߹ۿHַ| ţţ߾ƷƵۿ| ޹ۺϾƷĵһ| ³˿Ƭһ߹ۿ| ĻĴȫ|