﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-風向逆轉 - 就要爪哇-文章分类-DataBase</title><link>http://www.blogjava.net/iKingQu/category/8111.html</link><description>Java菜鸟升级中...</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 10:22:51 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 10:22:51 GMT</pubDate><ttl>60</ttl><item><title>[收藏]数据库连接、设计以及备份技巧集锦</title><link>http://www.blogjava.net/iKingQu/articles/47124.html</link><dc:creator>風向逆轉 - 就要爪哇</dc:creator><author>風向逆轉 - 就要爪哇</author><pubDate>Fri, 19 May 2006 14:46:00 GMT</pubDate><guid>http://www.blogjava.net/iKingQu/articles/47124.html</guid><wfw:comment>http://www.blogjava.net/iKingQu/comments/47124.html</wfw:comment><comments>http://www.blogjava.net/iKingQu/articles/47124.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/iKingQu/comments/commentRss/47124.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iKingQu/services/trackbacks/47124.html</trackback:ping><description><![CDATA[原文地址：<a href="http://java.ccidnet.com/art/297/20060326/489157_1.html">http://java.ccidnet.com/art/297/20060326/489157_1.html</a><img src ="http://www.blogjava.net/iKingQu/aggbug/47124.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iKingQu/" target="_blank">風向逆轉 - 就要爪哇</a> 2006-05-19 22:46 <a href="http://www.blogjava.net/iKingQu/articles/47124.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[收藏]MySQL数据库优化</title><link>http://www.blogjava.net/iKingQu/articles/38162.html</link><dc:creator>風向逆轉 - 就要爪哇</dc:creator><author>風向逆轉 - 就要爪哇</author><pubDate>Wed, 29 Mar 2006 20:01:00 GMT</pubDate><guid>http://www.blogjava.net/iKingQu/articles/38162.html</guid><wfw:comment>http://www.blogjava.net/iKingQu/comments/38162.html</wfw:comment><comments>http://www.blogjava.net/iKingQu/articles/38162.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/iKingQu/comments/commentRss/38162.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iKingQu/services/trackbacks/38162.html</trackback:ping><description><![CDATA[下决心开始学oracle了,用mysql已经有不短的时间了,今天写下这些算是对自己的一个mysql之旅的一个交代吧.以下仅仅是本人在使用mysql过程中的一点个人的体会,也许存在许多纰漏和错误,还请指正!! <br /><br /><br /><br />首先,为了使一个系统更快,最重要的部分就是基础设计,不过有些东西是现有情况下无法逾越的,比如说系统常见的瓶颈. <br /><br />我所能想到的: <br /><br />1:磁盘寻道能力,以高速硬盘(7200转/秒),理论上每秒寻道7200次.这是没有办法改变的,优化的方法是----用多个硬盘,或者把数据分散存储. <br /><br />2:硬盘的读写速度,这个速度非常的快(限于本人的知识所限,只知道在每秒几十甚至上百MB).这个更容易解决--可以从多个硬盘上并行读写. <br /><br />3:cpu.cpu处理内存中的数据,当有相对内存较小的表时,这是最常见的限制因素. <br /><br />4:内存的限制.当cpu需要超出适合cpu缓存的数据时,缓存的带宽就成了内存的一个瓶颈---不过现在内存大的惊人,一般不会出现这个问题. <br /><br />第二步: <br /><br />(本人使用的是学校网站的linux平台(Linux ADVX.Mandrakesoft.com 2.4.3-19mdk )) <br /><br />1:调节服务器参数 <br /><br />用shell&gt;mysqld-help这个命令声厂一张所有mysql选项和可配置变量的表.输出以下信息: <br /><br />possible variables for option--set-variable(-o) are: <br /><br />back_log current value:5 //要求mysql能有的连接数量.back_log指出在mysql暂停接受连接的时间内有多少个连接请求可以被存在堆栈中 <br /><br />connect_timeout current value:5 //mysql服务器在用bad handshake(不好翻译)应答前等待一个连接的时间 <br /><br />delayed_insert_timeout current value:200 //一个insert delayed在终止前等待insert的时间 <br /><br />delayed_insert_limit current value:50 //insert delayed处理器将检查是否有任何select语句未执行,如果有,继续前执行这些语句 <br /><br />delayed_queue_size current value:1000 //为insert delayed分配多大的队 <br /><br />flush_time current value:0 //如果被设置为非0,那么每个flush_time 时间,所有表都被关闭 <br /><br />interactive_timeout current value:28800 //服务器在关上它之前在洋交互连接上等待的时间 <br /><br />join_buffer_size current value:131072 //用与全部连接的缓冲区大小 <br /><br />key_buffer_size current value:1048540 //用语索引块的缓冲区的大小,增加它可以更好的处理索引 <br /><br />lower_case_table_names current value:0 // <br /><br />long_query_time current value:10 //如果一个查询所用时间大于此时间,slow_queried计数将增加 <br /><br />max_allowed_packet current value:1048576 //一个包的大小 <br /><br />max_connections current value:300 //允许同时连接的数量 <br /><br />max_connect_errors current value:10 //如果有多于该数量的中断连接,将阻止进一步的连接,可以用flush hosts来解决 <br /><br />max_delayed_threads current value:15 //可以启动的处理insert delayed的数量 <br /><br />max_heap_table_size current value:16777216 // <br /><br />max_join_size current value:4294967295 //允许读取的连接的数量 <br /><br />max_sort_length current value:1024 //在排序blob或者text时使用的字节数量 <br /><br />max_tmp_tables current value:32 //一个连接同时打开的临时表的数量 <br /><br />max_write_lock_count current value:4294967295 //指定一个值(通常很小)来启动mysqld,使得在一定数量的write锁定之后出现read锁定 <br /><br />net_buffer_length current value:16384 //通信缓冲区的大小--在查询时被重置为该大小 <br /><br />query_buffer_size current value:0 //查询时缓冲区大小 <br /><br />record_buffer current value:131072 //每个顺序扫描的连接为其扫描的每张表分配的缓冲区的大小 <br /><br />sort_buffer current value:2097116 //每个进行排序的连接分配的缓冲区的大小 <br /><br />table_cache current value:64 //为所有连接打开的表的数量 <br /><br />thread_concurrency current value:10 // <br /><br />tmp_table_size current value:1048576 //临时表的大小 <br /><br />thread_stack current value:131072 //每个线程的大小 <br /><br />wait_timeout current value:28800 //服务器在关闭它3之前的一个连接上等待的时间 <br /><br /><br /><br />根据自己的需要配置以上信息会对你帮助. <br /><br /><br /><br />第三: <br /><br />1:如果你在一个数据库中创建大量的表,那么执行打开,关闭，创建(表)的操作就会很慢. <br /><br />2:mysql使用内存 <br /><br />a: 关键字缓存区(key_buffer_size)由所有线程共享 <br /><br />b: 每个连接使用一些特定的线程空间.一个栈(默认为64k,变量thread_stack),一个连接缓冲区(变量net_buffer_length)和一个结果缓冲区(net_buffer_length).特定情况下,连接缓冲区和结果缓冲区被动态扩大到max_allowed_packet. <br /><br />c:所有线程共享一个基存储器 <br /><br />d:没有内存影射 <br /><br />e:每个做顺序扫描的请求分配一个读缓冲区(record_buffer) <br /><br />f:所有联结均有一遍完成并且大多数联结甚至可以不用一个临时表完成.最临时的表是基于内存的(heap)表 <br /><br />g:排序请求分配一个排序缓冲区和2个临时表 <br /><br />h:所有语法分析和计算都在一个本地存储器完成 <br /><br />i:每个索引文件只被打开一次,并且数据文件为每个并发运行的线程打开一次 <br /><br />j:对每个blob列的表，一个缓冲区动态的被扩大以便读入blob值 <br /><br />k:所有正在使用的表的表处理器被保存在一个缓冲器中并且作为一个fifo管理. <br /><br />l:一个mysqladmin flush-tables命令关闭所有不在使用的表并且在当前执行的线程结束时标记所有在使用的表准备关闭 <br /><br />3:mysql锁定表 <br /><br />mysql中所有锁定不会成为死锁. <br /><br />wirte锁定: <br /><br />mysql的锁定原理:a:如果表没有锁定,那么锁定;b否则,把锁定请求放入写锁定队列中 <br /><br />read锁定: <br /><br />mysql的锁定原理:a:如果表没有锁定,那么锁定;b否则,把锁定请求放入读锁定队列中 <br /><br /><br /><br />有时候会在一个表中进行很多的select,insert操作,可以在一个临时表中插入行并且偶尔用临时表的记录更新真正的表 <br /><br />a:用low_priority属性给一个特定的insert,update或者delete较低的优先级 <br /><br />b:max_write_lock_count指定一个值(通常很小)来启动mysqld,使得在一定数量的write锁定之后出现read锁定 <br /><br />c:通过使用set sql_low_priority_updates=1可以从一个特定的线程指定所有的更改应该由较低的优先级完成 <br /><br />d:用high_priority指定一个select <br /><br />e:如果使用insert....select....出现问题,使用myisam表------因为它支持因为它支持并发的select和insert <br /><br />4:最基本的优化是使数据在硬盘上占据的空间最小.如果索引做在最小的列上,那么索引也最小.实现方法: <br /><br />a:使用尽可能小的数据类型 <br /><br />b:如果可能，声明表列为NOT NULL. <br /><br />c:如果有可能使用变成的数据类型,如varchar(但是速度会受一定的影响) <br /><br />d:每个表应该有尽可能短的主索引 <br /><br />e:创建确实需要的索引 <br /><br />f:如果一个索引在头几个字符上有唯一的前缀,那么仅仅索引这个前缀----mysql支持在一个字符列的一部分上的索引 <br /><br />g:如果一个表经常被扫描,那么试图拆分它为更多的表 <br /><br /><br /><br /><br /><br />第四步 <br /><br />1:索引的使用,索引的重要性就不说了,功能也不说了,只说怎么做. <br /><br />首先要明确所有的mysql索引(primary,unique,index)在b树中有存储.索引主要用语: <br /><br />a:快速找到where指定条件的记录 <br /><br />b:执行联结时,从其他表检索行 <br /><br />c:对特定的索引列找出max()和min()值 <br /><br />d：如果排序或者分组在一个可用键的最前面加前缀，排序或分组一个表 <br /><br />e：一个查询可能被用来优化检索值，而不用访问数据文件．如果某些表的列是数字型并且正好是某个列的前缀，为了更快，值可以从索引树中取出 <br /><br />２：存储或者更新数据的查询速度 <br /><br />　grant的执行会稍稍的减低效率． <br /><br />　mysql的函数应该被高度的优化．可以用benchmark（loop_count,expression)来找出是否查询有问题 <br /><br />　select 的查询速度：如果想要让一个select．．．where．．．更快，我能想到的只有建立索引．可以在一个表上运行myisamchk－－analyze 来更好的优化查询．可以用myisamchk－－sort－index－－sort－records＝１来设置用一个索引排序一个索引和数据． <br /><br />３：mysql优化where子句 <br /><br />3.１：删除不必要的括号： <br /><br />　（（a AND b) AND c OR (((a AND b) AND (a AND d))))&gt;(a AND b AND c) OR (a AND b AND c AND d) <br /><br />3.2:使用常数 <br /><br />　（a&lt;b AND b=c) AND a=100 &gt; b&gt;5 AND b=c AND a=5 <br /><br />3.3:删除常数条件 <br /><br />（b&gt;=5 AND b=5) OR (b=6 AND 5=5) OR (b=100 AND 2=3) &gt; b=5 OR b=6 <br /><br />3.4:索引使用的常数表达式仅计算一次 <br /><br />3.5：在一个表中，没有一个where的count(*)直接从表中检索信息 <br /><br />3.6:所有常数的表在查询中在任何其他表之前读出 <br /><br />3.7:对外联结表最好联结组合是尝试了所有可能性找到的 <br /><br />3.8：如果有一个order　by字句和一个不同的group　by子句或者order　by或者group　by包含不是来自联结的第一个表的列，那么创建一个临时表 <br /><br />3.9:如果使用了sql_small_result，那么msyql使用在内存中的一个表 <br /><br />3.10:每个表的索引给查询并且使用跨越少于３０％的行的索引． <br /><br />3.11在每个记录输出前，跳过不匹配having子句的行 <br /><br /><br /><br />４：优化left　join <br /><br />在mysql中　a left join b按以下方式实现 <br /><br />a：表b依赖于表a　 <br /><br />b：表a依赖于所有用在left　join条件的表（除了b） <br /><br />c：所有left　join条件被移到where子句中 <br /><br />d：进行所有的联结优化，除了一个表总是在所有他依赖的表后读取．如果有一个循环依赖，那么将发生错误 <br /><br />e：进行所有的标准的where优化 <br /><br />f：如果在a中有一行匹配where子句，但是在b中没有任何匹配left　join条件，那么，在b中生成的所有设置为ＮＵＬＬ的一行 <br /><br />g：如果使用left　join来找出某些表中不存在的行并且在where部分有column_name IS NULL测试(column_name为NOT NULL列)．那么，mysql在它已经找到了匹配left　join条件的一行后，将停止在更多的行后寻找 <br /><br />５：优化limit <br /><br />a：如果用limit只选择一行，当mysql需要扫描整个表时，它的作用相当于索引 <br /><br />b：如果使用limit＃与order　by，mysql如果找到了第＃行，将结束排序，而不会排序正个表 <br /><br />c：当结合limit＃和distinct时，mysql如果找到了第＃行，将停止 <br /><br />d：只要mysql已经发送了第一个＃行到客户，mysql将放弃查询 <br /><br />e：limit 0一直会很快的返回一个空集合． <br /><br />f：临时表的大小使用limit＃计算需要多少空间来解决查询 <br /><br />６：优化insert <br /><br />插入一条记录的是由以下构成： <br /><br />a:连接（３） <br /><br />b:发送查询给服务器（２） <br /><br />c:分析查询（２） <br /><br />d:插入记录（１*记录大小） <br /><br />e：插入索引（１*索引） <br /><br />f：关闭（１） <br /><br />以上数字可以看成和总时间成比例 <br /><br />改善插入速度的一些方法： <br /><br />6.1：如果同时从一个连接插入许多行，使用多个值的insert，这比用多个语句要快 <br /><br />6.2：如果从不同连接插入很多行，使用insert　delayed语句速度更快 <br /><br />6.3: 用myisam，如果在表中没有删除的行，能在select：s正在运行的同时插入行 <br /><br />6.4: 当从一个文本文件装载一个表时，用load　data　infile．这个通常比insert快20 <br /><br />倍 <br /><br />6.5: 可以锁定表然后插入－－主要的速度差别是在所有insert语句完成后，索引缓冲区仅被存入到硬盘一次．一般与有不同的insert语句那样多次存入要快．如果能用一个单个语句插入所有的行，锁定就不需要．锁定也降低连接的整体时间．但是对某些线程最大等待时间将上升．例如： <br /><br />thread 1 does 1000 inserts <br /><br />thread 2,3 and 4 does 1 insert <br /><br />thread 5 does 1000 inserts <br /><br />如果不使用锁定，２，３，４将在１和５之前完成．如果使用锁定，２，３，４，将可能在１和５之后完成．但是整体时间应该快４０％．因为insert， update，delete操作在mysql中是很快的，通过为多于大约５次连续不断的插入或更新一行的东西加锁，将获得更好的整体性能．如果做很多一行的插入，可以做一个lock　tables，偶尔随后做一个unlock　tables（大约每１０００行）以允许另外的线程存取表．这仍然将导致获得好的性能．load　data　infile对装载数据仍然是很快的． <br /><br />为了对load　data　infile和insert得到一些更快的速度，扩大关键字缓冲区． <br /><br />７优化update的速度 <br /><br />它的速度依赖于被更新数据的大小和被更新索引的数量 <br /><br />使update更快的另一个方法是推迟修改，然后一行一行的做很多修改．如果锁定表，做一行一行的很多修改比一次做一个快 <br /><br />８优化delete速度 <br /><br />删除一个记录的时间与索引数量成正比．为了更快的删除记录，可以增加索引缓存的大小 <br /><br />从一个表删除所有行比删除这个表的大部分要快的多 <br /><br /><br /><br />第五步 <br /><br />１：选择一种表类型 <br /><br />1.1静态myisam <br /><br />这种格式是最简单且最安全的格式，它是磁盘格式中最快的．速度来自于数据能在磁盘上被找到的难易程度．当锁定有一个索引和静态格式的东西是，它很简单，只是行长度乘以数量．而且在扫描一张表时，每次用磁盘读取来读入常数个记录是很容易的．安全性来源于如果当写入一个静态myisam文件时导致计算机down 掉，myisamchk很容易指出每行在哪里开始和结束，因此，它通常能收回所有记录，除了部分被写入的记录．在mysql中所有索引总能被重建 <br /><br />1.2动态myisam <br /><br />这种格式每一行必须有一个头说明它有多长．当一个记录在更改期间变长时，它可以在多于一个位置上结束．能使用optimize　tablename或 myisamchk整理一张表．如果在同一个表中有像某些varchar或者blob列那样存取／改变的静态数据，将动态列移入另外一个表以避免碎片． <br /><br />1.2.1压缩myisam，用可选的myisampack工具生成 <br /><br />1.2.2内存 <br /><br />这种格式对小型／中型表很有用．对拷贝／创建一个常用的查找表到洋heap表有可能加快多个表联结，用同样数据可能要快好几倍时间． <br /><br />select tablename.a,tablename2.a from tablename,tablanem2,tablename3 where <br /><br />tablaneme.a=tablename2.a and tablename2.a=tablename3.a and tablename2.c!=0; <br /><br /><br /><br />为了加速它，可以用tablename2和tablename3的联结创建一个临时表，因为用相同列（tablename1.a）查找． <br /><br />CREATE  TEMPORARY  TABLE  test TYPE=HEAP <br /><br />SELECT <br /><br />tablename2.a as a2,tablename3.a as a3 <br /><br />FROM <br /><br />tablenam2,tablename3 <br /><br />WHERE <br /><br />tablename2.a=tablename3.a and c=0; <br /><br />SELECT tablename.a,test.a3 from tablename,test where tablename.a=test.a1; <br /><br />SELECT tablename.a,test,a3,from tablename,test where tablename.a=test.a1 and ....; <br /><br /><br /><br />1.3静态表的特点 <br /><br />1.3.1默认格式．用在表不包含varchar，blob，text列的时候 <br /><br />1.3.2所有的char，numeric和decimal列填充到列宽度 <br /><br />1.3.3非常快 <br /><br />1.3.4容易缓冲 <br /><br />1.3.5容易在down后重建，因为记录位于固定的位置 <br /><br />1.3.6不必被重新组织（用myisamchk），除非是一个巨量的记录被删除并且优化存储大小 <br /><br />1.3.7通常比动态表需要更多的存储空间 <br /><br /><br /><br />1.4动态表的特点 <br /><br />1.4.1如果表包含任何varchar，blob，text列，使用该格式 <br /><br />1.4.2所有字符串列是动态的 <br /><br />1.4.3每个记录前置一个位． <br /><br />1.4.4通常比定长表需要更多的磁盘空间 <br /><br />1.4.5每个记录仅仅使用所需要的空间，如果一个记录变的很大，它按需要被分成很多段，这导致了记录碎片 <br /><br />1.4.6如果用超过行长度的信息更新行，行被分段． <br /><br />1.4.7在系统down掉以后不好重建表，因为一个记录可以是多段 <br /><br />1.4.8对动态尺寸记录的期望行长度是３＋（number　of　columns＋７）／８＋(number <br /><br />of char columns)+packed size of numeric columns+length of strings +(number of <br /><br />NULL columns+7)/8 <br /><br />对每个连接有６个字节的惩罚．无论何时更改引起记录的变大，都有一个动态记录被连接．每个新连接至少有２０个字节，因此下一个变大将可能在同一个连接中．如果不是，将有另外一个连接．可以用myisamchk　－恶毒检查有多少连接．所有连接可以用myisamchk -r删除． <br /><br /><br /><br />1.5压缩表的特点 <br /><br />1.5.1一张用myisampack实用程序制作的只读表． <br /><br />1.5.2解压缩代码存在于所有mysql分发中，以便使没有myisampack的连接也能读取用myisampack压缩的表 <br /><br />1.5.3占据很小的磁盘空间 <br /><br />1.5.4每个记录被单独压缩．一个记录的头是一个定长的（１～～３个字节）这取决于表的最大记录．每列以不同的方式被压缩．一些常用的压缩类型是： <br /><br />　a:通常对每列有一张不同的哈夫曼表 <br /><br />　b:后缀空白压缩 <br /><br />　c:前缀空白压缩 <br /><br />d:用值０的数字使用１位存储 <br /><br />e:如果整数列的值有一个小范围，列使用最小的可能类型来存储．例如：如果所有的值在０到２５５之间，一个bigint可以作为一个tinyint存储 <br /><br />　g:如果列仅有可能值的一个小集合，列类型被转换到enum <br /><br />　h:列可以使用上面的压缩方法的组合 <br /><br />1.5.5能处理定长或动态长度的记录，去不能处理blob或者text列 <br /><br />1.5.6能用myisamchk解压缩 <br /><br />mysql能支持不同的索引类型，但一般的类型是isam，这是一个Ｂ树索引并且能粗略的为索引文件计算大小为(key_length+4)*0.67，在所有的键上的总和． <br /><br />字符串索引是空白压缩的。如果第一个索引是一个字符串，它可将压缩前缀如果字符串列有很多尾部空白或是一个总部能甬道全长的varchar列，空白压缩使索引文件更小．如果很多字符串有相同的前缀． <br /><br />1.6内存表的特点 <br /><br />mysql内部的heap表使用每偶溢出去的１００％动态哈希并且没有与删除有关的问题．只能通过使用在堆表中的一个索引来用等式存取东西（通常用＇＝＇操作符） <br /><br />堆表的缺点是： <br /><br />1.6.1想要同时使用的所有堆表需要足够的额外内存 <br /><br />1.6.2不能在索引的一个部分搜索 <br /><br />1.6.3不能按顺序搜索下一个条目（即，使用这个索引做一个order　by） <br /><br />1.6.4mysql不能算出在２个值之间大概有多少行．这被优化器使用是用来决定使用哪个索引的，但是在另一个方面甚至不需要磁盘寻道<img src ="http://www.blogjava.net/iKingQu/aggbug/38162.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iKingQu/" target="_blank">風向逆轉 - 就要爪哇</a> 2006-03-30 04:01 <a href="http://www.blogjava.net/iKingQu/articles/38162.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[收藏]JDBC系列教程（六）---可调用语句</title><link>http://www.blogjava.net/iKingQu/articles/36764.html</link><dc:creator>風向逆轉 - 就要爪哇</dc:creator><author>風向逆轉 - 就要爪哇</author><pubDate>Tue, 21 Mar 2006 19:44:00 GMT</pubDate><guid>http://www.blogjava.net/iKingQu/articles/36764.html</guid><wfw:comment>http://www.blogjava.net/iKingQu/comments/36764.html</wfw:comment><comments>http://www.blogjava.net/iKingQu/articles/36764.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/iKingQu/comments/commentRss/36764.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iKingQu/services/trackbacks/36764.html</trackback:ping><description><![CDATA[
		<p>
				<span class="Title">JDBC系列教程（六）---可调用语句 </span>
		</p>
		<p>CallableStatement </p>
		<p>本概述是从《JDBCTM Database Access from JavaTM: A Tutorial and Annotated Reference 》这本书中摘引来的。JavaSoft 目前正在准备这本书。这本书是一本教程，同时也是 JDBC 的重要参考手册，它将作为 Java 系列的组成部份在 1997 年春季由 Addison-Wesley 出版公司出版。  </p>
		<p>
				<br />7.1 概述 <br />CallableStatement 对象为所有的 DBMS 提供了一种以标准形式调用已储存过程的方法。已储存过程储存在数据库中。对已储存过程的调用是 CallableStatement 对象所含的内容。这种调用是用一种换码语法来写的，有两种形式：一种形式带结果参数，另一种形式不带结果参数（有关换码语法的信息，参见第 4 节“语句”）。结果参数是一种输出 (OUT) 参数，是已储存过程的返回值。两种形式都可带有数量可变的输入（IN 参数）、输出（OUT 参数）或输入和输出（INOUT 参数）的参数。问号将用作参数的占位符。 </p>
		<p>在 JDBC 中调用已储存过程的语法如下所示。注意，方括号表示其间的内容是可选项；方括号本身并不是语法的组成部份。 </p>
		<p>{call 过程名[(?, ?, ...)]} </p>
		<p>返回结果参数的过程的语法为：  </p>
		<p>{? = call 过程名[(?, ?, ...)]} </p>
		<p>不带参数的已储存过程的语法类似：  </p>
		<p>{call 过程名} </p>
		<p>通常，创建 CallableStatement 对象的人应当知道所用的 DBMS 是支持已储存过程的，并且知道这些过程都是些什么。然而，如果需要检查，多种 DatabaseMetaData 方法都可以提供这样的信息。例如，如果 DBMS 支持已储存过程的调用，则 supportsStoredProcedures 方法将返回 true，而 getProcedures 方法将返回对已储存过程的描述。 </p>
		<p>CallableStatement 继承 Statement 的方法（它们用于处理一般的 SQL 语句），还继承了 PreparedStatement 的方法（它们用于处理 IN 参数）。CallableStatement 中定义的所有方法都用于处理 OUT 参数或 INOUT 参数的输出部分：注册 OUT 参数的 JDBC 类型（一般 SQL 类型）、从这些参数中检索结果，或者检查所返回的值是否为 JDBC NULL。 </p>
		<p>
				<br />7.1.1 创建 CallableStatement 对象 <br />CallableStatement 对象是用 Connection 方法 prepareCall 创建的。下例创建 CallableStatement 的实例，其中含有对已储存过程 getTestData 调用。该过程有两个变量，但不含结果参数：  </p>
		<p>CallableStatement cstmt = con.prepareCall( <br />"{call getTestData(?, ?)}"); </p>
		<p>其中 ? 占位符为 IN、 OUT 还是 INOUT 参数，取决于已储存过程 getTestData。 </p>
		<p>
				<br />7.1.2 IN 和 OUT 参数 <br />将 IN 参数传给 CallableStatement 对象是通过 setXXX 方法完成的。该方法继承自 PreparedStatement。所传入参数的类型决定了所用的 setXXX 方法（例如，用 setFloat 来传入 float 值等）。 </p>
		<p>如果已储存过程返回 OUT 参数，则在执行 CallableStatement 对象以前必须先注册每个 OUT 参数的 JDBC 类型（这是必需的，因为某些 DBMS 要求 JDBC 类型）。注册 JDBC 类型是用 registerOutParameter 方法来完成的。语句执行完后，CallableStatement 的 getXXX 方法将取回参数值。正确的 getXXX 方法是为各参数所注册的 JDBC 类型所对应的 Java 类型（从 JDBC 类型到 Java 类型的标准映射见 8.6.1 节中的表）。换言之， registerOutParameter 使用的是 JDBC 类型（因此它与数据库返回的 JDBC 类型匹配），而 getXXX 将之转换为 Java 类型。 </p>
		<p>作为示例，下述代码先注册 OUT 参数，执行由 cstmt 所调用的已储存过程，然后检索在 OUT 参数中返回的值。方法 getByte 从第一个 OUT 参数中取出一个 Java 字节，而 getBigDecimal 从第二个 OUT 参数中取出一个 BigDecimal 对象（小数点后面带三位数）：  </p>
		<p>CallableStatement cstmt = con.prepareCall( <br />"{call getTestData(?, ?)}"); <br />cstmt.registerOutParameter(1, java.sql.Types.TINYINT); <br />cstmt.registerOutParameter(2, java.sql.Types.DECIMAL, 3); <br />cstmt.executeQuery(); <br />byte x = cstmt.getByte(1); <br />java.math.BigDecimal n = cstmt.getBigDecimal(2, 3); </p>
		<p>CallableStatement 与 ResultSet 不同，它不提供用增量方式检索大 OUT 值的特殊机制。 </p>
		<p>
				<br />7.1.3 INOUT 参数 <br />既支持输入又接受输出的参数（INOUT 参数）除了调用 registerOutParameter 方法外，还要求调用适当的 setXXX 方法（该方法是从 PreparedStatement 继承来的）。setXXX 方法将参数值设置为输入参数，而 registerOutParameter 方法将它的 JDBC 类型注册为输出参数。setXXX 方法提供一个 Java 值，而驱动程序先把这个值转换为 JDBC 值，然后将它送到数据库中。 </p>
		<p>这种 IN 值的 JDBC 类型和提供给 registerOutParameter 方法的 JDBC 类型应该相同。然后，要检索输出值，就要用对应的 getXXX 方法。例如，Java 类型为 byte 的参数应该使用方法 setByte 来赋输入值。应该给 registerOutParameter 提供类型为 TINYINT 的 JDBC 类型，同时应使用 getByte 来检索输出值 （第 8 节“JDBC 和 Java 类型之间的映射”将给出详细信息和类型映射表）。 </p>
		<p>下例假设有一个已储存过程 reviseTotal，其唯一参数是 INOUT 参数。方法 setByte 把此参数设为 25，驱动程序将把它作为 JDBC TINYINT 类型送到数据库中。接着，registerOutParameter 将该参数注册为 JDBC TINYINT。执行完该已储存过程后，将返回一个新的 JDBC TINYINT 值。方法 getByte 将把这个新值作为 Java byte 类型检索。 </p>
		<p>CallableStatement cstmt = con.prepareCall( <br />"{call reviseTotal(?)}"); <br />cstmt.setByte(1, 25); <br />cstmt.registerOutParameter(1, java.sql.Types.TINYINT); <br />cstmt.executeUpdate(); <br />byte x = cstmt.getByte(1); </p>
		<p>7.1.4 先检索结果，再检索 OUT 参数 <br />由于某些 DBMS 的限制，为了实现最大的可移植性，建议先检索由执行 CallableStatement 对象所产生的结果，然后再用 CallableStatement.getXXX 方法来检索 OUT 参数。 </p>
		<p>如果 CallableStatement 对象返回多个 ResultSet 对象（通过调用 execute 方法），在检索 OUT 参数前应先检索所有的结果。这种情况下，为确保对所有的结果都进行了访问，必须对 Statement 方法 getResultSet、getUpdateCount 和 getMoreResults 进行调用，直到不再有结果为止。 </p>
		<p>检索完所有的结果后，就可用 CallableStatement.getXXX 方法来检索 OUT 参数中的值。 </p>
		<p>
				<br />7.1.5 检索作为 OUT 参数的 NULL 值 <br />返回到 OUT 参数中的值可能会是 JDBC NULL。当出现这种情形时，将对 JDBC NULL 值进行转换以使 getXXX 方法所返回的值为 null、0 或 false，这取决于 getXXX 方法类型。对于 ResultSet 对象，要知道 0 或 false 是否源于 JDBC NULL 的唯一方法，是用方法 wasNull 进行检测。如果 getXXX 方法读取的最后一个值是 JDBC NULL，则该方法返回 true，否则返回 flase。第 5 节“ResultSet”将给出详细信息。   </p>
		<br />
		<br />
		<p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=630452</p>
<img src ="http://www.blogjava.net/iKingQu/aggbug/36764.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iKingQu/" target="_blank">風向逆轉 - 就要爪哇</a> 2006-03-22 03:44 <a href="http://www.blogjava.net/iKingQu/articles/36764.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[收藏]JDBC系列教程（五）---准备语句</title><link>http://www.blogjava.net/iKingQu/articles/36762.html</link><dc:creator>風向逆轉 - 就要爪哇</dc:creator><author>風向逆轉 - 就要爪哇</author><pubDate>Tue, 21 Mar 2006 19:32:00 GMT</pubDate><guid>http://www.blogjava.net/iKingQu/articles/36762.html</guid><wfw:comment>http://www.blogjava.net/iKingQu/comments/36762.html</wfw:comment><comments>http://www.blogjava.net/iKingQu/articles/36762.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/iKingQu/comments/commentRss/36762.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iKingQu/services/trackbacks/36762.html</trackback:ping><description><![CDATA[
		<div class="postText">
				<p>
						<span class="Title">JDBC系列教程（五）---准备语句</span>
				</p>
				<p>PreparedStatement </p>
				<p>本概述是从《JDBCTM Database Access from JavaTM: A Tutorial and Annotated Reference 》这本书中摘引来的。JavaSoft 目前正在准备这本书。这是一本教程，同时也是 JDBC 的重要参考手册，它将作为 Java 系列的组成部份在 1997 年春季由 Addison-Wesley 出版公司出版。  </p>
				<p>
						<br />6.1 概述 <br />该 PreparedStatement 接口继承 Statement，并与之在两方面有所不同：  </p>
				<p>
						<br />PreparedStatement 实例包含已编译的 SQL 语句。这就是使语句“准备好”。  <br />包含于 PreparedStatement 对象中的 SQL 语句可具有一个或多个 IN 参数。IN 参数的值在 SQL 语句创建时未被指定。相反的，该语句为每个 IN 参数保留一个问号（“？”）作为占位符。每个问号的值必须在该语句执行之前，通过适当的 setXXX 方法来提供。  </p>
				<p>由于 PreparedStatement 对象已预编译过，所以其执行速度要快于 Statement 对象。因此，多次执行的 SQL 语句经常创建为 PreparedStatement 对象，以提高效率。 </p>
				<p>作为 Statement 的子类，PreparedStatement 继承了 Statement 的所有功能。另外它还添加了一整套方法，用于设置发送给数据库以取代 IN 参数占位符的值。同时，三种方法 execute、 executeQuery 和 executeUpdate 已被更改以使之不再需要参数。这些方法的 Statement 形式（接受 SQL 语句参数的形式）不应该用于 PreparedStatement 对象。 </p>
				<p>
						<br />6.1.1 创建 PreparedStatement 对象 <br />以下的代码段（其中 con 是 Connection 对象）创建包含带两个 IN 参数占位符的 SQL 语句的 PreparedStatement 对象：  </p>
				<p>PreparedStatement pstmt = con.prepareStatement( <br />"UPDATE table4 SET m = ? WHERE x = ?"); </p>
				<p>pstmt 对象包含语句 "UPDATE table4 SET m = ? WHERE x = ?"，它已发送给 DBMS，并为执行作好了准备。 </p>
				<p>
						<br />6.1.2 传递 IN 参数 <br />在执行 PreparedStatement 对象之前，必须设置每个 ? 参数的值。这可通过调用 setXXX 方法来完成，其中 XXX 是与该参数相应的类型。例如，如果参数具有 Java 类型 long，则使用的方法就是 setLong。setXXX 方法的第一个参数是要设置的参数的序数位置，第二个参数是设置给该参数的值。例如，以下代码将第一个参数设为 123456789，第二个参数设为 100000000：  </p>
				<p>pstmt.setLong(1, 123456789); <br />pstmt.setLong(2, 100000000); </p>
				<p>一旦设置了给定语句的参数值，就可用它多次执行该语句，直到调用 clearParameters 方法清除它为止。 </p>
				<p>在连接的缺省模式下（启用自动提交），当语句完成时将自动提交或还原该语句。 </p>
				<p>如果基本数据库和驱动程序在语句提交之后仍保持这些语句的打开状态，则同一个 PreparedStatement 可执行多次。如果这一点不成立，那么试图通过使用 PreparedStatement 对象代替 Statement 对象来提高性能是没有意义的。 </p>
				<p>利用 pstmt（前面创建的 PreparedStatement 对象），以下代码例示了如何设置两个参数占位符的值并执行 pstmt 10 次。如上所述，为做到这一点，数据库不能关闭 pstmt。在该示例中，第一个参数被设置为 "Hi"并保持为常数。在 for 循环中，每次都将第二个参数设置为不同的值：从 0 开始，到 9 结束。 </p>
				<p>pstmt.setString(1, "Hi"); <br />for (int i = 0; i &lt; 10; i++) { <br />pstmt.setInt(2, i); <br />int rowCount = pstmt.executeUpdate(); <br />} </p>
				<p>6.1.3 IN 参数中数据类型的一致性 <br />setXXX 方法中的 XXX 是 Java 类型。它是一种隐含的 JDBC 类型（一般 SQL 类型），因为驱动程序将把 Java 类型映射为相应的 JDBC 类型（遵循该 JDBC Guide中§8.6.2 “映射 Java 和 JDBC 类型”表中所指定的映射），并将该 JDBC 类型发送给数据库。例如，以下代码段将 PreparedStatement 对象 pstmt 的第二个参数设置为 44，Java 类型为 short：  </p>
				<p>pstmt.setShort(2, 44); </p>
				<p>驱动程序将 44 作为 JDBC SMALLINT 发送给数据库，它是 Java short 类型的标准映射。 </p>
				<p>程序员的责任是确保将每个 IN 参数的 Java 类型映射为与数据库所需的 JDBC 数据类型兼容的 JDBC 类型。不妨考虑数据库需要 JDBC SMALLINT 的情况。如果使用方法 setByte ，则驱动程序将 JDBC TINYINT 发送给数据库。这是可行的，因为许多数据库可从一种相关的类型转换为另一种类型，并且通常 TINYINT 可用于 SMALLINT 适用的任何地方。然而，对于要适用于尽可能多的数据库的应用程序，最好使用与数据库所需的确切的 JDBC 类型相应的 Java 类型。如果所需的 JDBC 类型是 SMALLINT，则使用 setShort 代替 setByte 将使应用程序的可移植性更好。 </p>
				<p>
						<br />6.1.4 使用 setObject <br />程序员可使用 setObject 方法显式地将输入参数转换为特定的 JDBC 类型。该方法可以接受第三个参数，用来指定目标 JDBC 类型。将 Java Object 发送给数据库之前，驱动程序将把它转换为指定的 JDBC 类型。 </p>
				<p>如果没有指定 JDBC 类型，驱动程序就会将 Java Object 映射到其缺省的 JDBC 类型（参见第 8.6.4 节中的表格），然后将它发送到数据库。这与常规的 setXXX 方法类似；在这两种情况下，驱动程序在将值发送到数据库之前，会将该值的 Java 类型映射为适当的 JDBC 类型。二者的差别在于 setXXX 方法使用从 Java 类型到 JDBC 类型的标准映射（参见第 8.6.2 节中的表格），而 setObject 方法使用从 Java Object 类型到 JDBC 类型的映射（参见第 8.6.4 节中的表格）。 </p>
				<p>方法 setObject 允许接受所有 Java 对象的能力使应用程序更为通用，并可在运行时接受参数的输入。这种情况下，应用程序在编译时并不清楚输入类型。通过使用 setObject，应用程序可接受所有 Java 对象类型作为输入，并将其转换为数据库所需的 JDBC 类型。第 8.6.5 节中的表格显示了 setObject 可执行的所有可能转换。 </p>
				<p>
						<br />6.1.5 将 JDBC NULL 作为 IN 参数发送 <br />setNull 方法允许程序员将 JDBC NULL 值作为 IN 参数发送给数据库。但要注意，仍然必须指定参数的 JDBC 类型。 </p>
				<p>当把 Java null 值传递给 setXXX 方法时（如果它接受 Java 对象作为参数），也将同样把 JDBC NULL 发送到数据库。但仅当指定 JDBC 类型时，方法 setObject 才能接受 null 值。 </p>
				<p>
						<br />6.1.6 发送大的 IN 参数 <br />setBytes 和 setString 方法能够发送无限量的数据。但是，有时程序员更喜欢用较小的块传递大型的数据。这可通过将 IN 参数设置为 Java 输入流来完成。当语句执行时，JDBC 驱动程序将重复调用该输入流，读取其内容并将它们当作实际参数数据传输。 </p>
				<p>JDBC 提供了三种将 IN 参数设置为输入流的方法：setBinaryStream 用于含有未说明字节的流， setAsciiStream 用于含有 ASCII 字符的流，而 setUnicodeStream 用于含有 Unicode 字符的流。因为必须指定流的总长度，所以这些方法所采用的参数比其它的 setXXX 方法要多一个。这很有必要，因为一些数据库在发送数据之前需要知道其总的传送大小。 </p>
				<p>以下代码例示了使用流作为 IN 参数来发送文件内容：  </p>
				<p>java.io.File file = new java.io.File("/tmp/data"); <br />int fileLength = file.length(); <br />java.io.InputStream fin = new java.io.FileInputStream(file); <br />java.sql.PreparedStatement pstmt = con.prepareStatement( <br />"UPDATE Table5 SET stuff = ? WHERE index = 4"); <br />pstmt.setBinaryStream (1, fin, fileLength); <br />pstmt.executeUpdate(); </p>
				<p>当语句执行时，将反复调用输入流 fin 以传递其数据。 </p>
				<br />
				<br />
				<p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=630450</p>
		</div>
<img src ="http://www.blogjava.net/iKingQu/aggbug/36762.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iKingQu/" target="_blank">風向逆轉 - 就要爪哇</a> 2006-03-22 03:32 <a href="http://www.blogjava.net/iKingQu/articles/36762.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[收藏]JDBC系列教程（四）---结果设置</title><link>http://www.blogjava.net/iKingQu/articles/36761.html</link><dc:creator>風向逆轉 - 就要爪哇</dc:creator><author>風向逆轉 - 就要爪哇</author><pubDate>Tue, 21 Mar 2006 19:31:00 GMT</pubDate><guid>http://www.blogjava.net/iKingQu/articles/36761.html</guid><wfw:comment>http://www.blogjava.net/iKingQu/comments/36761.html</wfw:comment><comments>http://www.blogjava.net/iKingQu/articles/36761.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/iKingQu/comments/commentRss/36761.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iKingQu/services/trackbacks/36761.html</trackback:ping><description><![CDATA[
		<div class="postText">
				<p>
						<span class="Title">JDBC系列教程（四）---结果设置 </span>
				</p>
				<p>ResultSet <br />本概述是从《JDBCTM Database Access from JavaTM: A Tutorial and Annotated Reference 》这本书中摘引来的。JavaSoft 目前正在准备这本书。这是一本教程，同时也是 JDBC 的重要参考手册，它将作为 Java 系列的组成部份在 1997 年春季由 Addison-Wesley 出版公司出版。  </p>
				<p>5.1 概述 <br />ResultSet 包含符合 SQL 语句中条件的所有行，并且它通过一套 get 方法（这些 get 方法可以访问当前行中的不同列）提供了对这些行中数据的访问。ResultSet.next 方法用于移动到 ResultSet 中的下一行，使下一行成为当前行。 </p>
				<p>结果集一般是一个表，其中有查询所返回的列标题及相应的值。例如，如果查询为 SELECT a, b, c FROM Table1，则结果集将具有如下形式：  </p>
				<p>
						<br />a b c <br />-------- --------- -------- <br />12345 Cupertino CA <br />83472 Redmond WA <br />83492 Boston MA </p>
				<p>
						<br />下面的代码段是执行 SQL 语句的示例。该 SQL 语句将返回行集合，其中列 1 为 int，列 2 为 String，而列 3 则为字节数组：  </p>
				<p>
						<br />java.sql.Statement stmt = conn.createStatement(); <br />ResultSet r = stmt.executeQuery("SELECT a, b, c FROM Table1"); <br />while (r.next()) <br />{ <br />// 打印当前行的值。 <br />int i = r.getInt("a"); <br />String s = r.getString("b"); <br />float f = r.getFloat("c"); <br />System.out.println("ROW = " + i + " " + s + " " + f); <br />} </p>
				<p>5.1.1 行和光标 <br />ResultSet 维护指向其当前数据行的光标。每调用一次 next 方法，光标向下移动一行。最初它位于第一行之前，因此第一次调用 next 将把光标置于第一行上，使它成为当前行。随着每次调用 next 导致光标向下移动一行，按照从上至下的次序获取 ResultSet 行。 </p>
				<p>在 ResultSet 对象或其父辈 Statement 对象关闭之前，光标一直保持有效。 </p>
				<p>在 SQL 中，结果表的光标是有名字的。如果数据库允许定位更新或定位删除，则需要将光标的名字作为参数提供给更新或删除命令。可通过调用方法 getCursorName 获得光标名。 </p>
				<p>注意：不是所有的 DBMS 都支持定位更新和删除。可使用 DatabaseMetaData.supportsPositionedDelete 和 supportsPositionedUpdate 方法来检查特定连接是否支持这些操作。当支持这些操作时，DBMS/驱动程序必须确保适当锁定选定行，以使定位更新不会导致更新异常或其它并发问题。 </p>
				<p>
						<br />5.1.2 列 <br />方法 getXXX 提供了获取当前行中某列值的途径。在每一行内，可按任何次序获取列值。但为了保证可移植性，应该从左至右获取列值，并且一次性地读取列值。 </p>
				<p>列名或列号可用于标识要从中获取数据的列。例如，如果 ResultSet 对象 rs 的第二列名为“title”，并将值存储为字符串，则下列任一代码将获取存储在该列中的值：  </p>
				<p>String s = rs.getString("title"); <br />String s = rs.getString(2); </p>
				<p>注意列是从左至右编号的，并且从列 1 开始。同时，用作 getXXX 方法的输入的列名不区分大小写。 </p>
				<p>提供使用列名这个选项的目的是为了让在查询中指定列名的用户可使用相同的名字作为 getXXX 方法的参数。另一方面，如果 select 语句未指定列名（例如在“select * from table1”中或列是导出的时），则应该使用列号。这些情况下，用户将无法确切知道列名。 </p>
				<p>有些情况下，SQL 查询返回的结果集中可能有多个列具有相同的名字。如果列名用作 getXXX 方法的参数，则 getXXX 将返回第一个匹配列名的值。因而，如果多个列具有相同的名字，则需要使用列索引来确保检索了正确的列值。这时，使用列号效率要稍微高一些。 </p>
				<p>关于 ResultSet 中列的信息，可通过调用方法 ResultSet.getMetaData 得到。返回的 ResultSetMetaData 对象将给出其 ResultSet 对象各列的编号、类型和属性。 </p>
				<p>如果列名已知，但不知其索引，则可用方法 findColumn 得到其列号。 </p>
				<p>
						<br />5.1.3 数据类型和转换 <br />对于 getXXX 方法，JDBC 驱动程序试图将基本数据转换成指定 Java 类型，然后返回适合的 Java 值。例如，如果 getXXX 方法为 getString，而基本数据库中数据类型为 VARCHAR，则 JDBC 驱动程序将把 VARCHAR 转换成 Java String。getString 的返回值将为 Java String 对象。 </p>
				<p>下表显示了允许用 getXXX 获取的 JDBC 类型及推荐用它获取的 JDBC 类型（通用 SQL 类型）。小写的 x 表示允许 getXXX 方法获取该数据类型；大写的 X 表示对该数据类型推荐使用 getXXX 方法。例如，除了 getBytes 和 getBinaryStream 之外的任何 getXXX 方法都可用来获取 LONGVARCHAR 值，但是推荐根据返回的数据类型使用 getAsciiStream 或 getUnicodeStream 方法。方法 getObject 将任何数据类型返回为 Java Object。当基本数据类型是特定于数据库的抽象类型或当通用应用程序需要接受任何数据类型时，它是非常有用的。 </p>
				<p>可使用 ResultSet.getXXX 方法获取常见的 JDBC 数据类型。 </p>
				<p>“x”表示该 getXXX 方法可合法地用于获取给定 JDBC 类型。 </p>
				<p>“X”表示推荐使用该 getXXX 方法来获取给定 JDBC 类型。 </p>
				<p>　 T <br />I <br />N <br />Y <br />I <br />N <br />T S <br />M <br />A <br />L <br />L <br />I <br />N <br />T I <br />N <br />T <br />E <br />G <br />E <br />R B <br />I <br />G </p>
				<p>N <br />T R <br />E <br />A <br />L F <br />L <br />O <br />A <br />T D <br />O <br />U <br />B <br />L <br />E D <br />E <br />C <br />I <br />M <br />A <br />L N <br />U <br />M <br />E <br />R <br />I <br />C B <br />I <br />T C <br />H <br />A <br />R V <br />A <br />R <br />C <br />H <br />A <br />R <br />L <br />O <br />N <br />G <br />V <br />A <br />R <br />C <br />H <br />A <br />R B <br />I <br />N <br />A <br />R <br />Y V <br />A <br />R <br />B <br />I <br />N <br />A <br />R <br />Y L <br />O <br />N <br />G <br />V <br />A <br />R <br />B <br />I <br />N <br />A <br />R <br />Y D <br />A <br />T <br />E T <br />I <br />M <br />E T <br />I <br />M <br />E <br />S <br />T <br />A <br />M <br />P  <br />getByte X x x x x x x x x x x x x 　 　 　 　 　 　  <br />getShort x X x x x x x x x x x x x 　 　 　 　 　 　  <br />getInt x x X x x x x x x x x x x 　 　 　 　 　 　  <br />getLong x x x X x x x x x x x x x 　 　 　 　 　 　  <br />getFloat x x x x X x x x x x x x x 　 　 　 　 　 　  <br />getDouble x x x x x X X x x x x x x 　 　 　 　 　 　  <br />getBigDecimal x x x x x x x X X x x x x 　 　 　 　 　 　  <br />getBoolean x x x x x x x x x X x x x 　 　 　 　 　 　  <br />getString x x x x x x x x x x X X x x x x x x x  <br />getBytes 　 　 　 　 　 　 　 　 　 　 　 　 　 X X x 　 　 　  <br />getDate 　 　 　 　 　 　 　 　 　 　 x x x 　 　 　 X 　 x  <br />getTime 　 　 　 　 　 　 　 　 　 　 x x x 　 　 　 　 X x  <br />getTimestamp 　 　 　 　 　 　 　 　 　 　 x x x 　 　 　 x 　 X  <br />getAsciiStream 　 　 　 　 　 　 　 　 　 　 x x X x x x 　 　 　  <br />getUnicodeStream 　 　 　 　 　 　 　 　 　 　 x x X x x x 　 　 　  <br />getBinaryStream 　 　 　 　 　 　 　 　 　 　 　 　 　 x x X 　 　 　  <br />getObject x x x x x x x x x x x x x x x x x x x  </p>
				<p>
						<br />5.1.4 对非常大的行值使用流 <br />ResultSet 可以获取任意大的 LONGVARBINARY 或 LONGVARCHAR 数据。方法 getBytes 和 getString 将数据返回为大的块（最大为 Statement.getMaxFieldSize 的返回值）。但是，以较小的固定块获取非常大的数据可能会更方便，而这可通过让 ResultSet 类返回 java.io.Input 流来完成。从该流中可分块读取数据。注意：必须立即访问这些流，因为在下一次对 ResultSet 调用 getXXX 时它们将自动关闭（这是由于基本实现对大块数据访问有限制）。  </p>
				<p>JDBC API 具有三个获取流的方法，分别具有不同的返回值：  </p>
				<p>
						<br />getBinaryStream 返回只提供数据库原字节而不进行任何转换的流。 </p>
				<p>
						<br />getAsciiStream 返回提供单字节 ASCII 字符的流。 </p>
				<p>
						<br />getUnicodeStream 返回提供双字节 Unicode 字符的流。 </p>
				<p>
						<br />注意：它不同于 Java 流，后者返回无类型字节并可（例如）通用于 ASCII 和 Unicode 字符。 </p>
				<p>下列代码演示了 getAsciiStream 的用法：  </p>
				<p>java.sql.Statement stmt = con.createStatement(); <br />ResultSet r = stmt.executeQuery("SELECT x FROM Table2"); <br />// 现在以 4K 块大小获取列 1 结果： <br />byte buff = new byte[4096]; <br />while (r.next()) { <br />Java.io.InputStream fin = r.getAsciiStream(1); <br />for (;;) { <br />int size = fin.read(buff); <br />if (size == -1) { // 到达流末尾 <br />break; <br />} <br />// 将新填充的缓冲区发送到 ASCII 输出流： <br />output.write(buff, 0, size); <br />} <br />} </p>
				<p>5.1.5 NULL 结果值 <br />要确定给定结果值是否是 JDBC NULL，必须先读取该列，然后使用 ResultSet.wasNull 方法检查该次读取是否返回 JDBC NULL。 </p>
				<p>当使用 ResultSet.getXXX 方法读取 JDBC NULL 时，方法 wasNull 将返回下列值之一：  </p>
				<p>
						<br />Java null 值：对于返回 Java 对象的 getXXX 方法（例如 getString、getBigDecimal、getBytes、getDate、getTime、getTimestamp、getAsciiStream、getUnicodeStream、getBinaryStream、getObject 等）。 </p>
				<p>
						<br />零值：对于 getByte、getShort、getInt、getLong、getFloat 和 getDouble。 </p>
				<p>
						<br />false 值：对于 getBoolean。 </p>
				<p>
						<br />5.1.6 可选结果集或多结果集 <br />通常使用 executeQuery（它返回单个 ResultSet）或 executeUpdate（它可用于任何数据库修改语句，并返回更新行数）可执行 SQL 语句。但有些情况下，应用程序在执行语句之前不知道该语句是否返回结果集。此外，有些已存储过程可能返回几个不同的结果集和/或更新计数。 </p>
				<p>为了适应这些情况，JDBC 提供了一种机制，允许应用程序执行语句，然后处理由结果集和更新计数组成的任意集合。这种机制的原理是首先调用一个完全通用的 execute 方法，然后调用另外三个方法，getResultSet、getUpdateCount 和 getMoreResults。这些方法允许应用程序一次一个地研究语句结果，并确定给定结果是 ResultSet 还是更新计数。 </p>
				<p>用户不必关闭 ResultSet；当产生它的 Statement 关闭、重新执行或用于从多结果序列中获取下一个结果时，该 ResultSet 将被 Statement 自动关闭。  </p>
				<br />
				<br />
				<p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=630447</p>
		</div>
<img src ="http://www.blogjava.net/iKingQu/aggbug/36761.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iKingQu/" target="_blank">風向逆轉 - 就要爪哇</a> 2006-03-22 03:31 <a href="http://www.blogjava.net/iKingQu/articles/36761.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[收藏]JDBC系列教程（三）---语句</title><link>http://www.blogjava.net/iKingQu/articles/36760.html</link><dc:creator>風向逆轉 - 就要爪哇</dc:creator><author>風向逆轉 - 就要爪哇</author><pubDate>Tue, 21 Mar 2006 19:30:00 GMT</pubDate><guid>http://www.blogjava.net/iKingQu/articles/36760.html</guid><wfw:comment>http://www.blogjava.net/iKingQu/comments/36760.html</wfw:comment><comments>http://www.blogjava.net/iKingQu/articles/36760.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/iKingQu/comments/commentRss/36760.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iKingQu/services/trackbacks/36760.html</trackback:ping><description><![CDATA[
		<div class="postText">
				<p>
						<span class="Title">JDBC系列教程（三）---语句 </span>
				</p>
				<p>Statement <br />本概述是从《JDBCTM Database Access from JavaTM: A Tutorial and Annotated Reference 》这本书中摘引来的。JavaSoft 目前正在准备这本书。这是一本教程，同时也是 JDBC 的重要参考手册，它将作为 Java 系列的组成部份在 1997 年春季由 Addison-Wesley 出版公司出版。  </p>
				<p>4.1 概述 <br />Statement 对象用于将 SQL 语句发送到数据库中。实际上有三种 Statement 对象，它们都作为在给定连接上执行 SQL 语句的包容器：Statement、PreparedStatement（它从 Statement 继承而来）和 CallableStatement（它从 PreparedStatement 继承而来）。它们都专用于发送特定类型的 SQL 语句： Statement 对象用于执行不带参数的简单 SQL 语句；PreparedStatement 对象用于执行带或不带 IN 参数的预编译 SQL 语句；CallableStatement 对象用于执行对数据库已存储过程的调用。 </p>
				<p>Statement 接口提供了执行语句和获取结果的基本方法。PreparedStatement 接口添加了处理 IN 参数的方法；而 CallableStatement 添加了处理 OUT 参数的方法。 </p>
				<p>
						<br />4.1.1 创建 Statement 对象 <br />建立了到特定数据库的连接之后，就可用该连接发送 SQL 语句。Statement 对象用 Connection 的方法 createStatement 创建，如下列代码段中所示：  </p>
				<p>Connection con = DriverManager.getConnection(url, "sunny", ""); <br />Statement stmt = con.createStatement(); </p>
				<p>为了执行 Statement 对象，被发送到数据库的 SQL 语句将被作为参数提供给 Statement 的方法：  </p>
				<p>ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table2"); </p>
				<p>4.1.2 使用 Statement 对象执行语句 <br />Statement 接口提供了三种执行 SQL 语句的方法：executeQuery、executeUpdate 和 execute。使用哪一个方法由 SQL 语句所产生的内容决定。 </p>
				<p>方法 executeQuery 用于产生单个结果集的语句，例如 SELECT 语句。 </p>
				<p>方法 executeUpdate 用于执行 INSERT、UPDATE 或 DELETE 语句以及 SQL DDL（数据定义语言）语句，例如 CREATE TABLE 和 DROP TABLE。INSERT、UPDATE 或 DELETE 语句的效果是修改表中零行或多行中的一列或多列。executeUpdate 的返回值是一个整数，指示受影响的行数（即更新计数）。对于 CREATE TABLE 或 DROP TABLE 等不操作行的语句，executeUpdate 的返回值总为零。 </p>
				<p>方法 execute 用于执行返回多个结果集、多个更新计数或二者组合的语句。因为多数程序员不会需要该高级功能，所以本概述后面将在单独一节中对其进行介绍。 </p>
				<p>执行语句的所有方法都将关闭所调用的 Statement 对象的当前打开结果集（如果存在）。这意味着在重新执行 Statement 对象之前，需要完成对当前 ResultSet 对象的处理。 </p>
				<p>应注意，继承了 Statement 接口中所有方法的 PreparedStatement 接口都有自己的 executeQuery、executeUpdate 和 execute 方法。Statement 对象本身不包含 SQL 语句，因而必须给 Statement.execute 方法提供 SQL 语句作为参数。PreparedStatement 对象并不将 SQL 语句作为参数提供给这些方法，因为它们已经包含预编译 SQL 语句。CallableStatement 对象继承这些方法的 PreparedStatement 形式。对于这些方法的 PreparedStatement 或 CallableStatement 版本，使用查询参数将抛出 SQLException。 </p>
				<p>
						<br />4.1.3 语句完成 <br />当连接处于自动提交模式时，其中所执行的语句在完成时将自动提交或还原。语句在已执行且所有结果返回时，即认为已完成。对于返回一个结果集的 executeQuery 方法，在检索完 ResultSet 对象的所有行时该语句完成。对于方法 executeUpdate，当它执行时语句即完成。但在少数调用方法 execute 的情况中，在检索所有结果集或它生成的更新计数之后语句才完成。 </p>
				<p>有些 DBMS 将已存储过程中的每条语句视为独立的语句；而另外一些则将整个过程视为一个复合语句。在启用自动提交时，这种差别就变得非常重要，因为它影响什么时候调用 commit 方法。在前一种情况中，每条语句单独提交；在后一种情况中，所有语句同时提交。 </p>
				<p>
						<br />4.1.4 关闭 Statement 对象 <br />Statement 对象将由 Java 垃圾收集程序自动关闭。而作为一种好的编程风格，应在不需要 Statement 对象时显式地关闭它们。这将立即释放 DBMS 资源，有助于避免潜在的内存问题。 </p>
				<p>
						<br />4.1.5 Statement 对象中的 SQL 转义语法  <br />Statement 可包含使用 SQL 转义语法的 SQL 语句。转义语法告诉驱动程序其中的代码应该以不同方式处理。驱动程序将扫描任何转义语法，并将它转换成特定数据库可理解的代码。这使得转义语法与 DBMS 无关，并允许程序员使用在没有转义语法时不可用的功能。 </p>
				<p>转义子句由花括号和关键字界定：  </p>
				<p>{keyword . . . parameters . . . } </p>
				<p>该关键字指示转义子句的类型，如下所示。 </p>
				<p>
						<br />escape 表示 LIKE 转义字符  </p>
				<p>
						<br />字符“%”和“_”类似于 SQL LIKE 子句中的通配符（“%”匹配零个或多个字符，而“_”则匹配一个字符）。为了正确解释它们，应在其前面加上反斜杠（“\”），它是字符串中的特殊转义字符。在查询末尾包括如下语法即可指定用作转义字符的字符：  </p>
				<p>{escape 'escape-character'} </p>
				<p>
						<br />例如，下列查询使用反斜杠字符作为转义字符，查找以下划线开头的标识符名：  </p>
				<p>stmt.executeQuery("SELECT name FROM Identifiers <br />WHERE Id LIKE `\_%' {escape `\'}; </p>
				<p>
						<br />fn 表示标量函数 </p>
				<p>
						<br />几乎所有 DBMS 都具有标量值的数值、字符串、时间、日期、系统和转换函数。要使用这些函数，可使用如下转义语法：关键字 fn 后跟所需的函数名及其参数。例如，下列代码调用函数 concat 将两个参数连接在一起：  </p>
				<p>{fn concat("Hot", "Java")}; </p>
				<p>
						<br />可用下列语法获得当前数据库用户名：  </p>
				<p>{fn user()}; </p>
				<p>
						<br />标量函数可能由语法稍有不同的 DBMS 支持，而它们可能不被所有驱动程序支持。各种 DatabaseMetaData 方法将列出所支持的函数。例如，方法 getNumericFunctions 返回用逗号分隔的数值函数列表，而方法 getStringFunctions 将返回字符串函数，等等。 </p>
				<p>驱动程序将转义函数调用映射为相应的语法，或直接实现该函数。 </p>
				<p>
						<br />d、t 和 ts 表示日期和时间文字 </p>
				<p>
						<br />DBMS 用于日期、时间和时间标记文字的语法各不相同。JDBC 使用转义子句支持这些文字的语法的 ISO 标准格式。驱动程序必须将转义子句转换成 DBMS 表示。 </p>
				<p>例如，可用下列语法在 JDBC SQL 语句中指定日期：  </p>
				<p>{d `yyyy-mm-dd'} </p>
				<p>
						<br />在该语法中，yyyy 为年代，mm 为月份，而 dd 则为日期。驱动程序将用等价的特定于 DBMS 的表示替换这个转义子句。例如，如果 '28- FEB-99' 符合基本数据库的格式，则驱动程序将用它替换 {d 1999-02-28}。 </p>
				<p>对于 TIME 和 TIMESTAMP 也有类似的转义子句：  </p>
				<p>{t `hh:mm:ss'} <br />{ts `yyyy-mm-dd hh:mm:ss.f . . .'} </p>
				<p>
						<br />TIMESTAMP 中的小数点后的秒（.f . . .）部分可忽略。 </p>
				<p>
						<br />call 或 ? = call 表示已存储过程 </p>
				<p>
						<br />如果数据库支持已存储过程，则可从 JDBC 中调用它们，语法为：  </p>
				<p>{call procedure_name[(?, ?, . . .)]} </p>
				<p>
						<br />或（其中过程返回结果参数）：  </p>
				<p>{? = call procedure_name[(?, ?, . . .)]} </p>
				<p>
						<br />方括号指示其中的内容是可选的。它们不是语法的必要部分。 </p>
				<p>输入参数可以为文字或参数。有关详细信息，参见 JDBC 指南中第 7 节，“CallableStatement”。 </p>
				<p>可通过调用方法 DatabaseMetaData.supportsStoredProcedures 检查数据库是否支持已存储过程。 </p>
				<p>
						<br />oj 表示外部连接 </p>
				<p>
						<br />外部连接的语法为  </p>
				<p>{oj outer-join} </p>
				<p>
						<br />其中 outer-join 形式为  </p>
				<p>table LEFT OUTER JOIN {table / outer-join} ON search-condition </p>
				<p>
						<br />外部连接属于高级功能。有关它们的解释可参见 SQL 语法。JDBC 提供了三种 DatabaseMetaData 方法用于确定驱动程序支持哪些外部连接类型：supportsOuterJoins、supportsFullOuterJoins 和 supportsLimitedOuterJoins。 </p>
				<p>
						<br />方法 Statement.setEscapeProcessing 可打开或关闭转义处理；缺省状态为打开。当性能极为重要时，程序员可能想关闭它以减少处理时间。但通常它将出于打开状态。应注意： setEscapeProcessing 不适用于 PreparedStatement 对象，因为在调用该语句前它就可能已被发送到数据库。有关预编译的信息，参见 PreparedStatement。 </p>
				<p>
						<br />4.1.6 使用方法 execute <br />execute 方法应该仅在语句能返回多个 ResultSet 对象、多个更新计数或 ResultSet 对象与更新计数的组合时使用。当执行某个已存储过程或动态执行未知 SQL 字符串（即应用程序程序员在编译时未知）时，有可能出现多个结果的情况，尽管这种情况很少见。例如，用户可能执行一个已存储过程（使用 CallableStatement 对象 - 参见第 135 页的 CallableStatement），并且该已存储过程可执行更新，然后执行选择，再进行更新，再进行选择，等等。通常使用已存储过程的人应知道它所返回的内容。 </p>
				<p>因为方法 execute 处理非常规情况，所以获取其结果需要一些特殊处理并不足为怪。例如，假定已知某个过程返回两个结果集，则在使用方法 execute 执行该过程后，必须调用方法 getResultSet 获得第一个结果集，然后调用适当的 getXXX 方法获取其中的值。要获得第二个结果集，需要先调用 getMoreResults 方法，然后再调用 getResultSet 方法。如果已知某个过程返回两个更新计数，则首先调用方法 getUpdateCount，然后调用 getMoreResults，并再次调用 getUpdateCount。 </p>
				<p>对于不知道返回内容，则情况更为复杂。如果结果是 ResultSet 对象，则方法 execute 返回 true；如果结果是 Java int，则返回 false。如果返回 int，则意味着结果是更新计数或执行的语句是 DDL 命令。在调用方法 execute 之后要做的第一件事情是调用 getResultSet 或 getUpdateCount。调用方法 getResultSet 可以获得两个或多个 ResultSet 对象中第一个对象；或调用方法 getUpdateCount 可以获得两个或多个更新计数中第一个更新计数的内容。 </p>
				<p>当 SQL 语句的结果不是结果集时，则方法 getResultSet 将返回 null。这可能意味着结果是一个更新计数或没有其它结果。在这种情况下，判断 null 真正含义的唯一方法是调用方法 getUpdateCount，它将返回一个整数。这个整数为调用语句所影响的行数；如果为 -1 则表示结果是结果集或没有结果。如果方法 getResultSet 已返回 null（表示结果不是 ResultSet 对象），则返回值 -1 表示没有其它结果。也就是说，当下列条件为真时表示没有结果（或没有其它结果）：  </p>
				<p>((stmt.getResultSet() == null) &amp;&amp; (stmt.getUpdateCount() == -1)) </p>
				<p>如果已经调用方法 getResultSet 并处理了它返回的 ResultSet 对象，则有必要调用方法 getMoreResults 以确定是否有其它结果集或更新计数。如果 getMoreResults 返回 true，则需要再次调用 getResultSet 来检索下一个结果集。如上所述，如果 getResultSet 返回 null，则需要调用 getUpdateCount 来检查 null 是表示结果为更新计数还是表示没有其它结果。 </p>
				<p>当 getMoreResults 返回 false 时，它表示该 SQL 语句返回一个更新计数或没有其它结果。因此需要调用方法 getUpdateCount 来检查它是哪一种情况。在这种情况下，当下列条件为真时表示没有其它结果：  </p>
				<p>((stmt.getMoreResults() == false) &amp;&amp; (stmt.getUpdateCount() == -1)) </p>
				<p>下面的代码演示了一种方法用来确认已访问调用方法 execute 所产生的全部结果集和更新计数：  </p>
				<p>
						<br />stmt.execute(queryStringWithUnknownResults); <br />while (true) { <br />int rowCount = stmt.getUpdateCount(); <br />if (rowCount &gt; 0) { // 它是更新计数 <br />System.out.println("Rows changed = " + count); <br />stmt.getMoreResults(); <br />continue; <br />} <br />if (rowCount == 0) { // DDL 命令或 0 个更新 <br />System.out.println(" No rows changed or statement was DDL <br />command"); <br />stmt.getMoreResults(); <br />continue; <br />} </p>
				<p>// 执行到这里，证明有一个结果集 <br />// 或没有其它结果 </p>
				<p>ResultSet rs = stmt.getResultSet; <br />if (rs != null) { <br />. . . // 使用元数据获得关于结果集列的信息 <br />while (rs.next()) { <br />. . . // 处理结果 <br />stmt.getMoreResults(); <br />continue; <br />} <br />break; // 没有其它结果 </p>
				<br />
				<br />
				<p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=630445</p>
		</div>
<img src ="http://www.blogjava.net/iKingQu/aggbug/36760.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iKingQu/" target="_blank">風向逆轉 - 就要爪哇</a> 2006-03-22 03:30 <a href="http://www.blogjava.net/iKingQu/articles/36760.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[收藏]JDBC系列教程（二）---驱动设置</title><link>http://www.blogjava.net/iKingQu/articles/36759.html</link><dc:creator>風向逆轉 - 就要爪哇</dc:creator><author>風向逆轉 - 就要爪哇</author><pubDate>Tue, 21 Mar 2006 19:28:00 GMT</pubDate><guid>http://www.blogjava.net/iKingQu/articles/36759.html</guid><wfw:comment>http://www.blogjava.net/iKingQu/comments/36759.html</wfw:comment><comments>http://www.blogjava.net/iKingQu/articles/36759.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/iKingQu/comments/commentRss/36759.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iKingQu/services/trackbacks/36759.html</trackback:ping><description><![CDATA[
		<div class="postText">
				<p>
						<span class="Title">JDBC系列教程（二）---驱动设置 </span>
				</p>
				<p>DriverManager <br />本概述摘自《JDBCTM Database Access from JavaTM: A Tutorial and Annotated Reference》，目前正由 JavaSoft 继续编写。这本书既是 JDBC 的教程，也是一本权威性参考手册，将作为 Java 系列的一部分在 1997 年春季由 Addison-Wesley 出版公司出版。  </p>
				<p>3.1 概述 <br />DriverManager 类是 JDBC 的管理层，作用于用户和驱动程序之间。它跟踪可用的驱动程序，并在数据库和相应驱动程序之间建立连接。另外，DriverManager 类也处理诸如驱动程序登录时间限制及登录和跟踪消息的显示等事务。 </p>
				<p>对于简单的应用程序，一般程序员需要在此类中直接使用的唯一方法是 DriverManager.getConnection。正如名称所示，该方法将建立与数据库的连接。JDBC 允许用户调用 DriverManager 的方法 getDriver、getDrivers 和 registerDriver 及 Driver 的方法 connect。但多数情况下，让 DriverManager 类管理建立连接的细节为上策。 </p>
				<p>
						<br />3.1.1 跟踪可用驱动程序 <br />DriverManager 类包含一列 Driver 类，它们已通过调用方法 DriverManager.registerDriver 对自己进行了注册。所有 Driver 类都必须包含有一个静态部分。它创建该类的实例，然后在加载该实例时 DriverManager 类进行注册。这样，用户正常情况下将不会直接调用 DriverManager.registerDriver；而是在加载驱动程序时由驱动程序自动调用。加载 Driver 类，然后自动在 DriverManager 中注册的方式有两种：  </p>
				<p>
						<br />通过调用方法 Class.forName。这将显式地加载驱动程序类。由于这与外部设置无关，因此推荐使用这种加载驱动程序的方法。以下代码加载类 acme.db.Driver：  <br />Class.forName("acme.db.Driver"); </p>
				<p>如果将 acme.db.Driver 编写为加载时创建实例，并调用以该实例为参数的 DriverManager.registerDriver（本该如此），则它在 DriverManager 的驱动程序列表中，并可用于创建连接。 </p>
				<p>
						<br />通过将驱动程序添加到 java.lang.System 的属性 jdbc.drivers 中。这是一个由 DriverManager 类加载的驱动程序类名的列表，由冒号分隔：初始化 DriverManager 类时，它搜索系统属性 jdbc.drivers，如果用户已输入了一个或多个驱动程序，则 DriverManager 类将试图加载它们。以下代码说明程序员如何在 ~/.hotjava/properties 中输入三个驱动程序类（启动时，HotJava 将把它加载到系统属性列表中）：  <br />jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.test.ourDriver; </p>
				<p>对 DriverManager 方法的第一次调用将自动加载这些驱动程序类。 </p>
				<p>注意：加载驱动程序的第二种方法需要持久的预设环境。如果对这一点不能保证，则调用方法 Class.forName 显式地加载每个驱动程序就显得更为安全。这也是引入特定驱动程序的方法，因为一旦 DriverManager 类被初始化，它将不再检查 jdbc.drivers 属性列表。 </p>
				<p>在以上两种情况中，新加载的 Driver 类都要通过调用 DriverManager.registerDriver 类进行自我注册。如上所述，加载类时将自动执行这一过程。 </p>
				<p>由于安全方面的原因，JDBC 管理层将跟踪哪个类加载器提供哪个驱动程序。这样，当 DriverManager 类打开连接时，它仅使用本地文件系统或与发出连接请求的代码相同的类加载器提供的驱动程序。 </p>
				<p>
						<br />3.1.2 建立连接 <br />加载 Driver 类并在 DriverManager 类中注册后，它们即可用来与数据库建立连接。当调用 DriverManager.getConnection 方法发出连接请求时，DriverManager 将检查每个驱动程序，查看它是否可以建立连接。 </p>
				<p>有时可能有多个 JDBC 驱动程序可以与给定的 URL 连接。例如，与给定远程数据库连接时，可以使用 JDBC-ODBC 桥驱动程序、JDBC 到通用网络协议驱动程序或数据库厂商提供的驱动程序。在这种情况下，测试驱动程序的顺序至关重要，因为 DriverManager 将使用它所找到的第一个可以成功连接到给定 URL 的驱动程序。 </p>
				<p>首先 DriverManager 试图按注册的顺序使用每个驱动程序（jdbc.drivers 中列出的驱动程序总是先注册）。它将跳过代码不可信任的驱动程序，除非加载它们的源与试图打开连接的代码的源相同。 </p>
				<p>它通过轮流在每个驱动程序上调用方法 Driver.connect，并向它们传递用户开始传递给方法 DriverManager.getConnection 的 URL 来对驱动程序进行测试，然后连接第一个认出该 URL 的驱动程序。 </p>
				<p>这种方法初看起来效率不高，但由于不可能同时加载数十个驱动程序，因此每次连接实际只需几个过程调用和字符串比较。 </p>
				<p>以下代码是通常情况下用驱动程序（例如 JDBC-ODBC 桥驱动程序）建立连接所需所有步骤的示例：  </p>
				<p>Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); //加载驱动程序 <br />String url = "jdbc:odbc:fred"; <br />DriverManager.getConnection(url, "userID", "passwd"); </p>
				<br />
				<br />
				<p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=630442</p>
		</div>
<img src ="http://www.blogjava.net/iKingQu/aggbug/36759.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iKingQu/" target="_blank">風向逆轉 - 就要爪哇</a> 2006-03-22 03:28 <a href="http://www.blogjava.net/iKingQu/articles/36759.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[收藏]JDBC系列教程（一）---连接</title><link>http://www.blogjava.net/iKingQu/articles/36758.html</link><dc:creator>風向逆轉 - 就要爪哇</dc:creator><author>風向逆轉 - 就要爪哇</author><pubDate>Tue, 21 Mar 2006 19:27:00 GMT</pubDate><guid>http://www.blogjava.net/iKingQu/articles/36758.html</guid><wfw:comment>http://www.blogjava.net/iKingQu/comments/36758.html</wfw:comment><comments>http://www.blogjava.net/iKingQu/articles/36758.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/iKingQu/comments/commentRss/36758.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iKingQu/services/trackbacks/36758.html</trackback:ping><description><![CDATA[
		<div class="postText">
				<p>
						<span class="Title">JDBC系列教程（一）---连接</span>
				</p>
				<p>连接 <br />本概述是从《JDBCTM Database Access from JavaTM: A Tutorial and Annotated Reference 》这本书中摘引来的。JavaSoft 目前正在准备这本书。这本书是一本教程，同时也是 JDBC 的重要参考手册，它将作为 Java 系列的组成部份在 1997 年春季由 Addison-Wesley 出版公司出版。  </p>
				<p>
						<br />2.1 概述 <br />Connection 对象代表与数据库的连接。连接过程包括所执行的 SQL 语句和在该连接上所返回的结果。一个应用程序可与单个数据库有一个或多个连接，或者可与许多数据库有连接。 </p>
				<p>
						<br />2.1.1 打开连接 <br />与数据库建立连接的标准方法是调用 DriverManager.getConnection 方法。该方法接受含有某个 URL 的字符串。DriverManager 类（即所谓的 JDBC 管理层）将尝试找到可与那个 URL 所代表的数据库进行连接的驱动程序。DriverManager 类存有已注册的 Driver 类的清单。当调用方法 getConnection 时，它将检查清单中的每个驱动程序，直到找到可与 URL 中指定的数据库进行连接的驱动程序为止。Driver 的方法 connect 使用这个 URL 来建立实际的连接。 </p>
				<p>用户可绕过 JDBC 管理层直接调用 Driver 方法。这在以下特殊情况下将很有用：当两个驱动器可同时连接到数据库中，而用户需要明确地选用其中特定的驱动器。但一般情况下，让 DriverManager 类处理打开连接这种事将更为简单。 </p>
				<p>下述代码显示如何打开一个与位于 URL "jdbc:odbc:wombat" 的数据库的连接。所用的用户标识符为 "oboy" ，口令为 "12Java"：  </p>
				<p>String url = "jdbc:odbc:wombat"; <br />Connection con = DriverManager.getConnection(url, "oboy", "12Java"); </p>
				<p>2.1.2 一般用法的 URL <br />由于 URL 常引起混淆，我们将先对一般 URL 作简单说明，然后再讨论 JDBC URL。 </p>
				<p>URL（统一资源定位符）提供在 Internet 上定位资源所需的信息。可将它想象为一个地址。 </p>
				<p>URL 的第一部份指定了访问信息所用的协议，后面总是跟着冒号。常用的协议有 "ftp"（代表“文件传输协议”）和 "http" （代表“超文本传输协议”）。如果协议是 "file"，表示资源是在某个本地文件系统上而非在 Internet 上（下例用于表示我们所描述的部分；它并非 URL 的组成部分）。 </p>
				<p>
						<a href="ftp://javasoft.com/docs/JDK-1_apidocs.zip">ftp://javasoft.com/docs/JDK-1_apidocs.zip</a>
						<br />
						<a href="http://java.sun.com/products/jdk/CurrentRelease">http://java.sun.com/products/jdk/CurrentRelease</a>
						<br />file:/home/haroldw/docs/books/tutorial/summary.html </p>
				<p>URL 的其余部份（冒号后面的）给出了数据资源所处位置的有关信息。如果协议是 file，则 URL 的其余部份是文件的路径。对于 ftp 和 http 协议，URL 的其余部份标识了主机并可选地给出某个更详尽的地址路径。例如，以下是 JavaSoft 主页的 URL。该 URL 只标识了主机：  </p>
				<p>
						<a href="http://java.sun.com/">http://java.sun.com</a>
				</p>
				<p>从该主页开始浏览，就可以进到许多其它的网页中，其中之一就是 JDBC 主页。JDBC 主页的 URL 更为具体，它看起来类似：  </p>
				<p>
						<a href="http://java.sun.com/products/jdbc">http://java.sun.com/products/jdbc</a>
				</p>
				<p>2.1.3 JDBC URL  <br />JDBC URL 提供了一种标识数据库的方法，可以使相应的驱动程序能识别该数据库并与之建立连接。实际上，驱动程序编程员将决定用什么 JDBC URL 来标识特定的驱动程序。用户不必关心如何来形成 JDBC URL；他们只须使用与所用的驱动程序一起提供的 URL 即可。JDBC 的作用是提供某些约定，驱动程序编程员在构造他们的 JDBC URL 时应该遵循这些约定。 </p>
				<p>由于 JDBC URL 要与各种不同的驱动程序一起使用，因此这些约定应非常灵活。首先，它们应允许不同的驱动程序使用不同的方案来命名数据库。例如， odbc 子协议允许（但并不是要求） URL 含有属性值。 </p>
				<p>第二，JDBC URL 应允许驱动程序编程员将一切所需的信息编入其中。这样就可以让要与给定数据库对话的 applet 打开数据库连接，而无须要求用户去做任何系统管理工作。 </p>
				<p>第三， JDBC URL 应允许某种程度的间接性。也就是说，JDBC URL 可指向逻辑主机或数据库名，而这种逻辑主机或数据库名将由网络命名系统动态地转换为实际的名称。这可以使系统管理员不必将特定主机声明为 JDBC 名称的一部份。网络命名服务（例如 DNS、 NIS 和 DCE ）有多种,而对于使用哪种命名服务并无限制。 </p>
				<p>JDBC URL 的标准语法如下所示。它由三部分组成，各部分间用冒号分隔：  </p>
				<p>jdbc:&lt; 子协议 &gt;:&lt; 子名称 &gt; </p>
				<p>JDBC URL 的三个部分可分解如下：  </p>
				<p>
						<br />jdbc ─ 协议。JDBC URL 中的协议总是 jdbc。 </p>
				<p>
						<br />&lt;子协议&gt; ─ 驱动程序名或数据库连接机制（这种机制可由一个或多个驱动程序支持）的名称。子协议名的典型示例是 "odbc"，该名称是为用于指定 ODBC 风格的数据资源名称的 URL 专门保留的。例如，为了通过 JDBC-ODBC 桥来访问某个数据库，可以用如下所示的 URL：  <br />jdbc:odbc:fred </p>
				<p>本例中，子协议为 "odbc"，子名称 "fred" 是本地 <br />ODBC 数据资源。 </p>
				<p>如果要用网络命名服务（这样 JDBC URL 中的数据库名称不必是实际名称），则命名服务可以作为子协议。例如，可用如下所示的 URL ：  </p>
				<p>jdbc:dcenaming:accounts-payable </p>
				<p>本例中，该 URL 指定了本地 DCE 命名服务应该将 <br />数据库名称 "accounts-payable" 解析为更为具体的 <br />可用于连接真实数据库的名称。 </p>
				<p>
						<br />&lt;子名称&gt; ─ 一种标识数据库的方法。子名称可以依不同的子协议而变化。它还可以有子名称的子名称（含有驱动程序编程员所选的任何内部语法）。使用子名称的目的是为定位数据库提供足够的信息。前例中，因为 ODBC 将提供其余部份的信息，因此用 "fred" 就已足够。然而，位于远程服务器上的数据库需要更多的信息。例如，如果数据库是通过 Internet 来访问的，则在 JDBC URL 中应将网络地址作为子名称的一部份包括进去，且必须遵循如下所示的标准 URL 命名约定：  <br />//主机名:端口/子协议 </p>
				<p>假设 "dbnet" 是个用于将某个主机连接到 Internet 上的协议，则 JDBC URL 类似： </p>
				<p>jdbc:dbnet://wombat:356/fred  </p>
				<p>2.1.4 "odbc" 子协议 <br />子协议 odbc 是一种特殊情况。它是为用于指定 ODBC 风格的数据资源名称的 URL 而保留的，并具有下列特性：允许在子名称（数据资源名称）后面指定任意多个属性值。odbc 子协议的完整语法为：  </p>
				<p>
						<br />jdbc:odbc:&lt; 数据资源名称 &gt;[;&lt; 属性名 &gt;=&lt; 属性值 &gt;]* </p>
				<p>因此，以下都是合法的 jdbc:odbc 名称：  </p>
				<p>jdbc:odbc:qeor7 <br />jdbc:odbc:wombat <br />jdbc:odbc:wombat;CacheSize=20;ExtensionCase=LOWER <br />jdbc:odbc:qeora;UID=kgh;PWD=fooey </p>
				<p>2.1.5 注册子协议 <br />驱动程序编程员可保留某个名称以将之用作 JDBC URL 的子协议名。当 DriverManager 类将此名称加到已注册的驱动程序清单中时，为之保留该名称的驱动程序应能识别该名称并与它所标识的数据库建立连接。例如，odbc 是为 JDBC- ODBC 桥而保留的。示例之二，假设有个 Miracle 公司，它可能会将 "miracle" 注册为连接到其 Miracle DBMS 上的 JDBC 驱动程序的子协议，从而使其他人都无法使用这个名称。 </p>
				<p>JavaSoft 目前作为非正式代理负责注册 JDBC 子协议名称。要注册某个子协议名称，请发送电子邮件到下述地址：  </p>
				<p>
						<a href="mailto:jdbc@wombat.eng.sun.com">jdbc@wombat.eng.sun.com</a>
				</p>
				<p>2.1.6 发送 SQL 语句 <br />连接一旦建立，就可用来向它所涉及的数据库传送 SQL 语句。JDBC 对可被发送的 SQL 语句类型不加任何限制。这就提供了很大的灵活性，即允许使用特定的数据库语句或甚至于非 SQL 语句。然而，它要求用户自己负责确保所涉及的数据库可以处理所发送的 SQL 语句，否则将自食其果。例如，如果某个应用程序试图向不支持储存程序的 DBMS 发送储存程序调用，就会失败并将抛出异常。JDBC 要求驱动程序应至少能提供 ANSI SQL-2 Entry Level 功能才可算是符合 JDBC 标准TM 的。这意味着用户至少可信赖这一标准级别的功能。 </p>
				<p>JDBC 提供了三个类，用于向数据库发送 SQL 语句。Connection 接口中的三个方法可用于创建这些类的实例。下面列出这些类及其创建方法：  </p>
				<p>
						<br />Statement ─ 由方法 createStatement 所创建。Statement 对象用于发送简单的 SQL 语句。  <br />PreparedStatement ─ 由方法 prepareStatement 所创建。PreparedStatement 对象用于发送带有一个或多个输入参数（ IN 参数）的 SQL 语句。PreparedStatement 拥有一组方法，用于设置 IN 参数的值。执行语句时，这些 IN 参数将被送到数据库中。PreparedStatement 的实例扩展了 Statement ，因此它们都包括了 Statement 的方法。PreparedStatement 对象有可能比 Statement 对象的效率更高，因为它已被预编译过并存放在那以供将来使用。  <br />CallableStatement ─ 由方法 prepareCall 所创建。CallableStatement 对象用于执行 SQL 储存程序 ─ 一组可通过名称来调用（就象函数的调用那样）的 SQL 语句。CallableStatement 对象从 PreparedStatement 中继承了用于处理 IN 参数的方法，而且还增加了用于处理 OUT 参数和 INOUT 参数的方法。  </p>
				<p>以下所列提供的方法可以快速决定应用哪个 Connection 方法来创建不同类型的 SQL 语句：  </p>
				<p>
						<br />createStatement 方法用于： </p>
				<p>
						<br />简单的 SQL 语句（不带参数）  </p>
				<p>
						<br />prepareStatement 方法用于：  </p>
				<p>
						<br />带一个或多个 IN 参数的 SQL 语句  </p>
				<p>
						<br />经常被执行的简单 SQL 语句 </p>
				<p>
						<br />prepareCall 方法用于：  </p>
				<p>
						<br />调用已储存过程 </p>
				<p>
						<br />2.1.7 事务 <br />事务由一个或多个这样的语句组成：这些语句已被执行、完成并被提交或还原。当调用方法 commit 或 rollback 时，当前事务即告就结束，另一个事务随即开始。 </p>
				<p>缺省情况下，新连接将处于自动提交模式。也就是说，当执行完语句后，将自动对那个语句调用 commit 方法。这种情况下，由于每个语句都是被单独提交的，因此一个事务只由一个语句组成。如果禁用自动提交模式，事务将要等到 commit 或 rollback 方法被显式调用时才结束，因此它将包括上一次调用 commit 或 rollback 方法以来所有执行过的语句。对于第二种情况，事务中的所有语句将作为组来提交或还原。 </p>
				<p>方法 commit 使 SQL 语句对数据库所做的任何更改成为永久性的，它还将释放事务持有的全部锁。而方法 rollback 将弃去那些更改。 </p>
				<p>有时用户在另一个更改生效前不想让此更改生效。这可通过禁用自动提交并将两个更新组合在一个事务中来达到。如果两个更新都是成功的，则调用 commit 方法，从而使两个更新结果成为永久性的；如果其中之一或两个更新都失败了，则调用 rollback 方法，以将值恢复为进行更新之前的值。 </p>
				<p>大多数 JDBC 驱动程序都支持事务。事实上，符合 JDBC 的驱动程序必须支持事务。DatabaseMetaData 给出的信息描述 DBMS 所提供的事务支持水平。 </p>
				<p>
						<br />2.1.8 事务隔离级别 <br />如果 DBMS 支持事务处理，它必须有某种途径来管理两个事务同时对一个数据库进行操作时可能发生的冲突。用户可指定事务隔离级别，以指明 DBMS 应该花多大精力来解决潜在冲突。例如，当事务更改了某个值而第二个事务却在该更改被提交或还原前读取该值时该怎么办？ 假设第一个事务被还原后，第二个事务所读取的更改值将是无效的，那么是否可允许这种冲突？ JDBC 用户可用以下代码来指示 DBMS 允许在值被提交前读取该值（“dirty 读取”），其中 con 是当前连接：  </p>
				<p>con.setTransactionIsolation(TRANSACTION_READ_UNCOMMITTED); </p>
				<p>事务隔离级别越高，为避免冲突所花的精力也就越多。Connection 接口定义了五级，其中最低级别指定了根本就不支持事务，而最高级别则指定当事务在对某个数据库进行操作时，任何其它事务不得对那个事务正在读取的数据进行任何更改。通常，隔离级别越高，应用程序执行的速度也就越慢（由于用于锁定的资源耗费增加了，而用户间的并发操作减少了）。在决定采用什么隔离级别时，开发人员必须在性能需求和数据一致性需求之间进行权衡。当然，实际所能支持的级别取决于所涉及的 DBMS 的功能。 </p>
				<p>当创建 Connection 对象时，其事务隔离级别取决于驱动程序，但通常是所涉及的数据库的缺省值。用户可通过调用 setIsolationLevel 方法来更改事务隔离级别。新的级别将在该连接过程的剩余时间内生效。要想只改变一个事务的事务隔离级别，必须在该事务开始前进行设置，并在该事务结束后进行复位。我们不提倡在事务的中途对事务隔离级别进行更改，因为这将立即触发 commit 方法的调用，使在此之前所作的任何更改变成永久性的。  </p>
				<br />
				<br />
				<p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=630439</p>
		</div>
<img src ="http://www.blogjava.net/iKingQu/aggbug/36758.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iKingQu/" target="_blank">風向逆轉 - 就要爪哇</a> 2006-03-22 03:27 <a href="http://www.blogjava.net/iKingQu/articles/36758.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[收藏]Java程序员的存储过程</title><link>http://www.blogjava.net/iKingQu/articles/36757.html</link><dc:creator>風向逆轉 - 就要爪哇</dc:creator><author>風向逆轉 - 就要爪哇</author><pubDate>Tue, 21 Mar 2006 19:26:00 GMT</pubDate><guid>http://www.blogjava.net/iKingQu/articles/36757.html</guid><wfw:comment>http://www.blogjava.net/iKingQu/comments/36757.html</wfw:comment><comments>http://www.blogjava.net/iKingQu/articles/36757.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/iKingQu/comments/commentRss/36757.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iKingQu/services/trackbacks/36757.html</trackback:ping><description><![CDATA[
		<div class="postText">
				<p>
						<span class="Title">Java程序员的存储过程 <br /></span>--------------------------------------------------------------------------------</p>
				<p>原文：<a href="http://www.onjava.com/pub/a/onjava/2003/08/13/stored_procedures.html">http://www.onjava.com/pub/a/onjava/2003/08/13/stored_procedures.html</a><br />by Nic Ferrier </p>
				<p>本文阐述了怎么使用DBMS存储过程。我阐述了使用存储过程的基本的和高级特性，比如返回ResultSet。本文假设你对DBMS和JDBC已经非常熟悉，也假设你能够毫无障碍地阅读其它语言写成的代码（即不是Java的语言），但是，并不要求你有任何存储过程的编程经历。 <br />存储过程是指保存在数据库并在数据库端执行的程序。你可以使用特殊的语法在Java类中调用存储过程。在调用时，存储过程的名称及指定的参数通过JDBC连接发送给DBMS，执行存储过程并通过连接（如果有）返回结果。 <br />使用存储过程拥有和使用基于EJB或CORBA这样的应用服务器一样的好处。区别是存储过程可以从很多流行的DBMS中免费使用，而应用服务器大都非常昂贵。这并不只是许可证费用的问题。使用应用服务器所需要花费的管理、编写代码的费用，以及客户程序所增加的复杂性，都可以通过DBMS中的存储过程所整个地替代。 <br />你可以使用Java，Python，Perl或C编写存储过程，但是通常使用你的DBMS所指定的特定语言。Oracle使用PL/SQL，PostgreSQL使用pl/pgsql，DB2使用Procedural SQL。这些语言都非常相似。在它们之间移植存储过程并不比在Sun的EJB规范不同实现版本之间移植Session Bean困难。并且，存储过程是为嵌入SQL所设计，这使得它们比Java或C等语言更加友好地方式表达数据库的机制。 <br />因为存储过程运行在DBMS自身，这可以帮助减少应用程序中的等待时间。不是在Java代码中执行4个或5个SQL语句，而只需要在服务器端执行1个存储过程。网络上的数据往返次数的减少可以戏剧性地优化性能。 </p>
				<p>使用存储过程 </p>
				<p>简单的老的JDBC通过CallableStatement类支持存储过程的调用。该类实际上是PreparedStatement的一个子类。假设我们有一个poets数据库。数据库中有一个设置诗人逝世年龄的存储过程。下面是对老酒鬼Dylan Thomas（old soak Dylan Thomas，不指定是否有关典故、文化，请批评指正。译注）进行调用的详细代码： </p>
				<p>
						<font color="#003366">try<br />{<br />    int age = 39;<br />    String poetName = "dylan thomas";<br />    CallableStatement proc =<br />        connection.prepareCall("{ call set_death_age(?, ?) }");<br />    proc.setString(1, poetName);<br />    proc.setInt(2, age);<br />    cs.execute();<br />}<br />catch (SQLException e)<br />{<br />    // ....<br />}</font>
				</p>
				<p>传给prepareCall方法的字串是存储过程调用的书写规范。它指定了存储过程的名称，？代表了你需要指定的参数。 <br />和JDBC集成是存储过程的一个很大的便利：为了从应用中调用存储过程，不需要存根（stub）类或者配置文件，除了你的DBMS的JDBC驱动程序外什么也不需要。 <br />当这段代码执行时，数据库的存储过程就被调用。我们没有去获取结果，因为该存储过程并不返回结果。执行成功或失败将通过例外得知。失败可能意味着调用存储过程时的失败（比如提供的一个参数的类型不正确），或者一个应用程序的失败（比如抛出一个例外指示在poets数据库中并不存在“Dylan Thomas”） </p>
				<p>结合SQL操作与存储过程 </p>
				<p>映射Java对象到SQL表中的行相当简单，但是通常需要执行几个SQL语句；可能是一个SELECT查找ID，然后一个INSERT插入指定ID的数据。在高度规格化（符合更高的范式，译注）的数据库模式中，可能需要多个表的更新，因此需要更多的语句。Java代码会很快地膨胀，每一个语句的网络开销也迅速增加。 <br />将这些SQL语句转移到一个存储过程中将大大简化代码，仅涉及一次网络调用。所有关联的SQL操作都可以在数据库内部发生。并且，存储过程语言，例如PL/SQL，允许使用SQL语法，这比Java代码更加自然。下面是我们早期的存储过程，使用Oracle的PL/SQL语言编写： </p>
				<p>
						<font color="#003366">create procedure set_death_age(poet VARCHAR2, poet_age NUMBER)<br />    poet_id NUMBER;<br />begin<br />  SELECT id INTO poet_id FROM poets WHERE name = poet;<br />  INSERT INTO deaths (mort_id, age) VALUES (poet_id, poet_age);<br />end set_death_age;</font>
				</p>
				<p>很独特？不。我打赌你一定期待看到一个poets表上的UPDATE。这也暗示了使用存储过程实现是多么容易的一件事情。set_death_age几乎可以肯定是一个很烂的实现。我们应该在poets表中添加一列来存储逝世年龄。Java代码中并不关心数据库模式是怎么实现的，因为它仅调用存储过程。我们以后可以改变数据库模式以提高性能，但是我们不必修改我们代码。 <br />下面是调用上面存储过程的Java代码： </p>
				<p>
						<font color="#003366">public static void setDeathAge(Poet dyingBard, int age)<br />    throws SQLException<br />{<br />   Connection con = null;<br />   CallableStatement proc = null;<br /><br />   try<br />   {<br />      con  = connectionPool.getConnection();<br />      proc = con.prepareCall("{ call set_death_age(?, ?) }");<br />      proc.setString(1, dyingBard.getName());<br />      proc.setInt(2, age);<br />      proc.execute();<br />   }<br />   finally<br />   {<br />      try<br />      {<br />         proc.close();<br />      }<br />      catch (SQLException e) {}<br />      con.close();<br />   }<br />}</font>
				</p>
				<p>为了确保可维护性，建议使用像这儿这样的static方法。这也使得调用存储过程的代码集中在一个简单的模版代码中。如果你用到许多存储过程，就会发现仅需要拷贝、粘贴就可以创建新的方法。因为代码的模版化，甚至也可以通过脚本自动生产调用存储过程的代码。 </p>
				<p>Functions </p>
				<p>存储过程可以有返回值，所以CallableStatement类有类似getResultSet这样的方法来获取返回值。当存储过程返回一个值时，你必须使用registerOutParameter方法告诉JDBC驱动器该值的SQL类型是什么。你也必须调整存储过程调用来指示该过程返回一个值。 <br />下面接着上面的例子。这次我们查询Dylan Thomas逝世时的年龄。这次的存储过程使用PostgreSQL的pl/pgsql： </p>
				<p>
						<font color="#003366">create function snuffed_it_when (VARCHAR) returns integer '<br />declare<br />    poet_id NUMBER;<br />    poet_age NUMBER;<br />begin<br />    -- first get the id associated with the poet.<br />    SELECT id INTO poet_id FROM poets WHERE name = $1;<br />    -- get and return the age.<br />    SELECT age INTO poet_age FROM deaths WHERE mort_id = poet_id;<br />    return age;<br />end;<br />' language 'pl/pgsql';</font>
				</p>
				<p>另外，注意pl/pgsql参数名通过Unix和DOS脚本的$n语法引用。同时，也注意嵌入的注释，这是和Java代码相比的另一个优越性。在Java中写这样的注释当然是可以的，但是看起来很凌乱，并且和SQL语句脱节，必须嵌入到Java String中。 <br />下面是调用这个存储过程的Java代码： </p>
				<p>
						<font color="#003366">connection.setAutoCommit(false);<br />CallableStatement proc =<br />    connection.prepareCall("{ ? = call snuffed_it_when(?) }");<br />proc.registerOutParameter(1, Types.INTEGER);<br />proc.setString(2, poetName);<br />cs.execute();<br />int age = proc.getInt(2);</font>
				</p>
				<p>如果指定了错误的返回值类型会怎样？那么，当调用存储过程时将抛出一个RuntimeException，正如你在ResultSet操作中使用了一个错误的类型所碰到的一样。 </p>
				<p>复杂的返回值 </p>
				<p>关于存储过程的知识，很多人好像就熟悉我们所讨论的这些。如果这是存储过程的全部功能，那么存储过程就不是其它远程执行机制的替换方案了。存储过程的功能比这强大得多。 <br />当你执行一个SQL查询时，DBMS创建一个叫做cursor（游标）的数据库对象，用于在返回结果中迭代每一行。ResultSet是当前时间点的游标的一个表示。这就是为什么没有缓存或者特定数据库的支持，你只能在ResultSet中向前移动。 <br />某些DBMS允许从存储过程中返回游标的一个引用。JDBC并不支持这个功能，但是Oracle、PostgreSQL和DB2的JDBC驱动器都支持在ResultSet上打开到游标的指针（pointer）。 <br />设想列出所有没有活到退休年龄的诗人，下面是完成这个功能的存储过程，返回一个打开的游标，同样也使用PostgreSQL的pl/pgsql语言： </p>
				<p>
						<font color="#003366">create procedure list_early_deaths () return refcursor as '<br />declare<br />    toesup refcursor;<br />begin<br />    open toesup for<br />        SELECT poets.name, deaths.age<br />        FROM poets, deaths<br />        -- all entries in deaths are for poets.<br />        -- but the table might become generic.<br />        WHERE poets.id = deaths.mort_id<br />            AND deaths.age &lt; 60;<br />    return toesup;<br />end;<br />' language 'plpgsql';</font>
				</p>
				<p>下面是调用该存储过程的Java方法，将结果输出到PrintWriter： <br />PrintWriter: </p>
				<p>
						<font color="#003366">static void sendEarlyDeaths(PrintWriter out)<br />{<br />    Connection con = null;<br />    CallableStatement toesUp = null;<br />    try<br />    {<br />        con = ConnectionPool.getConnection();<br /><br />        // PostgreSQL needs a transaction to do this...<br />        con.setAutoCommit(false);<br /><br />        // Setup the call.<br />        CallableStatement toesUp<br />            = connection.prepareCall("{ ? = call list_early_deaths () }");<br />        toesUp.registerOutParameter(1, Types.OTHER);<br />        getResults.execute();<br /><br />        ResultSet rs = (ResultSet) getResults.getObject(1);<br />        while (rs.next())<br />        {<br />            String name = rs.getString(1);<br />            int age = rs.getInt(2);<br />            out.println(name + " was " + age + " years old.");<br />        }<br />        rs.close();<br />    }<br />    catch (SQLException e)<br />    {<br />        // We should protect these calls.<br />        toesUp.close();<br />        con.close();<br />    }<br />}</font>
				</p>
				<p>因为JDBC并不直接支持从存储过程中返回游标，我们使用Types.OTHER来指示存储过程的返回类型，然后调用getObject()方法并对返回值进行强制类型转换。 <br />这个调用存储过程的Java方法是mapping的一个好例子。Mapping是对一个集上的操作进行抽象的方法。不是在这个过程上返回一个集，我们可以把操作传送进去执行。本例中，操作就是把ResultSet打印到一个输出流。这是一个值得举例的很常用的例子，下面是调用同一个存储过程的另外一个方法实现： </p>
				<p>
						<font color="#003366">public class ProcessPoetDeaths<br />{<br />    public abstract void sendDeath(String name, int age);<br />}<br /><br />static void mapEarlyDeaths(ProcessPoetDeaths mapper)<br />{<br />    Connection con = null;<br />    CallableStatement toesUp = null;<br />    try<br />    {<br />        con = ConnectionPool.getConnection();<br />        con.setAutoCommit(false);<br /><br />        CallableStatement toesUp<br />            = connection.prepareCall("{ ? = call list_early_deaths () }");<br />        toesUp.registerOutParameter(1, Types.OTHER);<br />        getResults.execute();<br /><br />        ResultSet rs = (ResultSet) getResults.getObject(1);<br />        while (rs.next())<br />        {<br />            String name = rs.getString(1);<br />            int age = rs.getInt(2);<br />            mapper.sendDeath(name, age);<br />        }<br />        rs.close();<br />    }<br />    catch (SQLException e)<br />    {<br />        // We should protect these calls.<br />        toesUp.close();<br />        con.close();<br />    }<br />}</font>
				</p>
				<p>这允许在ResultSet数据上执行任意的处理，而不需要改变或者复制获取ResultSet的方法： </p>
				<p>
						<font color="#003366">static void sendEarlyDeaths(final PrintWriter out)<br />{<br />    ProcessPoetDeaths myMapper = new ProcessPoetDeaths()<br />    {<br />        public void sendDeath(String name, int age)<br />        {<br />            out.println(name + " was " + age + " years old.");<br />        }<br />    };<br />    mapEarlyDeaths(myMapper);<br />}</font>
				</p>
				<p>这个方法使用ProcessPoetDeaths的一个匿名实例调用mapEarlyDeaths。该实例拥有sendDeath方法的一个实现，和我们上面的例子一样的方式把结果写入到输出流。当然，这个技巧并不是存储过程特有的，但是和存储过程中返回的ResultSet结合使用，是一个非常强大的工具。 </p>
				<p>结论 </p>
				<p>存储过程可以帮助你在代码中分离逻辑，这基本上总是有益的。这个分离的好处有： <br />&amp;#8226; 快速创建应用，使用和应用一起改变和改善的数据库模式。  <br />&amp;#8226; 数据库模式可以在以后改变而不影响Java对象，当我们完成应用后，可以重新设计更好的模式。 <br />&amp;#8226; 存储过程通过更好的SQL嵌入使得复杂的SQL更容易理解。 <br />&amp;#8226; 编写存储过程比在Java中编写嵌入的SQL拥有更好的工具－－大部分编辑器都提供语法高亮！ <br />&amp;#8226; 存储过程可以在任何SQL命令行中测试，这使得调试更加容易。 </p>
				<p>并不是所有的数据库都支持存储过程，但是存在许多很棒的实现，包括免费/开源的和非免费的，所以移植并不是一个问题。Oracle、PostgreSQL和DB2都有类似的存储过程语言，并且有在线的社区很好地支持。 <br />存储过程工具很多，有像TOAD或TORA这样的编辑器、调试器和IDE，提供了编写、维护PL/SQL或pl/pgsql的强大的环境。 <br />存储过程确实增加了你的代码的开销，但是它们和大多数的应用服务器相比，开销小得多。如果你的代码复杂到需要使用DBMS，我建议整个采用存储过程的方式。 </p>
				<p>资源 </p>
				<p>&amp;#8226; JDBC specification  <br />&amp;#8226; PostgreSQL  <br />&amp;#8226; Oracle Corporation's Oracle database server  <br />&amp;#8226; IBM's DB2 database server  </p>
				<p>作者简介：Nic Ferrier 是Web应用方面的独立软件顾问。  </p>
				<br />
				<br />
				<p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=629847</p>
		</div>
<img src ="http://www.blogjava.net/iKingQu/aggbug/36757.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iKingQu/" target="_blank">風向逆轉 - 就要爪哇</a> 2006-03-22 03:26 <a href="http://www.blogjava.net/iKingQu/articles/36757.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[收藏]谈谈JDBC接口技术</title><link>http://www.blogjava.net/iKingQu/articles/36756.html</link><dc:creator>風向逆轉 - 就要爪哇</dc:creator><author>風向逆轉 - 就要爪哇</author><pubDate>Tue, 21 Mar 2006 19:24:00 GMT</pubDate><guid>http://www.blogjava.net/iKingQu/articles/36756.html</guid><wfw:comment>http://www.blogjava.net/iKingQu/comments/36756.html</wfw:comment><comments>http://www.blogjava.net/iKingQu/articles/36756.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/iKingQu/comments/commentRss/36756.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iKingQu/services/trackbacks/36756.html</trackback:ping><description><![CDATA[
		<div class="postText">
				<p>
						<span class="Title">谈谈JDBC接口技术</span>
						<br />--------------------------------------------------------------------------------<br /> <br />   JDBC是一种可用于执行SQL语句的JavaAPI（ApplicationProgrammingInterface应用程序设计接口）。它由一些Java语言编写的类和界面组成。JDBC为数据库应用开发人员、数据库前台工具开发人员提供了一种标准的应用程序设计接口，使开发人员可以用纯Java语言编写完整的数据库应用程序。  </p>
				<p>    一、ODBC到JDBC的发展历程  </p>
				<p>    说到JDBC，很容易让人联想到另一个十分熟悉的字眼“ODBC”。它们之间有没有联系呢？如果有，那么它们之间又是怎样的关系呢？  </p>
				<p>    ODBC是OpenDatabaseConnectivity的英文简写。它是一种用来在相关或不相关的数据库管理系统（DBMS）中存取数据的，用C语言实现的，标准应用程序数据接口。通过ODBCAPI，应用程序可以存取保存在多种不同数据库管理系统（DBMS）中的数据，而不论每个DBMS使用了何种数据存储格式和编程接口。  </p>
				<p>    1．ODBC的结构模型  <br />    ODBC的结构包括四个主要部分：应用程序接口、驱动器管理器、数据库驱动器和数据源。  <br />    应用程序接口：屏蔽不同的ODBC数据库驱动器之间函数调用的差别，为用户提供统一的SQL编程接口。  <br />    驱动器管理器：为应用程序装载数据库驱动器。  <br />    数据库驱动器：实现ODBC的函数调用，提供对特定数据源的SQL请求。如果需要，数据库驱动器将修改应用程序的请求，使得请求符合相关的DBMS所支持的文法。  <br />    数据源：由用户想要存取的数据以及与它相关的操作系统、DBMS和用于访问DBMS的网络平台组成。  </p>
				<p>    虽然ODBC驱动器管理器的主要目的是加载数据库驱动器，以便ODBC函数调用，但是数据库驱动器本身也执行ODBC函数调用，并与数据库相互配合。因此当应用系统发出调用与数据源进行连接时，数据库驱动器能管理通信协议。当建立起与数据源的连接时，数据库驱动器便能处理应用系统向DBMS发出的请求，对分析或发自数据源的设计进行必要的翻译，并将结果返回给应用系统。  </p>
				<p>    2．JDBC的诞生  </p>
				<p>    自从Java语言于1995年5月正式公布以来，Java风靡全球。出现大量的用java语言编写的程序，其中也包括数据库应用程序。由于没有一个Java语言的API，编程人员不得不在Java程序中加入C语言的ODBC函数调用。这就使很多Java的优秀特性无法充分发挥，比如平台无关性、面向对象特性等。随着越来越多的编程人员对Java语言的日益喜爱，越来越多的公司在Java程序开发上投入的精力日益增加，对java语言接口的访问数据库的API的要求越来越强烈。也由于ODBC的有其不足之处，比如它并不容易使用，没有面向对象的特性等等，SUN公司决定开发一Java语言为接口的数据库应用程序开发接口。在JDK1．x版本中，JDBC只是一个可选部件，到了JDK1．1公布时，SQL类包（也就是JDBCAPI）就成为Java语言的标准部件。  </p>
				<p>    二、JDBC技术概述  </p>
				<p>    JDBC是一种可用于执行SQL语句的JavaAPI（ApplicationProgrammingInterface，应用程序设计接口）。它由一些Java语言写的类、界面组成。JDBC给数据库应用开发人员、数据库前台工具开发人员提供了一种标准的应用程序设计接口，使开发人员可以用纯Java语言编写完整的数据库应用程序。  </p>
				<p>    通过使用JDBC，开发人员可以很方便地将SQL语句传送给几乎任何一种数据库。也就是说，开发人员可以不必写一个程序访问Sybase，写另一个程序访问Oracle，再写一个程序访问Microsoft的SQLServer。用JDBC写的程序能够自动地将SQL语句传送给相应的数据库管理系统（DBMS）。不但如此，使用Java编写的应用程序可以在任何支持Java的平台上运行，不必在不同的平台上编写不同的应用。Java和JDBC的结合可以让开发人员在开发数据库应用时真正实现“WriteOnce，RunEverywhere！”  </p>
				<p>    Java具有健壮、安全、易用等特性，而且支持自动网上下载，本质上是一种很好的数据库应用的编程语言。它所需要的是Java应用如何同各种各样的数据库连接，JDBC正是实现这种连接的关键。  </p>
				<p>    JDBC扩展了Java的能力，如使用Java和JDBCAPI就可以公布一个Web页，页中带有能访问远端数据库的Ap?plet。或者企业可以通过JDBC让全部的职工（他们可以使用不同的操作系统，如Windwos，Machintosh和UNIX）在In?tranet上连接到几个全球数据库上，而这几个全球数据库可以是不相同的。随着越来越多的程序开发人员使用Java语言，对Java访问数据库易操作性的需求越来越强烈。  </p>
				<p>    MIS管理人员喜欢Java和JDBC，因为这样可以更容易经济地公布信息。各种已经安装在数据库中的事务处理都将继续正常运行，甚至这些事务处理是存储在不同的数据库管理系统中；而对新的数据库应用来说，开发时间将缩短，安装和版本升级将大大简化。程序员可以编写或改写一个程序，然后将它放在服务器上，而每个用户都可以访问服务器得到最新的版本。对于信息服务行业，Java和JDBC提供了一种很好的向外界用户更新信息的方法。  </p>
				<p>    1．JDBC的任务  </p>
				<p>    简单地说，JDBC能完成下列三件事：  <br />    1）同一个数据库建立连接；  <br />    2）向数据库发送SQL语句；  <br />    3）处理数据库返回的结果。  </p>
				<p>    2．JDBC一种底层的API  </p>
				<p>    JDBC是一种底层API，这意味着它将直接调用SQL命令。JDBC完全胜任这个任务，而且比其他数据库互联更加容易实现。同时它也是构造高层API和数据库开发工具的基础。高层API和数据库开发工具应该是用户界面更加友好，使用更加方便，更易于理解的。但所有这样的API将最终被翻译为象JDBC这样的底层API。目前两种基于JDBC的高层API正处在开发阶段。  </p>
				<p>    1）SQL语言嵌入Java的预处理器。虽然DBMS已经实现了SQL查询，但JDBC要求SQL语句被当作字符串参数传送给Java程序。而嵌入式SQL预处理器允许程序员将SQL语句混用：Java变量可以在SQL语句中使用，来接收或提供数值。然后SQL的预处理器将把这种Java／SQL混用的程序翻译成带有JDBCAPI的Java程序。  </p>
				<p>    2）实现从关系数据库到Java类的直接映射。Javasoft和其他公司已经宣布要实现这一技术。在这种“对象／关系”映射中，表的每一行都将变成这类的一个实例，每一列的值对应实例的一个属性。程序员可以直接操作Java的对象；而存取所需要的SQL调用将在内部直接产生。还可以实现更加复杂的映射，比如多张表的行在一个Java的类中实现。  </p>
				<p>    随着大家对JDBC兴趣的不断浓厚，越来越多的开发人员已经开始利用JDBC为基础的工具进行开发。这使开发工作变得容易。同时，程序员也正在开发对最终用户来说访问数据库更加容易的应用程序。  </p>
				<p>    3．JDBC和ODBC及其他API的比较  </p>
				<p>    到目前为止，微软的ODBC可能是用得最广泛的访问关系数据库的API。它提供了连接几乎任何一种平台、任何一种数据库的能力。那么，为什么不直接从Java中直接使用ODBC呢？  </p>
				<p>    回答是可以从Java中使用ODBC，但最好在JDBC的协助下，用JDBC－ODBC桥接器实现。那么，为什么需要JDBC呢？要回答这个问题，有这么几个方面：  </p>
				<p>    1）ODBC并不适合在Java中直接使用。ODBC是一个C语言实现的API，从Java程序调用本地的C程序会带来一系列类似安全性、完整性、健壮性的缺点。  </p>
				<p>    2）其次，完全精确地实现从C代码ODBC到JavaAPI写的ODBC的翻译也并不令人满意。比如，Java没有指针，而ODBC中大量地使用了指针，包括极易出错的空指针“void＊”。因此，对Java程序员来说，把JDBC设想成将ODBC转换成面向对象的API是很自然的。  </p>
				<p>    3）ODBC并不容易学习，它将简单特性和复杂特性混杂在一起，甚至对非常简单的查询都有复杂的选项。而JDBC刚好相反，它保持了简单事物的简单性，但又允许复杂的特性。  </p>
				<p>    4）JDBC这样的JavaAPI对于纯Java方案来说是必须的。当使用ODBC时，人们必须在每一台客户机上安装ODBC驱动器和驱动管理器。如果JDBC驱动器是完全用Java语言实现的话，那么JDBC的代码就可以自动的下载和安装，并保证其安全性，而且，这将适应任何Java平台，从网络计算机NC到大型主机Mainframe。  </p>
				<p>    总而言之，JDBCAPI是能体现SQL最基本抽象概念的、最直接的Java接口。它建构在ODBC的基础上，因此，熟悉ODBC的程序员将发现学习JDBC非常容易。JDBC保持了ODBC的基本设计特征。实际上，这两种接口都是基于X／OPENSQL的调用级接口（CLI）。它们的最大的不同是JDBC是基于Java的风格和优点，并强化了Java的风格和优点。  </p>
				<p>    最近，微软又推出了除了ODBC以外的新的API，如RDO，ADO和OLEDB。这些API事实上在很多方面上同JDBC一样朝着相同的方向努力，也就是努力成为一个面向对象的，基于ODBC的类接口。然而，这些接口目前并不能代替ODBC，尤其在ODBC驱动器已经在市场完全形成的时候，更重要的是它们只是ODBC的“漂亮的包装”。  </p>
				<p>    4．JDBC两层模型和三层模型  </p>
				<p>    JDBC支持两层模型，也支持三层模型访问数据库。 两层模型中，一个java Appple或者一个JA－va应用直接同数据库连接。这就需要能直接被访问的数据库进行连接的JDBC驱动器。用户的SQL语句被传送给数据库，而这些语句执行的结果将被传回给用户。数据库可以在同一机器上，也可以另一机器上通过网络进行连接。这被称为“Client/Server”结构，用户的计算机作为Client,运行数据库的计算机作为Server。这个网络可是intranet，比如连接全体雇员的企业内部网，当然也可以是internet。  </p>
				<p>    在三层模型中，命令将被发送到服务的“中间层”，而“中间层”将SQL语句发送到数据库。数据库处理SQL语句并将结果返回“中间层”，然后“中间层”将它们 返回用户。MIS管理员将发现三层模型很有吸引力，因为“中间层”可以进行对访问的控制并协同数据库的更新，另一个优势就是如果有一个“中间层”用户就可以使用一个易用的高层的API，这个API可以由“中间层”进行转换，转换成底层的调用。而且，在许多情况下，三层模型可以提供更好的性能。  </p>
				<p>    到目前为止，“中间层”通常还是用C或C++实现，以保证其高性能。但随着优化编译器的引入，将java的字节码转换成高效的机器码，用java来实现“中间层”将越来越实际。而JDBC是允许从一个java“中间层”访问数据库的关键。 </p>
				<br />
				<br />
				<p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=629840</p>
		</div>
<img src ="http://www.blogjava.net/iKingQu/aggbug/36756.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iKingQu/" target="_blank">風向逆轉 - 就要爪哇</a> 2006-03-22 03:24 <a href="http://www.blogjava.net/iKingQu/articles/36756.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[收藏]JDBC 4.0规范之目标</title><link>http://www.blogjava.net/iKingQu/articles/36755.html</link><dc:creator>風向逆轉 - 就要爪哇</dc:creator><author>風向逆轉 - 就要爪哇</author><pubDate>Tue, 21 Mar 2006 19:23:00 GMT</pubDate><guid>http://www.blogjava.net/iKingQu/articles/36755.html</guid><wfw:comment>http://www.blogjava.net/iKingQu/comments/36755.html</wfw:comment><comments>http://www.blogjava.net/iKingQu/articles/36755.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/iKingQu/comments/commentRss/36755.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iKingQu/services/trackbacks/36755.html</trackback:ping><description><![CDATA[
		<div class="postText">
				<p>
						<span class="Title">JDBC 4.0规范之目标</span>
						<br />--------------------------------------------------------------------------------<br /> <br />　　历史</p>
				<p>　　JDBC API是一种成熟的技术，最早发布是1997年1月。在最初的版本中，JDBC API着重提供一个对SQL数据库的基本调用级接口。之后，JDBC 2.1规范和2.0可选包规范拓宽了API的范围。包括支持更高级应用和管理使用JDBC API来增强其应用的应用服务所需的各项特征。</p>
				<p>　　JDBC 3.0规范以填补较小范围内的功能缺失为目标。对于JDBC 4.0，我们的目标有两个：提高所有开发者在JAVA平台使用SQL开发的易用性。第二，提供企业级特性的JDBC工具集和API来管理JDBC资源。 <br />　　目标概述</p>
				<p>　　下面列出了一般的JDBC API和JDBC 4.0 API的目标和设计原理：</p>
				<p>　　1.适合J2EE和J2SE平台</p>
				<p>　　JDBC API是JAVA平台的重要技术。JDBC 4.0 API应遵循JAVA 2 企业版和JAVA 2 标准版平台的总体方向。另外，最近开发的JAVA 5.0平台已经展示出一系列新的特性和语言的改进，并在本规范中广泛使用。</p>
				<p>　　2.兼容SQL:2003</p>
				<p>　　JDBC API提供用JAVA编程语言编写标准SQL来对应用进行程序级访问能力。JDBC 3.0致力于确保其可以支持可广泛支持工业的具有SQL:99特征的子集。对于JDBC 4.0也一样，支持SQL:2003是本规范的一个主要组成部分。我们期望在不久的将来可以实现。</p>
				<p>　　3.巩固以前的规范</p>
				<p>　　本文档把4个以前的JDBC规范组织成一个单一的JDBC API规范。</p>
				<p>　　4.提供中立于开发商的一般访问特性</p>
				<p>　　JDBC API致力于提供支持针对不同开发商应用的高带宽的一般访问特征。其目标是提供与原生应用可以达到的同级别的访问特性。然而，本API必须足够通用和灵活以适应大范围的实施。</p>
				<p>　　5.关注于SQL</p>
				<p>　　JDBC API一直关注于用JAVA编程语言访问相关数据。这个目标曾在JDBC 3.0 API规范中说明，在本规范中仍是一个主要原则。提供API和工具来改进开发难度，并继续集中于在JAVA平台开发基于SQL的软件的需要。与以前的规范相似，本规范也不阻止与其它技术进行交互，如XML，CORBA和非关系型数据。</p>
				<p>　　6.提供基础数据和更高级别的API</p>
				<p>　　JDBC API提供标准API访各种数据源或旧系统。实施的差异使通过JDBC API抽象透明化。这使其成为对想开发可移动工具和应用的工具开发商来说，一个有价值的目标平台。</p>
				<p>　　由于它是一个用JAVA编程语言对SQL的“调用”级接口，所以JDBC API也适用于更高级别应用的底层，如EJB 3.0容器管理的持久性，SQLJ和JDBC的RowSet实现。</p>
				<p>　　7.保持简单</p>
				<p>　　JDBC API意欲成为一种使用简单、直接的接口。在之上可以构建更多复杂的实体。这个目标通过定义大量紧凑、单一目的方法来代替少数带有控制标识参数的复杂、多目的的方法来实现。</p>
				<p>　　8.增强可靠性、可用行和可测性</p>
				<p>　　可靠性、可用行和可测性是J2EE和J2SE平台的主题，也是未来JAVA平台的主题。JDBC 4.0 API严格按照以上目标进行。它扩展支持了一些领域，包括资源管理、对逻辑连接预备声明的复用和错误处理。</p>
				<p>　　9.支持对已有应用和驱动的向后兼容</p>
				<p>　　使用已有JDBC技术的驱动和应用必须能够在支持JDBC 4.0 API的JAVA虚拟机上继续工作。那些只使用更早版本中定义的JDBC API（不包括在JDBC 2.0中已废除的）的应用，应该不需要修改就可以继续运行。已有的应用应该可以直接迁移到JDBC 4.0技术。</p>
				<p>　　10.与JDBC RowSet工具紧密联系</p>
				<p>　　J2SE 5.0包含一个标准JDBC RowSet工具（在《JDBC RowSet工具集》中说明（JSR-114））。本规范会提供一个工具集包括工具类级别和元数据语言级别的工具。它允许开发者轻易的把使用JDBC技术的应用迁移到JDBC RowSet模型。该模型可以断开数据源访问连接，另外能够管理来自于XML驻留点的关系数据存储。</p>
				<p>　　11.允许对连接器的向前兼容</p>
				<p>　　连接器构架定义了一个标准方法来对资源适配器进行打包和布署。它允许一个J2EE容器整合它与外部资源的连接、处理和安全管理。JDBC 4.0 API提供JDBC驱动到连接器架构的迁移路径。对那些产品中使用JDBC技术的开发商来说，应可以转向对连接器API的实现。希望这些实现会重新包装已有数据源的实现。这样他们可以对连接器框架进行复用。 </p>
				<p>　　12.清晰的列明需求</p>
				<p>　　遵从JDBC要求的需求，要明确和易于识别。JDBC 4.0规范和API文档（Javadoc）会明晰什么特性是需要的，什么特性是可选的。</p>
				<br />
				<br />
				<p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=629584</p>
		</div>
<img src ="http://www.blogjava.net/iKingQu/aggbug/36755.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/iKingQu/" target="_blank">風向逆轉 - 就要爪哇</a> 2006-03-22 03:23 <a href="http://www.blogjava.net/iKingQu/articles/36755.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[收藏]JDBC连接Oracle数据库常见问题及解决方法</title><link>http://www.blogjava.net/iKingQu/articles/36519.html</link><dc:creator>風向逆轉 - 就要爪哇</dc:creator><author>風向逆轉 - 就要爪哇</author><pubDate>Mon, 20 Mar 2006 16:27:00 GMT</pubDate><guid>http://www.blogjava.net/iKingQu/articles/36519.html</guid><wfw:comment>http://www.blogjava.net/iKingQu/comments/36519.html</wfw:comment><comments>http://www.blogjava.net/iKingQu/articles/36519.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/iKingQu/comments/commentRss/36519.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/iKingQu/services/trackbacks/36519.html</trackback:ping><description><![CDATA[
		<ol>
				<li>Jbuilder正确连接 oracle 9i需要注意的几个问题 
<ul><li>oracle8以上的应该都使用classes12.jar文件作为jdbc驱动； 
</li><li>正确设置windows的classpath和jbuilder中的enterprise setup 、configure libraries，将casses12.jar路径正确添加到上述需要设置的地方；<strong></strong></li><li>进入databas