??xml version="1.0" encoding="utf-8" standalone="yes"?>
首先,Z使一个系l更?最重要的部分就是基设计,不过有些东西是现有情况下无法逾越?比如说系l常见的瓉.
我所能想到的:
1:盘寻道能力,以高速硬?7200?U?,理论上每U寻?200?q是没有办法改变?优化的方法是----用多个硬?或者把数据分散存储.
2:盘的读写速度,q个速度非常的快(限于本h的知识所?只知道在每秒几十甚至上百MB).q个更容易解?-可以从多个硬盘上q行d.
3:cpu.cpu处理内存中的数据,当有相对内存较小的表?q是最常见的限制因?
4:内存的限?当cpu需要超出适合cpu~存的数据时,~存的带宽就成了内存的一个瓶?--不过现在内存大的惊h,一般不会出现这个问?
W二?
(本h使用的是学校|站的linuxq_(Linux ADVX.Mandrakesoft.com 2.4.3-19mdk ))
1:调节服务器参?
用shell>mysqld-helpq个命o声厂一张所有mysql选项和可配置变量的表.输出以下信息:
possible variables for option--set-variable(-o) are:
back_log current value:5 //要求mysql能有的连接数?back_log指出在mysql暂停接受q接的时间内有多个q接h可以被存在堆栈中
connect_timeout current value:5 //mysql服务器在用bad handshake(不好译)应答前等待一个连接的旉
delayed_insert_timeout current value:200 //一个insert delayed在终止前{待insert的时?
delayed_insert_limit current value:50 //insert delayed处理器将查是否有Mselect语句未执?如果?l箋前执行这些语?
delayed_queue_size current value:1000 //为insert delayed分配多大的队
flush_time current value:0 //如果被设|ؓ?,那么每个flush_time 旉,所有表都被关闭
interactive_timeout current value:28800 //服务器在关上它之前在z交互连接上{待的时?
join_buffer_size current value:131072 //用与全部q接的缓冲区大小
key_buffer_size current value:1048540 //用语索引块的~冲区的大小,增加它可以更好的处理索引
lower_case_table_names current value:0 //
long_query_time current value:10 //如果一个查询所用时间大于此旉,slow_queried计数增?
max_allowed_packet current value:1048576 //一个包的大?
max_connections current value:300 //允许同时q接的数?
max_connect_errors current value:10 //如果有多于该数量的中断连?阻止进一步的q接,可以用flush hosts来解?
max_delayed_threads current value:15 //可以启动的处理insert delayed的数?
max_heap_table_size current value:16777216 //
max_join_size current value:4294967295 //允许d的连接的数量
max_sort_length current value:1024 //在排序blob或者text时用的字节数量
max_tmp_tables current value:32 //一个连接同时打开的时表的数?
max_write_lock_count current value:4294967295 //指定一个?通常很小)来启动mysqld,使得在一定数量的write锁定之后出现read锁定
net_buffer_length current value:16384 //通信~冲区的大小--在查询时被重|ؓ该大?
query_buffer_size current value:0 //查询时缓冲区大小
record_buffer current value:131072 //每个序扫描的连接ؓ其扫描的每张表分配的~冲区的大小
sort_buffer current value:2097116 //每个q行排序的连接分配的~冲区的大小
table_cache current value:64 //为所有连接打开的表的数?
thread_concurrency current value:10 //
tmp_table_size current value:1048576 //临时表的大小
thread_stack current value:131072 //每个U程的大?
wait_timeout current value:28800 //服务器在关闭?之前的一个连接上{待的时?
Ҏ(gu)自己的需要配|以上信息会对你帮助.
W三:
1:如果你在一个数据库中创建大量的?那么执行打开,关闭Q创??的操作就会很?
2:mysql使用内存
a: 关键字缓存区(key_buffer_size)由所有线E共?
b: 每个q接使用一些特定的U程I间.一个栈(默认?4k,变量thread_stack),一个连接缓冲区(变量net_buffer_length)和一个结果缓冲区(net_buffer_length).特定情况?q接~冲区和l果~冲动态扩大到max_allowed_packet.
c:所有线E共享一个基存储?
d:没有内存影射
e:每个做顺序扫描的h分配一个读~冲?record_buffer)
f:所有联l均有一遍完成ƈ且大多数联结甚至可以不用一个时表完成.最临时的表是基于内存的(heap)?
g:排序h分配一个排序缓冲区?个时表
h:所有语法分析和计算都在一个本地存储器完成
i:每个索引文g只被打开一?q且数据文g为每个ƈ发运行的U程打开一?
j:Ҏ(gu)个blob列的表,一个缓冲区动态的被扩大以便读入blob?
k:所有正在用的表的表处理器被保存在一个缓冲器中ƈ且作Z个fifo理.
l:一个mysqladmin flush-tables命o关闭所有不在用的表ƈ且在当前执行的线E结束时标记所有在使用的表准备关闭
3:mysql锁定?
mysql中所有锁定不会成为死?
wirte锁定:
mysql的锁定原?a:如果表没有锁?那么锁定;b否则,把锁定请求放入写锁定队列?
read锁定:
mysql的锁定原?a:如果表没有锁?那么锁定;b否则,把锁定请求放入读锁定队列?
有时候会在一个表中进行很多的select,insert操作,可以在一个时表中插入行q且偶尔用时表的记录更新真正的?
a:用low_priority属性给一个特定的insert,update或者delete较低的优先
b:max_write_lock_count指定一个?通常很小)来启动mysqld,使得在一定数量的write锁定之后出现read锁定
c:通过使用set sql_low_priority_updates=1可以从一个特定的U程指定所有的更改应该p低的优先U完?
d:用high_priority指定一个select
e:如果使用insert....select....出现问题,使用myisam?-----因ؓ它支持因为它支持q发的select和insert
4:最基本的优化是使数据在盘上占据的I间最?如果索引做在最的列上,那么索引也最?实现Ҏ(gu):
a:使用可能小的数据类?
b:如果可能Q声明表列ؓNOT NULL.
c:如果有可能用变成的数据cd,如varchar(但是速度会受一定的影响)
d:每个表应该有可能短的主索引
e:创徏实需要的索引
f:如果一个烦引在头几个字W上有唯一的前~,那么仅仅索引q个前缀----mysql支持在一个字W列的一部分上的索引
g:如果一个表l常被扫?那么试图拆分它ؓ更多的表
W四?
1:索引的?索引的重要性就不说?功能也不说了,只说怎么?
首先要明所有的mysql索引(primary,unique,index)在b树中有存?索引主要用语:
a:快速找到where指定条g的记?
b:执行联结?从其他表索行
c:对特定的索引列找出max()和min()?
dQ如果排序或者分l在一个可用键的最前面加前~Q排序或分组一个表
eQ一个查询可能被用来优化索|而不用访问数据文Ӟ如果某些表的列是数字型ƈ且正好是某个列的前缀Qؓ了更快,值可以从索引树中取出
Q:存储或者更新数据的查询速度
grant的执行会E稍的减低效率.
mysql的函数应该被高度的优化.可以用benchmarkQloop_count,expression)来找出是否查询有问题
select 的查询速度Q如果想要让一个selectQ.QwhereQ.Q更快,我能惛_的只有徏立烦引.可以在一个表上运行myisamchkQ-analyze 来更好的优化查询Q可以用myisamchkQ-sortQindexQ-sortQrecordsQ1来设|用一个烦引排序一个烦引和数据Q?
Q:mysql优化where子句
3.Q:删除不必要的括号Q?
Q(a AND b) AND c OR (((a AND b) AND (a AND d))))>(a AND b AND c) OR (a AND b AND c AND d)
3.2:使用常数
Qa<b AND b=c) AND a=100 > b>5 AND b=c AND a=5
3.3:删除常数条g
Qb>=5 AND b=5) OR (b=6 AND 5=5) OR (b=100 AND 2=3) > b=5 OR b=6
3.4:索引使用的常数表辑ּ仅计一?
3.5Q在一个表中,没有一个where的count(*)直接从表中检索信?
3.6:所有常数的表在查询中在M其他表之前读?
3.7:对外联结表最好联l组合是试了所有可能性找到的
3.8Q如果有一个order by字句和一个不同的group by子句或者order by或者group by包含不是来自联结的第一个表的列Q那么创Z个时表
3.9:如果使用了sql_small_resultQ那么msyql使用在内存中的一个表
3.10:每个表的索引l查询ƈ且用跨少于3Q%的行的烦引.
3.11在每个记录输出前Q蟩q不匚whaving子句的行
Q:优化left join
在mysql中 a left join b按以下方式实?
aQ表b依赖于表a
bQ表a依赖于所有用在left join条g的表Q除了bQ?
cQ所有left join条g被移到where子句?
dQ进行所有的联结优化Q除了一个表L在所有他依赖的表后读取.如果有一个@环依赖,那么发生错?
eQ进行所有的标准的where优化
fQ如果在a中有一行匹配where子句Q但是在b中没有Q何匹配left join条gQ那么,在b中生成的所有设|ؓQUQL的一?
gQ如果用left join来找出某些表中不存在的行q且在where部分有column_name IS NULL试(column_name为NOT NULL?Q那么,mysql在它已经扑ֈ了匹配left join条g的一行后Q将停止在更多的行后L
Q:优化limit
aQ如果用limit只选择一行,当mysql需要扫描整个表Ӟ它的作用相当于烦?
bQ如果用limitQ与order byQmysql如果扑ֈ了第Q行Q将l束排序Q而不会排序正个表
cQ当l合limitQ和distinctӞmysql如果扑ֈ了第Q行Q将停止
dQ只要mysql已经发送了W一个#行到客户Qmysql放弃查?
eQlimit 0一直会很快的返回一个空集合Q?
fQ时表的大用limitQ计需要多空间来解决查询
Q:优化insert
插入一条记录的是由以下构成Q?
a:q接Q3Q?
b:发送查询给服务器(Q)
c:分析查询Q2Q?
d:插入记录Q1*记录大小Q?
eQ插入烦引(Q?索引Q?
fQ关闭(Q)
以上数字可以看成和L间成比例
改善插入速度的一些方法:
6.1Q如果同时从一个连接插入许多行Q用多个值的insertQ这比用多个语句要快
6.2Q如果从不同q接插入很多行,使用insert delayed语句速度更快
6.3: 用myisamQ如果在表中没有删除的行Q能在selectQs正在q行的同时插入行
6.4: 当从一个文本文件装载一个表Ӟ用load data infileQ这个通常比insert?0
?
6.5: 可以锁定表然后插入-Q主要的速度差别是在所有insert语句完成后,索引~冲Z被存入到盘一ơ.一般与有不同的insert语句那样多次存入要快Q如果能用一个单个语句插入所有的行,锁定׃需要.锁定也降低连接的整体旉Q但是对某些U程最大等待时间将上升Q例如:
thread 1 does 1000 inserts
thread 2,3 and 4 does 1 insert
thread 5 does 1000 inserts
如果不用锁定,Q,Q,Q将在1和5之前完成Q如果用锁定,Q,Q,Q,可能在Q和Q之后完成.但是整体旉应该快4Q%Q因为insertQ?updateQdelete操作在mysql中是很快的,通过为多于大U5ơ连l不断的插入或更C行的东西加锁Q将获得更好的整体性能Q如果做很多一行的插入Q可以做一个lock tablesQ偶随后做一个unlock tablesQ大U每Q0Q0行)以允许另外的U程存取表.q仍然将D获得好的性能Qload data infile对装载数据仍然是很快的.
Z对load data infile和insert得到一些更快的速度Q扩大关键字~冲区.
Q优化update的速度
它的速度依赖于被更新数据的大和被更新烦引的数量
使update更快的另一个方法是推迟修改Q然后一行一行的做很多修改.如果锁定表,做一行一行的很多修改比一ơ做一个快
Q优化delete速度
删除一个记录的旉与烦引数量成正比Qؓ了更快的删除记录Q可以增加烦引缓存的大小
从一个表删除所有行比删除这个表的大部分要快的多
W五?
Q:选择一U表cd
1.1静态myisam
q种格式是最单且最安全的格式,它是盘格式中最快的Q速度来自于数据能在磁盘上被找到的难易E度Q当锁定有一个烦引和静态格式的东西是,它很单,只是行长度乘以数量.而且在扫描一张表Ӟ每次用磁盘读取来d常数个记录是很容易的Q安全性来源于如果当写入一个静态myisam文g时导致计机down 掉,myisamchk很容易指出每行在哪里开始和l束Q因此,它通常能收回所有记录,除了部分被写入的记录Q在mysql中所有烦引总能被重?
1.2动态myisam
q种格式每一行必L一个头说明它有多长Q当一个记录在更改期间变长Ӟ它可以在多于一个位|上l束Q能使用optimize tablename?myisamchk整理一张表Q如果在同一个表中有像某些varchar或者blob列那样存取/改变的静态数据,动态列Ud另外一个表以避免碎片.
1.2.1压羃myisamQ用可选的myisampack工具生成
1.2.2内存
q种格式对小型/中型表很有用Q对拯Q创Z个常用的查找表到zheap表有可能加快多个表联l,用同h据可能要快好几倍时_
select tablename.a,tablename2.a from tablename,tablanem2,tablename3 where
tablaneme.a=tablename2.a and tablename2.a=tablename3.a and tablename2.c!=0;
Z加速它Q可以用tablename2和tablename3的联l创Z个时表Q因为用相同列(tablename1.aQ查找.
CREATE TEMPORARY TABLE test TYPE=HEAP
SELECT
tablename2.a as a2,tablename3.a as a3
FROM
tablenam2,tablename3
WHERE
tablename2.a=tablename3.a and c=0;
SELECT tablename.a,test.a3 from tablename,test where tablename.a=test.a1;
SELECT tablename.a,test,a3,from tablename,test where tablename.a=test.a1 and ....;
1.3静态表的特?
1.3.1默认格式Q用在表不包含varcharQblobQtext列的时?
1.3.2所有的charQnumeric和decimal列填充到列宽?
1.3.3非常?
1.3.4Ҏ(gu)~冲
1.3.5Ҏ(gu)在down后重建,因ؓ记录位于固定的位|?
1.3.6不必被重新组l(用myisamchkQ,除非是一个巨量的记录被删除ƈ且优化存储大?
1.3.7通常比动态表需要更多的存储I间
1.4动态表的特?
1.4.1如果表包含Q何varcharQblobQtext列,使用该格?
1.4.2所有字W串列是动态的
1.4.3每个记录前置一个位Q?
1.4.4通常比定长表需要更多的盘I间
1.4.5每个记录仅仅使用所需要的I间Q如果一个记录变的很大,它按需要被分成很多D,q导致了记录片
1.4.6如果用超q行长度的信息更新行Q行被分D.
1.4.7在系ldown掉以后不好重Q因Z个记录可以是多段
1.4.8对动态尺寸记录的期望行长度是Q+Qnumber of columnsQ7Q/Q+(number
of char columns)+packed size of numeric columns+length of strings +(number of
NULL columns+7)/8
Ҏ(gu)个连接有Q个字节的惩|.无论何时更改引v记录的变大,都有一个动态记录被q接Q每个新q接臛_有2Q个字节Q因此下一个变大将可能在同一个连接中Q如果不是,有另外一个连接.可以用myisamchk Q恶毒检查有多少q接Q所有连接可以用myisamchk -r删除Q?
1.5压羃表的特点
1.5.1一张用myisampack实用E序制作的只读表Q?
1.5.2解压~代码存在于所有mysql分发中,以便使没有myisampack的连接也能读取用myisampack压羃的表
1.5.3占据很小的磁盘空?
1.5.4每个记录被单独压~.一个记录的头是一个定长的Q1~~Q个字节Q这取决于表的最大记录.每列以不同的方式被压~.一些常用的压羃cd是:
a:通常Ҏ(gu)列有一张不同的哈夫D
b:后缀I白压羃
c:前缀I白压羃
d:用|的数字用1位存?
e:如果整数列的值有一个小范围Q列使用最的可能cd来存储.例如Q如果所有的值在Q到Q5Q之_一个bigint可以作ؓ一个tinyint存储
g:如果列仅有可能值的一个小集合Q列cd被{换到enum
h:列可以用上面的压羃Ҏ(gu)的组?
1.5.5能处理定长或动态长度的记录Q去不能处理blob或者text?
1.5.6能用myisamchk解压~?
mysql能支持不同的索引cdQ但一般的cd是isamQ这是一个树烦引ƈ且能_略的ؓ索引文g计算大小?key_length+4)*0.67Q在所有的键上的dQ?
字符串烦引是I白压羃的。如果第一个烦引是一个字W串Q它可将压羃前缀如果字符串列有很多尾部空白或是一个总部能甬道全长的varchar列,I白压羃使烦引文件更.如果很多字符串有相同的前~Q?
1.6内存表的特点
mysql内部的heap表用每偶溢出去的1Q0Q动态哈希ƈ且没有与删除有关的问题.只能通过使用在堆表中的一个烦引来用等式存取东西(通常用'Q'操作W)
堆表的缺Ҏ(gu)Q?
1.6.1惌同时使用的所有堆表需要够的额外内存
1.6.2不能在烦引的一个部分搜?
1.6.3不能按顺序搜索下一个条目(卻I使用q个索引做一个order byQ?
1.6.4mysql不能出在2个g间大概有多少行.q被优化器用是用来军_使用哪个索引的,但是在另一个方面甚至不需要磁盘寻?img src ="http://www.tkk7.com/iKingQu/aggbug/38162.html" width = "1" height = "1" />
CallableStatement
本概q是从《JDBCTM Database Access from JavaTM: A Tutorial and Annotated Reference 》这本书中摘引来的。JavaSoft 目前正在准备q本书。这本书是一本教E,同时也是 JDBC 的重要参考手册,它将作ؓ Java pd的组成部份在 1997 q春季由 Addison-Wesley 出版公司出版。?
7.1 概述
CallableStatement 对象为所有的 DBMS 提供了一U以标准形式调用已储存过E的Ҏ(gu)。已储存q程储存在数据库中。对已储存过E的调用?CallableStatement 对象所含的内容。这U调用是用一U换码语法来写的Q有两种形式Q一UŞ式带l果参数Q另一UŞ式不带结果参敎ͼ有关换码语法的信息,参见W?4 节“语句”)。结果参数是一U输?(OUT) 参数Q是已储存过E的q回倹{两UŞ式都可带有数量可变的输入QIN 参数Q、输出(OUT 参数Q或输入和输出(INOUT 参数Q的参数。问号将用作参数的占位符?
?JDBC 中调用已储存q程的语法如下所C。注意,Ҏ(gu)可C其间的内容是可选项Q方括号本nq不是语法的l成部䆾?
{call q程名[(?, ?, ...)]}
q回l果参数的过E的语法为:
{? = call q程名[(?, ?, ...)]}
不带参数的已储存q程的语法类|
{call q程名}
通常Q创?CallableStatement 对象的h应当知道所用的 DBMS 是支持已储存q程的,q且知道q些q程都是些什么。然而,如果需要检查,多种 DatabaseMetaData Ҏ(gu)都可以提供这L信息。例如,如果 DBMS 支持已储存过E的调用Q则 supportsStoredProcedures Ҏ(gu)返?trueQ?getProcedures Ҏ(gu)返回对已储存过E的描述?
CallableStatement l承 Statement 的方法(它们用于处理一般的 SQL 语句Q,q承了 PreparedStatement 的方法(它们用于处理 IN 参数Q。CallableStatement 中定义的所有方法都用于处理 OUT 参数?INOUT 参数的输出部分:注册 OUT 参数?JDBC cdQ一?SQL cdQ、从q些参数中检索结果,或者检查所q回的值是否ؓ JDBC NULL?
7.1.1 创徏 CallableStatement 对象
CallableStatement 对象是用 Connection Ҏ(gu) prepareCall 创徏的。下例创?CallableStatement 的实例,其中含有对已储存q程 getTestData 调用。该q程有两个变量,但不含结果参敎ͼ
CallableStatement cstmt = con.prepareCall(
"{call getTestData(?, ?)}");
其中 ? 占位Wؓ IN?OUT q是 INOUT 参数Q取决于已储存过E?getTestData?
7.1.2 IN ?OUT 参数
?IN 参数传给 CallableStatement 对象是通过 setXXX Ҏ(gu)完成的。该Ҏ(gu)l承?PreparedStatement。所传入参数的类型决定了所用的 setXXX Ҏ(gu)Q例如,?setFloat 来传?float 值等Q?
如果已储存过E返?OUT 参数Q则在执?CallableStatement 对象以前必须先注册每?OUT 参数?JDBC cdQ这是必需的,因ؓ某些 DBMS 要求 JDBC cdQ。注?JDBC cd是用 registerOutParameter Ҏ(gu)来完成的。语句执行完后,CallableStatement ?getXXX Ҏ(gu)取回参数倹{正的 getXXX Ҏ(gu)是ؓ各参数所注册?JDBC cd所对应?Java cdQ从 JDBC cd?Java cd的标准映见 8.6.1 节中的表Q。换a之, registerOutParameter 使用的是 JDBC cdQ因此它与数据库q回?JDBC cd匚wQ,?getXXX 之转换?Java cd?
作ؓCZQ下qC码先注册 OUT 参数Q执行由 cstmt 所调用的已储存q程Q然后检索在 OUT 参数中返回的倹{方?getByte 从第一?OUT 参数中取Z?Java 字节Q?getBigDecimal 从第二个 OUT 参数中取Z?BigDecimal 对象Q小数点后面带三位数Q:
CallableStatement cstmt = con.prepareCall(
"{call getTestData(?, ?)}");
cstmt.registerOutParameter(1, java.sql.Types.TINYINT);
cstmt.registerOutParameter(2, java.sql.Types.DECIMAL, 3);
cstmt.executeQuery();
byte x = cstmt.getByte(1);
java.math.BigDecimal n = cstmt.getBigDecimal(2, 3);
CallableStatement ?ResultSet 不同Q它不提供用增量方式索大 OUT 值的Ҏ(gu)机制?
7.1.3 INOUT 参数
既支持输入又接受输出的参敎ͼINOUT 参数Q除了调?registerOutParameter Ҏ(gu)外,q要求调用适当?setXXX Ҏ(gu)Q该Ҏ(gu)是从 PreparedStatement l承来的Q。setXXX Ҏ(gu)参数D|ؓ输入参数Q?registerOutParameter Ҏ(gu)它?JDBC cd注册出参数。setXXX Ҏ(gu)提供一?Java |而驱动程序先把这个D{换ؓ JDBC |然后它送到数据库中?
q种 IN 值的 JDBC cd和提供给 registerOutParameter Ҏ(gu)?JDBC cd应该相同。然后,要检索输出|p用对应的 getXXX Ҏ(gu)。例如,Java cd?byte 的参数应该用方?setByte 来赋输入倹{应该给 registerOutParameter 提供cd?TINYINT ?JDBC cdQ同时应使用 getByte 来检索输出?Q第 8 节“JDBC ?Java cd之间的映”将l出详细信息和类型映表Q?
下例假设有一个已储存q程 reviseTotalQ其唯一参数?INOUT 参数。方?setByte 把此参数设ؓ 25Q驱动程序将把它作ؓ JDBC TINYINT cd送到数据库中。接着QregisterOutParameter 该参数注册?JDBC TINYINT。执行完该已储存q程后,返回一个新?JDBC TINYINT 倹{方?getByte 把q个新g?Java byte cd索?
CallableStatement cstmt = con.prepareCall(
"{call reviseTotal(?)}");
cstmt.setByte(1, 25);
cstmt.registerOutParameter(1, java.sql.Types.TINYINT);
cstmt.executeUpdate();
byte x = cstmt.getByte(1);
7.1.4 先检索结果,再检?OUT 参数
׃某些 DBMS 的限ӞZ实现最大的可移植性,先检索由执行 CallableStatement 对象所产生的结果,然后再用 CallableStatement.getXXX Ҏ(gu)来检?OUT 参数?
如果 CallableStatement 对象q回多个 ResultSet 对象Q通过调用 execute Ҏ(gu)Q,在检?OUT 参数前应先检索所有的l果。这U情况下Qؓ保Ҏ(gu)有的l果都进行了讉KQ必d Statement Ҏ(gu) getResultSet、getUpdateCount ?getMoreResults q行调用Q直C再有l果为止?
索完所有的l果后,可?CallableStatement.getXXX Ҏ(gu)来检?OUT 参数中的倹{?
7.1.5 索作?OUT 参数?NULL ?
q回?OUT 参数中的值可能会?JDBC NULL。当出现q种情ŞӞ对 JDBC NULL D行{换以?getXXX Ҏ(gu)所q回的gؓ null? ?falseQ这取决?getXXX Ҏ(gu)cd。对?ResultSet 对象Q要知道 0 ?false 是否源于 JDBC NULL 的唯一Ҏ(gu)Q是用方?wasNull q行。如?getXXX Ҏ(gu)d的最后一个值是 JDBC NULLQ则该方法返?trueQ否则返?flase。第 5 节“ResultSet”将l出详细信息。 ?
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=630452
JDBCpd教程Q五Q?--准备语句
PreparedStatement
本概q是从《JDBCTM Database Access from JavaTM: A Tutorial and Annotated Reference 》这本书中摘引来的。JavaSoft 目前正在准备q本书。这是一本教E,同时也是 JDBC 的重要参考手册,它将作ؓ Java pd的组成部份在 1997 q春季由 Addison-Wesley 出版公司出版。?
6.1 概述
?PreparedStatement 接口l承 StatementQƈ与之在两斚w有所不同Q?
PreparedStatement 实例包含已编译的 SQL 语句。这是使语句“准备好”。?
包含?PreparedStatement 对象中的 SQL 语句可具有一个或多个 IN 参数。IN 参数的值在 SQL 语句创徏时未被指定。相反的Q该语句为每?IN 参数保留一个问P“?”)作ؓ占位W。每个问L值必d该语句执行之前,通过适当?setXXX Ҏ(gu)来提供。?
׃ PreparedStatement 对象已预~译q,所以其执行速度要快?Statement 对象。因此,多次执行?SQL 语句l常创徏?PreparedStatement 对象Q以提高效率?
作ؓ Statement 的子c,PreparedStatement l承?Statement 的所有功能。另外它q添加了一整套Ҏ(gu)Q用于设|发送给数据库以取代 IN 参数占位W的倹{同Ӟ三种Ҏ(gu) execute?executeQuery ?executeUpdate 已被更改以之不再需要参数。这些方法的 Statement 形式Q接?SQL 语句参数的Ş式)不应该用?PreparedStatement 对象?
6.1.1 创徏 PreparedStatement 对象
以下的代码段Q其?con ?Connection 对象Q创建包含带两个 IN 参数占位W的 SQL 语句?PreparedStatement 对象Q?
PreparedStatement pstmt = con.prepareStatement(
"UPDATE table4 SET m = ? WHERE x = ?");
pstmt 对象包含语句 "UPDATE table4 SET m = ? WHERE x = ?"Q它已发送给 DBMSQƈ为执行作好了准备?
6.1.2 传?IN 参数
在执?PreparedStatement 对象之前Q必设|每?? 参数的倹{这可通过调用 setXXX Ҏ(gu)来完成,其中 XXX 是与该参数相应的cd。例如,如果参数h Java cd longQ则使用的方法就?setLong。setXXX Ҏ(gu)的第一个参数是要设|的参数的序C|,W二个参数是讄l该参数的倹{例如,以下代码第一个参数设?123456789Q第二个参数设ؓ 100000000Q?
pstmt.setLong(1, 123456789);
pstmt.setLong(2, 100000000);
一旦设|了l定语句的参数|可用它多次执行该语句,直到调用 clearParameters Ҏ(gu)清除它ؓ止?
在连接的~省模式下(启用自动提交Q,当语句完成时自动提交或q原该语句?
如果基本数据库和驱动E序在语句提交之后仍保持q些语句的打开状态,则同一?PreparedStatement 可执行多ơ。如果这一点不成立Q那么试N过使用 PreparedStatement 对象代替 Statement 对象来提高性能是没有意义的?
利用 pstmtQ前面创建的 PreparedStatement 对象Q,以下代码例示了如何设|两个参数占位符的值ƈ执行 pstmt 10 ơ。如上所qͼ为做到这一点,数据库不能关?pstmt。在该示例中Q第一个参数被讄?"Hi"q保持ؓ常数。在 for 循环中,每次都将W二个参数设|ؓ不同的|?0 开始,?9 l束?
pstmt.setString(1, "Hi");
for (int i = 0; i < 10; i++) {
pstmt.setInt(2, i);
int rowCount = pstmt.executeUpdate();
}
6.1.3 IN 参数中数据类型的一致?
setXXX Ҏ(gu)中的 XXX ?Java cd。它是一U隐含的 JDBC cdQ一?SQL cdQ,因ؓ驱动E序把 Java cd映射为相应的 JDBC cdQ遵循该 JDBC Guide中?.6.2 “映?Java ?JDBC cd”表中所指定的映)Qƈ该 JDBC cd发送给数据库。例如,以下代码D将 PreparedStatement 对象 pstmt 的第二个参数讄?44QJava cd?shortQ?
pstmt.setShort(2, 44);
驱动E序?44 作ؓ JDBC SMALLINT 发送给数据库,它是 Java short cd的标准映?
E序员的责Q是确保将每个 IN 参数?Java cd映射Z数据库所需?JDBC 数据cd兼容?JDBC cd。不妨考虑数据库需?JDBC SMALLINT 的情c如果用方?setByte Q则驱动E序?JDBC TINYINT 发送给数据库。这是可行的Q因多数据库可从一U相关的cd转换为另一U类型,q且通常 TINYINT 可用?SMALLINT 适用的Q何地斏V然而,对于要适用于尽可能多的数据库的应用E序Q最好用与数据库所需的确切的 JDBC cd相应?Java cd。如果所需?JDBC cd?SMALLINTQ则使用 setShort 代替 setByte 应用E序的可UL性更好?
6.1.4 使用 setObject
E序员可使用 setObject Ҏ(gu)昑ּ地将输入参数转换为特定的 JDBC cd。该Ҏ(gu)可以接受W三个参敎ͼ用来指定目标 JDBC cd。将 Java Object 发送给数据库之前,驱动E序把它{换ؓ指定?JDBC cd?
如果没有指定 JDBC cdQ驱动程序就会将 Java Object 映射到其~省?JDBC cdQ参见第 8.6.4 节中的表|Q然后将它发送到数据库。这与常规的 setXXX Ҏ(gu)cMQ在q两U情况下Q驱动程序在值发送到数据库之前,会将该值的 Java cd映射为适当?JDBC cd。二者的差别在于 setXXX Ҏ(gu)使用?Java cd?JDBC cd的标准映(参见W?8.6.2 节中的表|Q?setObject Ҏ(gu)使用?Java Object cd?JDBC cd的映(参见W?8.6.4 节中的表|?
Ҏ(gu) setObject 允许接受所?Java 对象的能力应用E序更ؓ通用Qƈ可在q行时接受参数的输入。这U情况下Q应用程序在~译时ƈ不清楚输入类型。通过使用 setObjectQ应用程序可接受所?Java 对象cd作ؓ输入Qƈ其转换为数据库所需?JDBC cd。第 8.6.5 节中的表格显CZ setObject 可执行的所有可能{换?
6.1.5 ?JDBC NULL 作ؓ IN 参数发?
setNull Ҏ(gu)允许E序员将 JDBC NULL g?IN 参数发送给数据库。但要注意,仍然必须指定参数?JDBC cd?
当把 Java null g递给 setXXX Ҏ(gu)Ӟ如果它接?Java 对象作ؓ参数Q,也将同样?JDBC NULL 发送到数据库。但仅当指定 JDBC cdӞҎ(gu) setObject 才能接受 null 倹{?
6.1.6 发送大?IN 参数
setBytes ?setString Ҏ(gu)能够发送无限量的数据。但是,有时E序员更喜欢用较?yu)的块传递大型的数据。这可通过?IN 参数讄?Java 输入来完成。当语句执行ӞJDBC 驱动E序重复调用该输入,d其内容ƈ它们当作实际参数数据传输?
JDBC 提供了三U将 IN 参数讄入流的方法:setBinaryStream 用于含有未说明字节的, setAsciiStream 用于含有 ASCII 字符的流Q?setUnicodeStream 用于含有 Unicode 字符的流。因为必L定流的总长度,所以这些方法所采用的参数比其它?setXXX Ҏ(gu)要多一个。这很有必要Q因Z些数据库在发送数据之前需要知道其ȝ传送大?
以下代码例示了用流作ؓ IN 参数来发送文件内容:
java.io.File file = new java.io.File("/tmp/data");
int fileLength = file.length();
java.io.InputStream fin = new java.io.FileInputStream(file);
java.sql.PreparedStatement pstmt = con.prepareStatement(
"UPDATE Table5 SET stuff = ? WHERE index = 4");
pstmt.setBinaryStream (1, fin, fileLength);
pstmt.executeUpdate();
当语句执行时Q将反复调用输入?fin 以传递其数据?
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=630450
JDBCpd教程Q四Q?--l果讄
ResultSet
本概q是从《JDBCTM Database Access from JavaTM: A Tutorial and Annotated Reference 》这本书中摘引来的。JavaSoft 目前正在准备q本书。这是一本教E,同时也是 JDBC 的重要参考手册,它将作ؓ Java pd的组成部份在 1997 q春季由 Addison-Wesley 出版公司出版。?
5.1 概述
ResultSet 包含W合 SQL 语句中条件的所有行Qƈ且它通过一?get Ҏ(gu)Q这?get Ҏ(gu)可以讉K当前行中的不同列Q提供了对这些行中数据的讉K。ResultSet.next Ҏ(gu)用于Ud?ResultSet 中的下一行,使下一行成为当前行?
l果集一般是一个表Q其中有查询所q回的列标题及相应的倹{例如,如果查询?SELECT a, b, c FROM Table1Q则l果集将h如下形式Q?
a b c
-------- --------- --------
12345 Cupertino CA
83472 Redmond WA
83492 Boston MA
下面的代码段是执?SQL 语句的示例。该 SQL 语句返回行集合Q其中列 1 ?intQ列 2 ?StringQ而列 3 则ؓ字节数组Q?
java.sql.Statement stmt = conn.createStatement();
ResultSet r = stmt.executeQuery("SELECT a, b, c FROM Table1");
while (r.next())
{
// 打印当前行的倹{?
int i = r.getInt("a");
String s = r.getString("b");
float f = r.getFloat("c");
System.out.println("ROW = " + i + " " + s + " " + f);
}
5.1.1 行和光标
ResultSet l护指向其当前数据行的光标。每调用一?next Ҏ(gu)Q光标向下移动一行。最初它位于W一行之前,因此W一ơ调?next 把光标|于W一行上Q它成为当前行。随着每次调用 next D光标向下Ud一行,按照从上至下的次序获?ResultSet 行?
?ResultSet 对象或其父辈 Statement 对象关闭之前Q光标一直保持有效?
?SQL 中,l果表的光标是有名字的。如果数据库允许定位更新或定位删除,则需要将光标的名字作为参数提供给更新或删除命令。可通过调用Ҏ(gu) getCursorName 获得光标名?
注意Q不是所有的 DBMS 都支持定位更新和删除。可使用 DatabaseMetaData.supportsPositionedDelete ?supportsPositionedUpdate Ҏ(gu)来检查特定连接是否支持这些操作。当支持q些操作ӞDBMS/驱动E序必须保适当锁定选定行,以定位更新不会D更新异常或其它ƈ发问题?
5.1.2 ?
Ҏ(gu) getXXX 提供了获取当前行中某列值的途径。在每一行内Q可按Q何次序获取列倹{但Z保证可移植性,应该从左臛_获取列|q且一ơ性地d列倹{?
列名或列号可用于标识要从中获取数据的列。例如,如果 ResultSet 对象 rs 的第二列名ؓ“title”,q将值存储ؓ字符Ԍ则下列Q一代码获取存储在该列中的|
String s = rs.getString("title");
String s = rs.getString(2);
注意列是从左臛_~号的,q且从列 1 开始。同Ӟ用作 getXXX Ҏ(gu)的输入的列名不区分大写?
提供使用列名q个选项的目的是Z让在查询中指定列名的用户可用相同的名字作ؓ getXXX Ҏ(gu)的参数。另一斚wQ如?select 语句未指定列名(例如在“select * from table1”中或列是导出的ӞQ则应该使用列号。这些情况下Q用户将无法切知道列名?
有些情况下,SQL 查询q回的结果集中可能有多个列具有相同的名字。如果列名用?getXXX Ҏ(gu)的参敎ͼ?getXXX 返回第一个匹配列名的倹{因而,如果多个列具有相同的名字Q则需要用列索引来确保检索了正确的列倹{这Ӟ使用列号效率要稍微高一些?
关于 ResultSet 中列的信息,可通过调用Ҏ(gu) ResultSet.getMetaData 得到。返回的 ResultSetMetaData 对象给出其 ResultSet 对象各列的编受类型和属性?
如果列名已知Q但不知其烦引,则可用方?findColumn 得到其列受?
5.1.3 数据cd和{?
对于 getXXX Ҏ(gu)QJDBC 驱动E序试图基本数据{换成指定 Java cdQ然后返回适合?Java 倹{例如,如果 getXXX Ҏ(gu)?getStringQ而基本数据库中数据类型ؓ VARCHARQ则 JDBC 驱动E序把 VARCHAR 转换?Java String。getString 的返回值将?Java String 对象?
下表昄了允许用 getXXX 获取?JDBC cd及推荐用它获取的 JDBC cdQ通用 SQL cdQ。小写的 x 表示允许 getXXX Ҏ(gu)获取该数据类型;大写?X 表示对该数据cd推荐使用 getXXX Ҏ(gu)。例如,除了 getBytes ?getBinaryStream 之外的Q?getXXX Ҏ(gu)都可用来获取 LONGVARCHAR |但是推荐Ҏ(gu)q回的数据类型?getAsciiStream ?getUnicodeStream Ҏ(gu)。方?getObject Q何数据类型返回ؓ Java Object。当基本数据cd是特定于数据库的抽象cd或当通用应用E序需要接受Q何数据类型时Q它是非常有用的?
可?ResultSet.getXXX Ҏ(gu)获取常见?JDBC 数据cd?
“x”表C getXXX Ҏ(gu)可合法地用于获取l定 JDBC cd?
“X”表C推荐用该 getXXX Ҏ(gu)来获取给?JDBC cd?
T
I
N
Y
I
N
T S
M
A
L
L
I
N
T I
N
T
E
G
E
R B
I
G
N
T R
E
A
L F
L
O
A
T D
O
U
B
L
E D
E
C
I
M
A
L N
U
M
E
R
I
C B
I
T C
H
A
R V
A
R
C
H
A
R
L
O
N
G
V
A
R
C
H
A
R B
I
N
A
R
Y V
A
R
B
I
N
A
R
Y L
O
N
G
V
A
R
B
I
N
A
R
Y D
A
T
E T
I
M
E T
I
M
E
S
T
A
M
P
getByte X x x x x x x x x x x x x
getShort x X x x x x x x x x x x x
getInt x x X x x x x x x x x x x
getLong x x x X x x x x x x x x x
getFloat x x x x X x x x x x x x x
getDouble x x x x x X X x x x x x x
getBigDecimal x x x x x x x X X x x x x
getBoolean x x x x x x x x x X x x x
getString x x x x x x x x x x X X x x x x x x x
getBytes X X x
getDate x x x X x
getTime x x x X x
getTimestamp x x x x X
getAsciiStream x x X x x x
getUnicodeStream x x X x x x
getBinaryStream x x X
getObject x x x x x x x x x x x x x x x x x x x
5.1.4 寚w常大的行g用流
ResultSet 可以获取L大的 LONGVARBINARY ?LONGVARCHAR 数据。方?getBytes ?getString 数据返回ؓ大的块(最大ؓ Statement.getMaxFieldSize 的返回|。但是,以较?yu)的固定块获取非常大的数据可能会更方便,而这可通过?ResultSet c返?java.io.Input 来完成。从该流中可分块d数据。注意:必须立即讉Kq些,因ؓ在下一ơ对 ResultSet 调用 getXXX 时它们将自动关闭Q这是由于基本实现对大块数据讉K有限Ӟ。?
JDBC API h三个获取的Ҏ(gu)Q分别具有不同的q回|
getBinaryStream q回只提供数据库原字节而不q行M转换的流?
getAsciiStream q回提供单字?ASCII 字符的流?
getUnicodeStream q回提供双字?Unicode 字符的流?
注意Q它不同?Java ,后者返回无cd字节q可Q例如)通用?ASCII ?Unicode 字符?
下列代码演示?getAsciiStream 的用法:
java.sql.Statement stmt = con.createStatement();
ResultSet r = stmt.executeQuery("SELECT x FROM Table2");
// 现在?4K 块大获取列 1 l果Q?
byte buff = new byte[4096];
while (r.next()) {
Java.io.InputStream fin = r.getAsciiStream(1);
for (;;) {
int size = fin.read(buff);
if (size == -1) { // 到达末?
break;
}
// 新填充的缓冲区发送到 ASCII 输出:
output.write(buff, 0, size);
}
}
5.1.5 NULL l果?
要确定给定结果值是否是 JDBC NULLQ必dd该列Q然后?ResultSet.wasNull Ҏ(gu)查该ơ读取是否返?JDBC NULL?
当?ResultSet.getXXX Ҏ(gu)d JDBC NULL ӞҎ(gu) wasNull 返回下列g一Q?
Java null |对于q回 Java 对象?getXXX Ҏ(gu)Q例?getString、getBigDecimal、getBytes、getDate、getTime、getTimestamp、getAsciiStream、getUnicodeStream、getBinaryStream、getObject {)?
零|对于 getByte、getShort、getInt、getLong、getFloat ?getDouble?
false |对于 getBoolean?
5.1.6 可选结果集或多l果?
通常使用 executeQueryQ它q回单个 ResultSetQ或 executeUpdateQ它可用于Q何数据库修改语句Qƈq回更新行数Q可执行 SQL 语句。但有些情况下,应用E序在执行语句之前不知道该语句是否返回结果集。此外,有些已存储过E可能返回几个不同的l果集和/或更新计数?
Z适应q些情况QJDBC 提供了一U机Ӟ允许应用E序执行语句Q然后处理由l果集和更新计数l成的Q意集合。这U机制的原理是首先调用一个完全通用?execute Ҏ(gu)Q然后调用另外三个方法,getResultSet、getUpdateCount ?getMoreResults。这些方法允许应用程序一ơ一个地研究语句l果Qƈ定l定l果?ResultSet q是更新计数?
用户不必关闭 ResultSetQ当产生它的 Statement 关闭、重新执行或用于从多l果序列中获取下一个结果时Q该 ResultSet 被 Statement 自动关闭。?
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=630447
JDBCpd教程Q三Q?--语句
Statement
本概q是从《JDBCTM Database Access from JavaTM: A Tutorial and Annotated Reference 》这本书中摘引来的。JavaSoft 目前正在准备q本书。这是一本教E,同时也是 JDBC 的重要参考手册,它将作ؓ Java pd的组成部份在 1997 q春季由 Addison-Wesley 出版公司出版。?
4.1 概述
Statement 对象用于?SQL 语句发送到数据库中。实际上有三U?Statement 对象Q它们都作ؓ在给定连接上执行 SQL 语句的包容器QStatement、PreparedStatementQ它?Statement l承而来Q和 CallableStatementQ它?PreparedStatement l承而来Q。它们都专用于发送特定类型的 SQL 语句Q?Statement 对象用于执行不带参数的简?SQL 语句QPreparedStatement 对象用于执行带或不带 IN 参数的预~译 SQL 语句QCallableStatement 对象用于执行Ҏ(gu)据库已存储过E的调用?
Statement 接口提供了执行语句和获取l果的基本方法。PreparedStatement 接口d了处?IN 参数的方法;?CallableStatement d了处?OUT 参数的方法?
4.1.1 创徏 Statement 对象
建立了到特定数据库的q接之后Q就可用该连接发?SQL 语句。Statement 对象?Connection 的方?createStatement 创徏Q如下列代码D中所C:
Connection con = DriverManager.getConnection(url, "sunny", "");
Statement stmt = con.createStatement();
Z执行 Statement 对象Q被发送到数据库的 SQL 语句被作ؓ参数提供l?Statement 的方法:
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table2");
4.1.2 使用 Statement 对象执行语句
Statement 接口提供了三U执?SQL 语句的方法:executeQuery、executeUpdate ?execute。用哪一个方法由 SQL 语句所产生的内容决定?
Ҏ(gu) executeQuery 用于产生单个l果集的语句Q例?SELECT 语句?
Ҏ(gu) executeUpdate 用于执行 INSERT、UPDATE ?DELETE 语句以及 SQL DDLQ数据定义语aQ语句,例如 CREATE TABLE ?DROP TABLE。INSERT、UPDATE ?DELETE 语句的效果是修改表中零行或多行中的一列或多列。executeUpdate 的返回值是一个整敎ͼ指示受媄响的行数Q即更新计数Q。对?CREATE TABLE ?DROP TABLE {不操作行的语句QexecuteUpdate 的返回值Mؓ零?
Ҏ(gu) execute 用于执行q回多个l果集、多个更新计数或二者组合的语句。因为多数程序员不会需要该高功能Q所以本概述后面在单独一节中对其q行介绍?
执行语句的所有方法都关闭所调用?Statement 对象的当前打开l果集(如果存在Q。这意味着在重新执?Statement 对象之前Q需要完成对当前 ResultSet 对象的处理?
应注意,l承?Statement 接口中所有方法的 PreparedStatement 接口都有自己?executeQuery、executeUpdate ?execute Ҏ(gu)。Statement 对象本n不包?SQL 语句Q因而必ȝ Statement.execute Ҏ(gu)提供 SQL 语句作ؓ参数。PreparedStatement 对象q不?SQL 语句作ؓ参数提供l这些方法,因ؓ它们已经包含预编?SQL 语句。CallableStatement 对象l承q些Ҏ(gu)?PreparedStatement 形式。对于这些方法的 PreparedStatement ?CallableStatement 版本Q用查询参数将抛出 SQLException?
4.1.3 语句完成
当连接处于自动提交模式时Q其中所执行的语句在完成时将自动提交或还原。语句在已执行且所有结果返回时Q即认ؓ已完成。对于返回一个结果集?executeQuery Ҏ(gu)Q在索完 ResultSet 对象的所有行时该语句完成。对于方?executeUpdateQ当它执行时语句卛_成。但在少数调用方?execute 的情况中Q在索所有结果集或它生成的更新计C后语句才完成?
有些 DBMS 已存储q程中的每条语句视ؓ独立的语句;而另外一些则整个过E视Z个复合语句。在启用自动提交Ӟq种差别变得非帔R要,因ؓ它媄响什么时候调?commit Ҏ(gu)。在前一U情况中Q每条语句单独提交;在后一U情况中Q所有语句同时提交?
4.1.4 关闭 Statement 对象
Statement 对象由 Java 垃圾攉E序自动关闭。而作ZU好的编E风|应在不需?Statement 对象时显式地关闭它们。这立即释?DBMS 资源Q有助于避免潜在的内存问题?
4.1.5 Statement 对象中的 SQL 转义语法
Statement 可包含?SQL 转义语法?SQL 语句。{义语法告诉驱动程序其中的代码应该以不同方式处理。驱动程序将扫描M转义语法Qƈ它转换成特定数据库可理解的代码。这使得转义语法?DBMS 无关Qƈ允许E序员用在没有转义语法时不可用的功能?
转义子句p括号和关键字界定Q?
{keyword . . . parameters . . . }
该关键字指示转义子句的类型,如下所C?
escape 表示 LIKE 转义字符
字符?”和“_”类g SQL LIKE 子句中的通配W(?”匹配零个或多个字符Q而“_”则匚w一个字W)。ؓ了正解释它们,应在其前面加上反斜杠Q“\”)Q它是字W串中的Ҏ(gu)转义字符。在查询末尾包括如下语法卛_指定用作转义字符的字W:
{escape 'escape-character'}
例如Q下列查询用反斜杠字符作ؓ转义字符Q查找以下划U开头的标识W名Q?
stmt.executeQuery("SELECT name FROM Identifiers
WHERE Id LIKE `\_%' {escape `\'};
fn 表示标量函数
几乎所?DBMS 都具有标量值的数倹{字W串、时间、日期、系l和转换函数。要使用q些函数Q可使用如下转义语法Q关键字 fn 后跟所需的函数名及其参数。例如,下列代码调用函数 concat 两个参数连接在一P
{fn concat("Hot", "Java")};
可用下列语法获得当前数据库用户名Q?
{fn user()};
标量函数可能p法稍有不同的 DBMS 支持Q而它们可能不被所有驱动程序支持。各U?DatabaseMetaData Ҏ(gu)列出所支持的函数。例如,Ҏ(gu) getNumericFunctions q回用逗号分隔的数值函数列表,而方?getStringFunctions 返回字W串函数Q等{?
驱动E序{义函数调用映ؓ相应的语法,或直接实现该函数?
d、t ?ts 表示日期和时间文?
DBMS 用于日期、时间和旉标记文字的语法各不相同。JDBC 使用转义子句支持q些文字的语法的 ISO 标准格式。驱动程序必d转义子句转换?DBMS 表示?
例如Q可用下列语法在 JDBC SQL 语句中指定日期:
{d `yyyy-mm-dd'}
在该语法中,yyyy 为年代,mm 为月份,?dd 则ؓ日期。驱动程序将用等L特定?DBMS 的表C替换这个{义子句。例如,如果 '28- FEB-99' W合基本数据库的格式Q则驱动E序用它替?{d 1999-02-28}?
对于 TIME ?TIMESTAMP 也有cM的{义子句:
{t `hh:mm:ss'}
{ts `yyyy-mm-dd hh:mm:ss.f . . .'}
TIMESTAMP 中的数点后的秒Q?f . . .Q部分可忽略?
call ?? = call 表示已存储过E?
如果数据库支持已存储q程Q则可从 JDBC 中调用它们,语法为:
{call procedure_name[(?, ?, . . .)]}
或(其中q程q回l果参数Q:
{? = call procedure_name[(?, ?, . . .)]}
Ҏ(gu)hC其中的内容是可选的。它们不是语法的必要部分?
输入参数可以为文字或参数。有兌l信息,参见 JDBC 指南中第 7 节,“CallableStatement”?
可通过调用Ҏ(gu) DatabaseMetaData.supportsStoredProcedures 查数据库是否支持已存储过E?
oj 表示外部q接
外部q接的语法ؓ
{oj outer-join}
其中 outer-join 形式为?
table LEFT OUTER JOIN {table / outer-join} ON search-condition
外部q接属于高功能。有兛_们的解释可参?SQL 语法。JDBC 提供了三U?DatabaseMetaData Ҏ(gu)用于定驱动E序支持哪些外部q接cdQsupportsOuterJoins、supportsFullOuterJoins ?supportsLimitedOuterJoins?
Ҏ(gu) Statement.setEscapeProcessing 可打开或关闭{义处理;~省状态ؓ打开。当性能极ؓ重要ӞE序员可能想关闭它以减少处理旉。但通常它将Z打开状态。应注意Q?setEscapeProcessing 不适用?PreparedStatement 对象Q因为在调用该语句前它就可能已被发送到数据库。有关预~译的信息,参见 PreparedStatement?
4.1.6 使用Ҏ(gu) execute
execute Ҏ(gu)应该仅在语句能返回多?ResultSet 对象、多个更新计数或 ResultSet 对象与更新计数的l合时用。当执行某个已存储过E或动态执行未?SQL 字符Ԍ卛_用程序程序员在编译时未知Q时Q有可能出现多个l果的情况,管q种情况很少见。例如,用户可能执行一个已存储q程Q?CallableStatement 对象 - 参见W?135 늚 CallableStatementQ,q且该已存储q程可执行更斎ͼ然后执行选择Q再q行更新Q再q行选择Q等{。通常使用已存储过E的人应知道它所q回的内宏V?
因ؓҎ(gu) execute 处理非常规情况,所以获取其l果需要一些特D处理ƈ不为怪。例如,假定已知某个q程q回两个l果集,则在使用Ҏ(gu) execute 执行该过E后Q必调用方?getResultSet 获得W一个结果集Q然后调用适当?getXXX Ҏ(gu)获取其中的倹{要获得W二个结果集Q需要先调用 getMoreResults Ҏ(gu)Q然后再调用 getResultSet Ҏ(gu)。如果已知某个过E返回两个更新计敎ͼ则首先调用方?getUpdateCountQ然后调?getMoreResultsQƈ再次调用 getUpdateCount?
对于不知道返回内容,则情冉|为复杂。如果结果是 ResultSet 对象Q则Ҏ(gu) execute q回 trueQ如果结果是 Java intQ则q回 false。如果返?intQ则意味着l果是更新计数或执行的语句是 DDL 命o。在调用Ҏ(gu) execute 之后要做的第一件事情是调用 getResultSet ?getUpdateCount。调用方?getResultSet 可以获得两个或多?ResultSet 对象中第一个对象;或调用方?getUpdateCount 可以获得两个或多个更新计CW一个更新计数的内容?
?SQL 语句的结果不是结果集Ӟ则方?getResultSet 返?null。这可能意味着l果是一个更新计数或没有其它l果。在q种情况下,判断 null 真正含义的唯一Ҏ(gu)是调用方?getUpdateCountQ它?yu)返回一个整数。这个整Cؓ调用语句所影响的行敎ͼ如果?-1 则表C结果是l果集或没有l果。如果方?getResultSet 已返?nullQ表C结果不?ResultSet 对象Q,则返回?-1 表示没有其它l果。也是_当下列条件ؓ真时表示没有l果Q或没有其它l果Q:
((stmt.getResultSet() == null) && (stmt.getUpdateCount() == -1))
如果已经调用Ҏ(gu) getResultSet q处理了它返回的 ResultSet 对象Q则有必要调用方?getMoreResults 以确定是否有其它l果集或更新计数。如?getMoreResults q回 trueQ则需要再ơ调?getResultSet 来检索下一个结果集。如上所qͼ如果 getResultSet q回 nullQ则需要调?getUpdateCount 来检?null 是表C结果ؓ更新计数q是表示没有其它l果?
?getMoreResults q回 false Ӟ它表C SQL 语句q回一个更新计数或没有其它l果。因此需要调用方?getUpdateCount 来检查它是哪一U情c在q种情况下,当下列条件ؓ真时表示没有其它l果Q?
((stmt.getMoreResults() == false) && (stmt.getUpdateCount() == -1))
下面的代码演CZ一U方法用来确认已讉K调用Ҏ(gu) execute 所产生的全部结果集和更新计敎ͼ
stmt.execute(queryStringWithUnknownResults);
while (true) {
int rowCount = stmt.getUpdateCount();
if (rowCount > 0) { // 它是更新计数
System.out.println("Rows changed = " + count);
stmt.getMoreResults();
continue;
}
if (rowCount == 0) { // DDL 命o?0 个更?
System.out.println(" No rows changed or statement was DDL
command");
stmt.getMoreResults();
continue;
}
// 执行到这里,证明有一个结果集
// 或没有其它结?
ResultSet rs = stmt.getResultSet;
if (rs != null) {
. . . // 使用元数据获得关于结果集列的信息
while (rs.next()) {
. . . // 处理l果
stmt.getMoreResults();
continue;
}
break; // 没有其它l果
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=630445
JDBCpd教程Q二Q?--驱动讄
DriverManager
本概q摘自《JDBCTM Database Access from JavaTM: A Tutorial and Annotated Reference》,目前正由 JavaSoft l箋~写。这本书既是 JDBC 的教E,也是一本权威性参考手册,作?Java pd的一部分?1997 q春季由 Addison-Wesley 出版公司出版。?
3.1 概述
DriverManager cL JDBC 的管理层Q作用于用户和驱动程序之间。它跟踪可用的驱动程序,q在数据库和相应驱动E序之间建立q接。另外,DriverManager cM处理诸如驱动E序d旉限制及登录和跟踪消息的显C等事务?
对于单的应用E序Q一般程序员需要在此类中直接用的唯一Ҏ(gu)?DriverManager.getConnection。正如名U所C,该方法将建立与数据库的连接。JDBC 允许用户调用 DriverManager 的方?getDriver、getDrivers ?registerDriver ?Driver 的方?connect。但多数情况下,?DriverManager cȝ理徏立连接的l节Z{?
3.1.1 跟踪可用驱动E序
DriverManager cd含一?Driver c,它们已通过调用Ҏ(gu) DriverManager.registerDriver 对自p行了注册。所?Driver c都必须包含有一个静态部分。它创徏该类的实例,然后在加载该实例?DriverManager c进行注册。这P用户正常情况下将不会直接调用 DriverManager.registerDriverQ而是在加载驱动程序时由驱动程序自动调用。加?Driver c,然后自动?DriverManager 中注册的方式有两U:
通过调用Ҏ(gu) Class.forName。这显式地加蝲驱动E序cR由于这与外部设|无养I因此推荐使用q种加蝲驱动E序的方法。以下代码加载类 acme.db.DriverQ?
Class.forName("acme.db.Driver");
如果?acme.db.Driver ~写为加载时创徏实例Qƈ调用以该实例为参数的 DriverManager.registerDriverQ本该如此)Q则它在 DriverManager 的驱动程序列表中Qƈ可用于创接?
通过驱动程序添加到 java.lang.System 的属?jdbc.drivers 中。这是一个由 DriverManager cd载的驱动E序cd的列表,由冒号分隔:初始?DriverManager cLQ它搜烦pȝ属?jdbc.driversQ如果用户已输入了一个或多个驱动E序Q则 DriverManager cd试图加蝲它们。以下代码说明程序员如何?~/.hotjava/properties 中输入三个驱动程序类Q启动时QHotJava 把它加载到pȝ属性列表中Q:
jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.test.ourDriver;
?DriverManager Ҏ(gu)的第一ơ调用将自动加蝲q些驱动E序cR?
注意Q加载驱动程序的W二U方法需要持久的预设环境。如果对q一点不能保证,则调用方?Class.forName 昑ּ地加载每个驱动程序就昑־更ؓ安全。这也是引入特定驱动E序的方法,因ؓ一?DriverManager c被初始化,它将不再?jdbc.drivers 属性列表?
在以上两U情况中Q新加蝲?Driver c都要通过调用 DriverManager.registerDriver c进行自我注册。如上所qͼ加蝲cL自动执行这一q程?
׃安全斚w的原因,JDBC 理层将跟踪哪个cd载器提供哪个驱动E序。这P?DriverManager cL开q接Ӟ它仅使用本地文gpȝ或与发出q接h的代码相同的cd载器提供的驱动程序?
3.1.2 建立q接
加蝲 Driver cdƈ?DriverManager cM注册后,它们卛_用来与数据库建立q接。当调用 DriverManager.getConnection Ҏ(gu)发出q接hӞDriverManager 检查每个驱动程序,查看它是否可以徏立连接?
有时可能有多?JDBC 驱动E序可以与给定的 URL q接。例如,与给定远E数据库q接Ӟ可以使用 JDBC-ODBC 桥驱动程序、JDBC 到通用|络协议驱动E序或数据库厂商提供的驱动程序。在q种情况下,试驱动E序的顺序至关重要,因ؓ DriverManager 用它所扑ֈ的第一个可以成功连接到l定 URL 的驱动程序?
首先 DriverManager 试图按注册的序使用每个驱动E序Qjdbc.drivers 中列出的驱动E序L先注册)。它?yu)蟩q代码不可信ȝ驱动E序Q除非加载它们的源与试图打开q接的代码的源相同?
它通过轮流在每个驱动程序上调用Ҏ(gu) Driver.connectQƈ向它们传递用户开始传递给Ҏ(gu) DriverManager.getConnection ?URL 来对驱动E序q行试Q然后连接第一个认 URL 的驱动程序?
q种Ҏ(gu)初看h效率不高Q但׃不可能同时加载数十个驱动E序Q因此每ơ连接实际只需几个q程调用和字W串比较?
以下代码是通常情况下用驱动E序Q例?JDBC-ODBC 桥驱动程序)建立q接所需所有步骤的CZQ?
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); //加蝲驱动E序
String url = "jdbc:odbc:fred";
DriverManager.getConnection(url, "userID", "passwd");
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=630442
JDBCpd教程Q一Q?--q接
q接
本概q是从《JDBCTM Database Access from JavaTM: A Tutorial and Annotated Reference 》这本书中摘引来的。JavaSoft 目前正在准备q本书。这本书是一本教E,同时也是 JDBC 的重要参考手册,它将作ؓ Java pd的组成部份在 1997 q春季由 Addison-Wesley 出版公司出版。?
2.1 概述
Connection 对象代表与数据库的连接。连接过E包括所执行?SQL 语句和在该连接上所q回的结果。一个应用程序可与单个数据库有一个或多个q接Q或者可与许多数据库有连接?
2.1.1 打开q接
与数据库建立q接的标准方法是调用 DriverManager.getConnection Ҏ(gu)。该Ҏ(gu)接受含有某个 URL 的字W串。DriverManager c(x谓的 JDBC 理层)尝试找到可与那?URL 所代表的数据库q行q接的驱动程序。DriverManager cd有已注册?Driver cȝ清单。当调用Ҏ(gu) getConnection Ӟ它将查清单中的每个驱动程序,直到扑ֈ可与 URL 中指定的数据库进行连接的驱动E序为止。Driver 的方?connect 使用q个 URL 来徏立实际的q接?
用户可绕q?JDBC 理层直接调?Driver Ҏ(gu)。这在以下特D情况下很有用Q当两个驱动器可同时q接到数据库中,而用户需要明地选用其中特定的驱动器。但一般情况下Q让 DriverManager cd理打开q接q种事将更ؓ单?
下述代码昄如何打开一个与位于 URL "jdbc:odbc:wombat" 的数据库的连接。所用的用户标识Wؓ "oboy" Q口令ؓ "12Java"Q?
String url = "jdbc:odbc:wombat";
Connection con = DriverManager.getConnection(url, "oboy", "12Java");
2.1.2 一般用法的 URL
׃ URL 常引h淆,我们先对一?URL 作简单说明,然后再讨?JDBC URL?
URLQ统一资源定位W)提供?Internet 上定位资源所需的信息。可它惌Z个地址?
URL 的第一部䆾指定了访问信息所用的协议Q后面L跟着冒号。常用的协议?"ftp"Q代表“文件传输协议”)?"http" Q代表“超文本传输协议”)。如果协议是 "file"Q表C源是在某个本地文件系l上而非?Internet 上(下例用于表示我们所描述的部分;它ƈ?URL 的组成部分)?
ftp://javasoft.com/docs/JDK-1_apidocs.zip
http://java.sun.com/products/jdk/CurrentRelease
file:/home/haroldw/docs/books/tutorial/summary.html
URL 的其余部份(冒号后面的)l出了数据资源所处位|的有关信息。如果协议是 fileQ则 URL 的其余部份是文g的\径。对?ftp ?http 协议QURL 的其余部份标识了Lq可选地l出某个更详的地址路径。例如,以下?JavaSoft 主页?URL。该 URL 只标识了LQ?
从该主页开始浏览,可以进到许多其它的|页中,其中之一是 JDBC 主页。JDBC 主页?URL 更ؓ具体Q它看v来类|
http://java.sun.com/products/jdbc
2.1.3 JDBC URL
JDBC URL 提供了一U标识数据库的方法,可以使相应的驱动E序能识别该数据库ƈ与之建立q接。实际上Q驱动程序编E员决定用什?JDBC URL 来标识特定的驱动E序。用户不必关心如何来形成 JDBC URLQ他们只M用与所用的驱动E序一h供的 URL 卛_。JDBC 的作用是提供某些U定Q驱动程序编E员在构造他们的 JDBC URL 时应该遵循这些约定?
׃ JDBC URL 要与各种不同的驱动程序一起用,因此q些U定应非常灵zR首先,它们应允怸同的驱动E序使用不同的方案来命名数据库。例如, odbc 子协议允许(但ƈ不是要求Q?URL 含有属性倹{?
W二QJDBC URL 应允讔R动程序编E员一切所需的信息编入其中。这样就可以让要与给定数据库对话?applet 打开数据库连接,而无要求用户去做Q何系l管理工作?
W三Q?JDBC URL 应允许某U程度的间接性。也是_JDBC URL 可指向逻辑L或数据库名,而这U逻辑L或数据库名将ql命名系l动态地转换为实际的名称。这可以使系l管理员不必特定主机声明ؓ JDBC 名称的一部䆾。网l命名服务(例如 DNS?NIS ?DCE Q有多种,而对于用哪U命名服务ƈ无限制?
JDBC URL 的标准语法如下所C。它׃部分l成Q各部分间用冒号分隔Q?
jdbc:< 子协?>:< 子名U?>
JDBC URL 的三个部分可分解如下Q?
jdbc ─ 协议。JDBC URL 中的协议L jdbc?
<子协?gt; ─ 驱动E序名或数据库连接机Ӟq种机制可由一个或多个驱动E序支持Q的名称。子协议名的典型CZ?"odbc"Q该名称是ؓ用于指定 ODBC 风格的数据资源名U的 URL 专门保留的。例如,Z通过 JDBC-ODBC 桥来讉K某个数据库,可以用如下所C的 URLQ?
jdbc:odbc:fred
本例中,子协议ؓ "odbc"Q子名称 "fred" 是本?
ODBC 数据资源?
如果要用|络命名服务Q这?JDBC URL 中的数据库名UC必是实际名称Q,则命名服务可以作为子协议。例如,可用如下所C的 URL Q?
jdbc:dcenaming:accounts-payable
本例中,?URL 指定了本?DCE 命名服务应该?
数据库名U?"accounts-payable" 解析为更为具体的
可用于连接真实数据库的名U?
<子名U?gt; ─ 一U标识数据库的方法。子名称可以依不同的子协议而变化。它q可以有子名U的子名Uͼ含有驱动E序~程员所选的M内部语法Q。用子名称的目的是为定位数据库提供_的信息。前例中Q因?ODBC 提供其余部份的信息Q因此用 "fred" 已_。然而,位于q程服务器上的数据库需要更多的信息。例如,如果数据库是通过 Internet 来访问的Q则?JDBC URL 中应网l地址作ؓ子名U的一部䆾包括q去Q且必须遵@如下所C的标准 URL 命名U定Q?
//L?端口/子协?
假设 "dbnet" 是个用于某个主接到 Internet 上的协议Q则 JDBC URL cMQ?
jdbc:dbnet://wombat:356/fred
2.1.4 "odbc" 子协?
子协?odbc 是一U特D情c它是ؓ用于指定 ODBC 风格的数据资源名U的 URL 而保留的Qƈh下列Ҏ(gu):允许在子名称Q数据资源名Uͼ后面指定L多个属性倹{odbc 子协议的完整语法为:
jdbc:odbc:< 数据资源名称 >[;< 属性名 >=< 属性?>]*
因此Q以下都是合法的 jdbc:odbc 名称Q?
jdbc:odbc:qeor7
jdbc:odbc:wombat
jdbc:odbc:wombat;CacheSize=20;ExtensionCase=LOWER
jdbc:odbc:qeora;UID=kgh;PWD=fooey
2.1.5 注册子协?
驱动E序~程员可保留某个名称以将之用?JDBC URL 的子协议名。当 DriverManager cd此名U加到已注册的驱动程序清单中ӞZ保留该名U的驱动E序应能识别该名Uƈ与它所标识的数据库建立q接。例如,odbc 是ؓ JDBC- ODBC 桥而保留的。示例之二,假设有个 Miracle 公司Q它可能会将 "miracle" 注册接到?Miracle DBMS 上的 JDBC 驱动E序的子协议Q从而其他人都无法使用q个名称?
JavaSoft 目前作ؓ非正式代理负责注?JDBC 子协议名U。要注册某个子协议名Uͼ请发送电(sh)子邮件到下述地址Q?
2.1.6 发?SQL 语句
q接一旦徏立,可用来向它所涉及的数据库传?SQL 语句。JDBC 对可被发送的 SQL 语句cd不加M限制。这提供了很大的灵zL,卛_怋用特定的数据库语句或甚至于非 SQL 语句。然而,它要求用戯p责确保所涉及的数据库可以处理所发送的 SQL 语句Q否则将自食其果。例如,如果某个应用E序试图向不支持储存E序?DBMS 发送储存程序调用,׃p|q将抛出异常。JDBC 要求驱动E序应至能提供 ANSI SQL-2 Entry Level 功能才可是W合 JDBC 标准TM 的。这意味着用户臛_可信赖这一标准U别的功能?
JDBC 提供了三个类Q用于向数据库发?SQL 语句。Connection 接口中的三个Ҏ(gu)可用于创些类的实例。下面列些类及其创徏Ҏ(gu)Q?
Statement ─ 由方?createStatement 所创徏。Statement 对象用于发送简单的 SQL 语句。?
PreparedStatement ─ 由方?prepareStatement 所创徏。PreparedStatement 对象用于发送带有一个或多个输入参数Q?IN 参数Q的 SQL 语句。PreparedStatement 拥有一l方法,用于讄 IN 参数的倹{执行语句时Q这?IN 参数被送到数据库中。PreparedStatement 的实例扩展了 Statement Q因此它们都包括?Statement 的方法。PreparedStatement 对象有可能比 Statement 对象的效率更高,因ؓ它已被预~译qƈ存放在那以供来使用。?
CallableStatement ─ 由方?prepareCall 所创徏。CallableStatement 对象用于执行 SQL 储存E序 ─ 一l可通过名称来调用(p函数的调用那P?SQL 语句。CallableStatement 对象?PreparedStatement 中承了用于处理 IN 参数的方法,而且q增加了用于处理 OUT 参数?INOUT 参数的方法。?
以下所列提供的Ҏ(gu)可以快速决定应用哪?Connection Ҏ(gu)来创Z同类型的 SQL 语句Q?
createStatement Ҏ(gu)用于Q?
单的 SQL 语句Q不带参敎ͼ
prepareStatement Ҏ(gu)用于Q?
带一个或多个 IN 参数?SQL 语句
l常被执行的?SQL 语句
prepareCall Ҏ(gu)用于Q?
调用已储存过E?
2.1.7 事务
事务׃个或多个q样的语句组成:q些语句已被执行、完成ƈ被提交或q原。当调用Ҏ(gu) commit ?rollback Ӟ当前事务卛_q束,另一个事务随卛_始?
~省情况下,新连接将处于自动提交模式。也是_当执行完语句后,自动对那个语句调用 commit Ҏ(gu)。这U情况下Q由于每个语句都是被单独提交的,因此一个事务只׃个语句组成。如果禁用自动提交模式,事务要{到 commit ?rollback Ҏ(gu)被显式调用时才结束,因此它将包括上一ơ调?commit ?rollback Ҏ(gu)以来所有执行过的语句。对于第二种情况Q事务中的所有语句将作ؓl来提交或还原?
Ҏ(gu) commit ?SQL 语句Ҏ(gu)据库所做的M更改成ؓ怹性的Q它q将释放事务持有的全部锁。而方?rollback 弃去那些更攏V?
有时用户在另一个更改生效前不想让此更改生效。这可通过用自动提交q将两个更新l合在一个事务中来达到。如果两个更新都是成功的Q则调用 commit Ҏ(gu)Q从而两个更新l果成ؓ怹性的Q如果其中之一或两个更新都p|了,则调?rollback Ҏ(gu)Q以值恢复ؓq行更新之前的倹{?
大多?JDBC 驱动E序都支持事务。事实上Q符?JDBC 的驱动程序必L持事务。DatabaseMetaData l出的信息描q?DBMS 所提供的事务支持水q?
2.1.8 事务隔离U别
如果 DBMS 支持事务处理Q它必须有某U途径来管理两个事务同时对一个数据库q行操作时可能发生的冲突。用户可指定事务隔离U别Q以指明 DBMS 应该花多大精力来解决潜在冲突。例如,当事务更改了某个D第二个事务却在该更改被提交或还原前d该值时该怎么办? 假设W一个事务被q原后,W二个事务所d的更改值将是无效的Q那么是否可允许q种冲突Q?JDBC 用户可用以下代码来指C?DBMS 允许在D提交前读取该|“dirty d”)Q其?con 是当前连接:
con.setTransactionIsolation(TRANSACTION_READ_UNCOMMITTED);
事务隔离U别高Qؓ避免冲突所q_֊也就多。Connection 接口定义了五U,其中最低别指定了Ҏ(gu)׃支持事务Q而最高别则指定当事务在Ҏ(gu)个数据库q行操作ӞM其它事务不得寚w个事务正在读取的数据q行M更改。通常Q隔ȝ别越高,应用E序执行的速度也就慢Q由于用于锁定的资源耗费增加了,而用户间的ƈ发操作减了Q。在军_采用什么隔ȝ别时Q开发h员必d性能需求和数据一致性需求之间进行权衡。当Ӟ实际所能支持的U别取决于所涉及?DBMS 的功能?
当创?Connection 对象Ӟ其事务隔ȝ别取决于驱动E序Q但通常是所涉及的数据库的缺省倹{用户可通过调用 setIsolationLevel Ҏ(gu)来更改事务隔ȝ别。新的别将在该q接q程的剩余时间内生效。要惛_改变一个事务的事务隔离U别Q必d该事务开始前q行讄Qƈ在该事务l束后进行复位。我们不提倡在事务的中途对事务隔离U别q行更改Q因立卌?commit Ҏ(gu)的调用,使在此之前所作的M更改变成怹性的。?
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=630439
JavaE序员的存储q程
--------------------------------------------------------------------------------
原文Q?a >http://www.onjava.com/pub/a/onjava/2003/08/13/stored_procedures.html
by Nic Ferrier
本文阐述了怎么使用DBMS存储q程。我阐述了用存储过E的基本的和高Ҏ(gu),比如q回ResultSet。本文假设你对DBMS和JDBC已经非常熟?zhn)Q也假设你能够毫无障地阅读其它语言写成的代码(即不是Java的语aQ,但是Qƈ不要求你有Q何存储过E的~程l历?
存储q程是指保存在数据库q在数据库端执行的程序。你可以使用Ҏ(gu)的语法在JavacM调用存储q程。在调用Ӟ存储q程的名U及指定的参数通过JDBCq接发送给DBMSQ执行存储过Eƈ通过q接Q如果有Q返回结果?
使用存储q程拥有和用基于EJB或CORBAq样的应用服务器一L好处。区别是存储q程可以从很多流行的DBMS中免费用,而应用服务器大都非常昂贵。这q不只是许可证费用的问题。用应用服务器所需要花费的理、编写代码的费用Q以及客L序所增加的复杂性,都可以通过DBMS中的存储q程所整个地替代?
你可以用JavaQPythonQPerl或C~写存储q程Q但是通常使用你的DBMS所指定的特定语a。Oracle使用PL/SQLQPostgreSQL使用pl/pgsqlQDB2使用Procedural SQL。这些语a都非常相伹{在它们之间UL存储q程q不比在Sun的EJB规范不同实现版本之间ULSession Bean困难。ƈ且,存储q程是ؓ嵌入SQL所设计Q这使得它们比Java或C{语a更加友好地方式表达数据库的机制?
因ؓ存储q程q行在DBMS自nQ这可以帮助减少应用E序中的{待旉。不是在Java代码中执?个或5个SQL语句Q而只需要在服务器端执行1个存储过E。网l上的数据往q次数的减少可以戏剧性地优化性能?
使用存储q程
单的老的JDBC通过CallableStatementcL持存储过E的调用。该cd际上是PreparedStatement的一个子cR假设我们有一个poets数据库。数据库中有一个设|诗人逝世q龄的存储过E。下面是对老酒鬼Dylan ThomasQold soak Dylan ThomasQ不指定是否有关典故、文化,h评指正。译注)q行调用的详l代码:
try
{
int age = 39;
String poetName = "dylan thomas";
CallableStatement proc =
connection.prepareCall("{ call set_death_age(?, ?) }");
proc.setString(1, poetName);
proc.setInt(2, age);
cs.execute();
}
catch (SQLException e)
{
// ....
}
传给prepareCallҎ(gu)的字串是存储q程调用的书写规范。它指定了存储过E的名称Q?代表了你需要指定的参数?
和JDBC集成是存储过E的一个很大的便利Qؓ了从应用中调用存储过E,不需要存根(stubQ类或者配|文Ӟ除了你的DBMS的JDBC驱动E序外什么也不需要?
当这D代码执行时Q数据库的存储过E就被调用。我们没有去获取l果Q因存储q程q不q回l果。执行成功或p|通过例外得知。失败可能意味着调用存储q程时的p|Q比如提供的一个参数的cd不正)Q或者一个应用程序的p|Q比如抛Z个例外指C在poets数据库中q不存在“Dylan Thomas”)
l合SQL操作与存储过E?
映射Java对象到SQL表中的行相当单,但是通常需要执行几个SQL语句Q可能是一个SELECT查找IDQ然后一个INSERT插入指定ID的数据。在高度规格化(W合更高的范式,译注Q的数据库模式中Q可能需要多个表的更斎ͼ因此需要更多的语句。Java代码会很快地膨胀Q每一个语句的|络开销也迅速增加?
这些SQL语句转移C个存储过E中大大简化代码,仅涉及一ơ网l调用。所有关联的SQL操作都可以在数据库内部发生。ƈ且,存储q程语言Q例如PL/SQLQ允怋用SQL语法Q这比Java代码更加自然。下面是我们早期的存储过E,使用Oracle的PL/SQL语言~写Q?
create procedure set_death_age(poet VARCHAR2, poet_age NUMBER)
poet_id NUMBER;
begin
SELECT id INTO poet_id FROM poets WHERE name = poet;
INSERT INTO deaths (mort_id, age) VALUES (poet_id, poet_age);
end set_death_age;
很独特?不。我打赌你一定期待看C个poets表上的UPDATE。这也暗CZ使用存储q程实现是多么容易的一件事情。set_death_age几乎可以肯定是一个很烂的实现。我们应该在poets表中d一列来存储逝世q龄。Java代码中ƈ不关心数据库模式是怎么实现的,因ؓ它仅调用存储q程。我们以后可以改变数据库模式以提高性能Q但是我们不必修Ҏ(gu)们代码?
下面是调用上面存储过E的Java代码Q?
public static void setDeathAge(Poet dyingBard, int age)
throws SQLException
{
Connection con = null;
CallableStatement proc = null;
try
{
con = connectionPool.getConnection();
proc = con.prepareCall("{ call set_death_age(?, ?) }");
proc.setString(1, dyingBard.getName());
proc.setInt(2, age);
proc.execute();
}
finally
{
try
{
proc.close();
}
catch (SQLException e) {}
con.close();
}
}
Z保可维护性,使用像这儿这LstaticҎ(gu)。这也得调用存储过E的代码集中在一个简单的模版代码中。如果你用到许多存储q程Q就会发C需要拷贝、粘贴就可以创徏新的Ҏ(gu)。因Z码的模版化,甚至也可以通过脚本自动生调用存储q程的代码?
Functions
存储q程可以有返回|所以CallableStatementcLcMgetResultSetq样的方法来获取q回倹{当存储q程q回一个值时Q你必须使用registerOutParameterҎ(gu)告诉JDBC驱动器该值的SQLcd是什么。你也必调整存储过E调用来指示该过E返回一个倹{?
下面接着上面的例子。这ơ我们查询Dylan Thomas逝世时的q龄。这ơ的存储q程使用PostgreSQL的pl/pgsqlQ?
create function snuffed_it_when (VARCHAR) returns integer '
declare
poet_id NUMBER;
poet_age NUMBER;
begin
-- first get the id associated with the poet.
SELECT id INTO poet_id FROM poets WHERE name = $1;
-- get and return the age.
SELECT age INTO poet_age FROM deaths WHERE mort_id = poet_id;
return age;
end;
' language 'pl/pgsql';
另外Q注意pl/pgsql参数名通过Unix和DOS脚本?n语法引用。同Ӟ也注意嵌入的注释Q这是和Java代码相比的另一个优性。在Java中写q样的注释当然是可以的,但是看v来很凌ؕQƈ且和SQL语句pQ必d入到Java String中?
下面是调用这个存储过E的Java代码Q?
connection.setAutoCommit(false);
CallableStatement proc =
connection.prepareCall("{ ? = call snuffed_it_when(?) }");
proc.registerOutParameter(1, Types.INTEGER);
proc.setString(2, poetName);
cs.execute();
int age = proc.getInt(2);
如果指定了错误的q回值类型会怎样Q那么,当调用存储过E时抛Z个RuntimeExceptionQ正如你在ResultSet操作中用了一个错误的cd所到的一栗?
复杂的返回?
关于存储q程的知识,很多人好像就熟?zhn)我们所讨论的这些。如果这是存储过E的全部功能Q那么存储过E就不是其它q程执行机制的替换方案了。存储过E的功能比这强大得多?
当你执行一个SQL查询ӞDBMS创徏一个叫做cursorQ游标)的数据库对象Q用于在q回l果中P代每一行。ResultSet是当前时间点的游标的一个表C。这是Z么没有缓存或者特定数据库的支持,你只能在ResultSet中向前移动?
某些DBMS允许从存储过E中q回游标的一个引用。JDBCq不支持q个功能Q但是Oracle、PostgreSQL和DB2的JDBC驱动器都支持在ResultSet上打开到游标的指针QpointerQ?
设想列出所有没有活到退休年龄的诗hQ下面是完成q个功能的存储过E,q回一个打开的游标,同样也用PostgreSQL的pl/pgsql语言Q?
create procedure list_early_deaths () return refcursor as '
declare
toesup refcursor;
begin
open toesup for
SELECT poets.name, deaths.age
FROM poets, deaths
-- all entries in deaths are for poets.
-- but the table might become generic.
WHERE poets.id = deaths.mort_id
AND deaths.age < 60;
return toesup;
end;
' language 'plpgsql';
下面是调用该存储q程的JavaҎ(gu)Q将l果输出到PrintWriterQ?
PrintWriter:
static void sendEarlyDeaths(PrintWriter out)
{
Connection con = null;
CallableStatement toesUp = null;
try
{
con = ConnectionPool.getConnection();
// PostgreSQL needs a transaction to do this...
con.setAutoCommit(false);
// Setup the call.
CallableStatement toesUp
= connection.prepareCall("{ ? = call list_early_deaths () }");
toesUp.registerOutParameter(1, Types.OTHER);
getResults.execute();
ResultSet rs = (ResultSet) getResults.getObject(1);
while (rs.next())
{
String name = rs.getString(1);
int age = rs.getInt(2);
out.println(name + " was " + age + " years old.");
}
rs.close();
}
catch (SQLException e)
{
// We should protect these calls.
toesUp.close();
con.close();
}
}
因ؓJDBCq不直接支持从存储过E中q回游标Q我们用Types.OTHER来指C存储过E的q回cdQ然后调用getObject()Ҏ(gu)q对q回D行强制类型{换?
q个调用存储q程的JavaҎ(gu)是mapping的一个好例子。Mapping是对一个集上的操作q行抽象的方法。不是在q个q程上返回一个集Q我们可以把操作传送进L行。本例中Q操作就是把ResultSet打印C个输出流。这是一个值得举例的很常用的例子,下面是调用同一个存储过E的另外一个方法实玎ͼ
public class ProcessPoetDeaths
{
public abstract void sendDeath(String name, int age);
}
static void mapEarlyDeaths(ProcessPoetDeaths mapper)
{
Connection con = null;
CallableStatement toesUp = null;
try
{
con = ConnectionPool.getConnection();
con.setAutoCommit(false);
CallableStatement toesUp
= connection.prepareCall("{ ? = call list_early_deaths () }");
toesUp.registerOutParameter(1, Types.OTHER);
getResults.execute();
ResultSet rs = (ResultSet) getResults.getObject(1);
while (rs.next())
{
String name = rs.getString(1);
int age = rs.getInt(2);
mapper.sendDeath(name, age);
}
rs.close();
}
catch (SQLException e)
{
// We should protect these calls.
toesUp.close();
con.close();
}
}
q允许在ResultSet数据上执行Q意的处理Q而不需要改变或者复制获取ResultSet的方法:
static void sendEarlyDeaths(final PrintWriter out)
{
ProcessPoetDeaths myMapper = new ProcessPoetDeaths()
{
public void sendDeath(String name, int age)
{
out.println(name + " was " + age + " years old.");
}
};
mapEarlyDeaths(myMapper);
}
q个Ҏ(gu)使用ProcessPoetDeaths的一个匿名实例调用mapEarlyDeaths。该实例拥有sendDeathҎ(gu)的一个实玎ͼ和我们上面的例子一L方式把结果写入到输出。当Ӟq个技巧ƈ不是存储q程Ҏ(gu)的,但是和存储过E中q回的ResultSetl合使用Q是一个非常强大的工具?
l论
存储q程可以帮助你在代码中分逻辑Q这基本上L有益的。这个分ȝ好处有:
• 快速创建应用,使用和应用一h变和改善的数据库模式。?
• 数据库模式可以在以后改变而不影响Java对象Q当我们完成应用后,可以重新设计更好的模式?
• 存储q程通过更好的SQL嵌入使得复杂的SQL更容易理解?
• ~写存储q程比在Java中编写嵌入的SQL拥有更好的工PQ大部分~辑器都提供语法高亮Q?
• 存储q程可以在Q何SQL命o行中试Q这使得调试更加Ҏ(gu)?
q不是所有的数据库都支持存储q程Q但是存在许多很的实现Q包括免?开源的和非免费的,所以移植ƈ不是一个问题。Oracle、PostgreSQL和DB2都有cM的存储过E语aQƈ且有在线的社区很好地支持?
存储q程工具很多Q有像TOAD或TORAq样的编辑器、调试器和IDEQ提供了~写、维护PL/SQL或pl/pgsql的强大的环境?
存储q程实增加了你的代码的开销Q但是它们和大多数的应用服务器相比,开销得多。如果你的代码复杂到需要用DBMSQ我整个采用存储q程的方式?
资源
• JDBC specification
• PostgreSQL
• Oracle Corporation's Oracle database server
• IBM's DB2 database server
作者简介:Nic Ferrier 是Web应用斚w的独立Y仉问。?
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=629847
谈谈JDBC接口技?/span>
--------------------------------------------------------------------------------
JDBC是一U可用于执行SQL语句的JavaAPIQApplicationProgrammingInterface应用E序设计接口Q。它׃些Java语言~写的类和界面组成。JDBC为数据库应用开发h员、数据库前台工具开发h员提供了一U标准的应用E序设计接口Q开发h员可以用UJava语言~写完整的数据库应用E序。?
一、ODBC到JDBC的发展历E?
说到JDBCQ很Ҏ(gu)让h联想到另一个十分熟(zhn)的字眼“ODBC”。它们之间有没有联系呢?如果有,那么它们之间又是怎样的关pdQ?
ODBC是OpenDatabaseConnectivity的英文简写。它是一U用来在相关或不相关的数据库理pȝQDBMSQ中存取数据的,用C语言实现的,标准应用E序数据接口。通过ODBCAPIQ应用程序可以存取保存在多种不同数据库管理系l(DBMSQ中的数据,而不论每个DBMS使用了何U数据存储格式和~程接口。?
1QODBC的结构模型?
ODBC的结构包括四个主要部分:应用E序接口、驱动器理器、数据库驱动器和数据源。?
应用E序接口Q屏蔽不同的ODBC数据库驱动器之间函数调用的差别,为用h供统一的SQL~程接口。?
驱动器管理器Qؓ应用E序装蝲数据库驱动器。?
数据库驱动器Q实现ODBC的函数调用,提供对特定数据源的SQLh。如果需要,数据库驱动器修改应用程序的hQ得请求符合相关的DBMS所支持的文法。?
数据源:qh要存取的数据以及与它相关的操作系l、DBMS和用于访问DBMS的网l^台组成。?
虽然ODBC驱动器管理器的主要目的是加蝲数据库驱动器Q以便ODBC函数调用Q但是数据库驱动器本w也执行ODBC函数调用Qƈ与数据库怺配合。因此当应用pȝ发出调用与数据源q行q接Ӟ数据库驱动器能管理通信协议。当建立起与数据源的q接Ӟ数据库驱动器便能处理应用pȝ向DBMS发出的请求,对分析或发自数据源的设计q行必要的翻译,q将l果q回l应用系l。?
2QJDBC的诞生?
自从Java语言?995q?月正式公布以来,Java风靡全球。出现大量的用java语言~写的程序,其中也包括数据库应用E序。由于没有一个Java语言的APIQ编Eh员不得不在JavaE序中加入C语言的ODBC函数调用。这׃很多Java的优UҎ(gu)无法充分发挥,比如q_无关性、面向对象特性等。随着来多的编Eh员对Java语言的日益喜爱,来多的公司在JavaE序开发上投入的精力日益增加,对java语言接口的访问数据库的API的要求越来越强烈。也׃ODBC的有其不之处,比如它ƈ不容易用,没有面向对象的特性等{,SUN公司军_开发一Java语言为接口的数据库应用程序开发接口。在JDK1Qx版本中,JDBC只是一个可选部ӞCJDK1Q?公布ӞSQLcdQ也是JDBCAPIQ就成ؓJava语言的标准部件。?
二、JDBC技术概qW?
JDBC是一U可用于执行SQL语句的JavaAPIQApplicationProgrammingInterfaceQ应用程序设计接口)。它׃些Java语言写的cR界面组成。JDBCl数据库应用开发h员、数据库前台工具开发h员提供了一U标准的应用E序设计接口Q开发h员可以用UJava语言~写完整的数据库应用E序。?
通过使用JDBCQ开发h员可以很方便地将SQL语句传送给几乎M一U数据库。也是_开发h员可以不必写一个程序访问SybaseQ写另一个程序访问OracleQ再写一个程序访问Microsoft的SQLServer。用JDBC写的E序能够自动地将SQL语句传送给相应的数据库理pȝQDBMSQ。不但如此,使用Java~写的应用程序可以在M支持Java的^Cq行Q不必在不同的^C~写不同的应用。Java和JDBC的结合可以让开发h员在开发数据库应用时真正实现“WriteOnceQRunEverywhereQ”?
Javah健壮、安全、易用等Ҏ(gu),而且支持自动|上下蝲Q本质上是一U很好的数据库应用的~程语言。它所需要的是Java应用如何同各U各L数据库连接,JDBC正是实现q种q接的关键。?
JDBC扩展了Java的能力,如用Java和JDBCAPI可以公布一个Web,中带有能访问远端数据库的Ap?plet。或者企业可以通过JDBC让全部的职工Q他们可以用不同的操作pȝQ如WindwosQMachintosh和UNIXQ在In?tranet上连接到几个全球数据库上Q而这几个全球数据库可以是不相同的。随着来多的程序开发h员用Java语言Q对Java讉K数据库易操作性的需求越来越强烈。?
MIS理人员喜欢Java和JDBCQ因样可以更Ҏ(gu)l济地公布信息。各U已l安装在数据库中的事务处理都l正常运行,甚至q些事务处理是存储在不同的数据库理pȝ中;而对新的数据库应用来_开发时间将~短Q安装和版本升大大简化。程序员可以~写或改写一个程序,然后它攑֜服务器上Q而每个用户都可以讉K服务器得到最新的版本。对于信息服务行业,Java和JDBC提供了一U很好的向外界用hC息的Ҏ(gu)。?
1QJDBC的Q务?
单地_JDBC能完成下列三件事Q?
1Q同一个数据库建立q接Q?
2Q向数据库发送SQL语句Q?
3Q处理数据库q回的结果。?
2QJDBC一U底层的API
JDBC是一U底层APIQ这意味着它将直接调用SQL命o。JDBC完全胜Qq个dQ而且比其他数据库互联更加Ҏ(gu)实现。同时它也是构造高层API和数据库开发工L基础。高层API和数据库开发工具应该是用户界面更加友好Q用更加方便,更易于理解的。但所有这LAPI最l被译JDBCq样的底层API。目前两U基于JDBC的高层API正处在开发阶Dc?
1QSQL语言嵌入Java的预处理器。虽然DBMS已经实现了SQL查询Q但JDBC要求SQL语句被当作字W串参数传送给JavaE序。而嵌入式SQL预处理器允许E序员将SQL语句LQJava变量可以在SQL语句中用,来接收或提供数倹{然后SQL的预处理器将把这UJavaQSQLL的程序翻译成带有JDBCAPI的JavaE序。?
2Q实C关系数据库到Javacȝ直接映射。Javasoft和其他公司已l宣布要实现q一技术。在q种“对象/关系”映中Q表的每一行都变成这cȝ一个实例,每一列的值对应实例的一个属性。程序员可以直接操作Java的对象;而存取所需要的SQL调用在内部直接产生。还可以实现更加复杂的映,比如多张表的行在一个Java的类中实现。?
随着大家对JDBC兴趣的不断浓厚,来多的开发h员已l开始利用JDBC为基的工兯行开发。这使开发工作变得容易。同ӞE序员也正在开发对最l用h说访问数据库更加Ҏ(gu)的应用程序。?
3QJDBC和ODBC及其他API的比较?
到目前ؓ止,微Y的ODBC可能是用得最q泛的访问关pL据库的API。它提供了连接几乎Q何一U^台、Q何一U数据库的能力。那么,Z么不直接从Java中直接用ODBC呢?
回答是可以从Java中用ODBCQ但最好在JDBC的协助下Q用JDBCQODBC桥接器实现。那么,Z么需要JDBC呢?要回{这个问题,有这么几个方面:
1QODBCq不适合在Java中直接用。ODBC是一个C语言实现的APIQ从JavaE序调用本地的CE序会带来一pdcM安全性、完整性、健壮性的~点。?
2Q其ơ,完全_地实CC代码ODBC到JavaAPI写的ODBC的翻译也q不令h满意。比如,Java没有指针Q而ODBC中大量地使用了指针,包括极易出错的空指针“voidQ”。因此,对JavaE序员来_把JDBC设想成将ODBC转换成面向对象的API是很自然的。?
3QODBCq不Ҏ(gu)学习Q它?yu)简单特性和复杂Ҏ(gu)杂在一P甚至寚w常简单的查询都有复杂的选项。而JDBC刚好相反Q它保持了简单事物的单性,但又允许复杂的特性。?
4QJDBCq样的JavaAPI对于UJavaҎ(gu)来说是必ȝ。当使用ODBCӞZ必须在每一台客h上安装ODBC驱动器和驱动理器。如果JDBC驱动器是完全用Java语言实现的话Q那么JDBC的代码就可以自动的下载和安装Qƈ保证其安全性,而且Q这适应MJavaq_Q从|络计算机NC到大型主机Mainframe。?
总而言之,JDBCAPI是能体现SQL最基本抽象概念的、最直接的Java接口。它建构在ODBC的基上,因此Q熟(zhn)ODBC的程序员发现学习JDBC非常Ҏ(gu)。JDBC保持了ODBC的基本设计特征。实际上Q这两种接口都是ZXQOPENSQL的调用接口QCLIQ。它们的最大的不同是JDBC是基于Java的风格和优点Qƈ强化了Java的风格和优点。?
最q,微Y又推Z除了ODBC以外的新的APIQ如RDOQADO和OLEDB。这些API事实上在很多斚w上同JDBC一h着相同的方向努力,也就是努力成Z个面向对象的Q基于ODBC的类接口。然而,q些接口目前q不能代替ODBCQ尤其在ODBC驱动器已l在市场完全形成的时候,更重要的是它们只是ODBC的“漂亮的包装”。?
4QJDBC两层模型和三层模型?
JDBC支持两层模型Q也支持三层模型讉K数据库?两层模型中,一个java Appple或者一个JAQva应用直接同数据库q接。这需要能直接被访问的数据库进行连接的JDBC驱动器。用LSQL语句被传送给数据库,而这些语句执行的l果被传回l用戗数据库可以在同一机器上,也可以另一机器上通过|络q行q接。这被称为“Client/Server”结构,用户的计机作ؓClient,q行数据库的计算Z为Server。这个网l可是intranetQ比如连接全体雇员的企业内部|,当然也可以是internet。?
在三层模型中Q命令将被发送到服务的“中间层”,而“中间层”将SQL语句发送到数据库。数据库处理SQL语句q将l果q回“中间层”,然后“中间层”将它们 q回用户。MIS理员将发现三层模型很有吸引力,因ؓ“中间层”可以进行对讉K的控制ƈ协同数据库的更新Q另一个优势就是如果有一个“中间层”用户就可以使用一个易用的高层的APIQ这个API可以由“中间层”进行{换,转换成底层的调用。而且Q在许多情况下,三层模型可以提供更好的性能。?
到目前ؓ止,“中间层”通常q是用C或C++实现Q以保证光性能。但随着优化~译器的引入Q将java的字节码转换成高效的机器码,用java来实现“中间层”将来实际。而JDBC是允总一个java“中间层”访问数据库的关键?
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=629840
JDBC 4.0规范之目?/span>
--------------------------------------------------------------------------------
历史
JDBC API是一U成熟的技术,最早发布是1997q?月。在最初的版本中,JDBC API着重提供一个对SQL数据库的基本调用U接口。之后,JDBC 2.1规范?.0可选包规范拓宽了API的范围。包括支持更高应用和管理用JDBC API来增强其应用的应用服务所需的各特征?/p>
JDBC 3.0规范以填补较?yu)范围内的功能缺׃ؓ目标。对于JDBC 4.0Q我们的目标有两个:提高所有开发者在JAVAq_使用SQL开发的易用性。第二,提供企业U特性的JDBC工具集和API来管理JDBC资源?
目标概述
下面列出了一般的JDBC API和JDBC 4.0 API的目标和设计原理Q?/p>
1.适合J2EE和J2SEq_
JDBC API是JAVAq_的重要技术。JDBC 4.0 API应遵循JAVA 2 企业版和JAVA 2 标准版^台的M方向。另外,最q开发的JAVA 5.0q_已经展示Zpd新的Ҏ(gu)和语言的改q,q在本规范中q泛使用?/p>
2.兼容SQL:2003
JDBC API提供用JAVA~程语言~写标准SQL来对应用q行E序U访问能力。JDBC 3.0致力于确保其可以支持可广泛支持工业的hSQL:99特征的子集。对于JDBC 4.0也一P支持SQL:2003是本规范的一个主要组成部分。我们期望在不久的将来可以实现?/p>
3.巩固以前的规?/p>
本文档把4个以前的JDBC规范l织成一个单一的JDBC API规范?/p>
4.提供中立于开发商的一般访问特?/p>
JDBC API致力于提供支持针对不同开发商应用的高带宽的一般访问特征。其目标是提供与原生应用可以辑ֈ的同U别的访问特性。然而,本API必须_通用和灵zM适应大范围的实施?/p>
5.x于SQL
JDBC API一直关注于用JAVA~程语言讉K相关数据。这个目标曾在JDBC 3.0 API规范中说明,在本规范中仍是一个主要原则。提供API和工h改进开发难度,ql集中于在JAVAq_开发基于SQL的Y件的需要。与以前的规范相|本规范也不阻止与其它技术进行交互,如XMLQCORBA和非关系型数据?/p>
6.提供基础数据和更高别的API
JDBC API提供标准API访各U数据源或旧pȝ。实施的差异佉K过JDBC API抽象透明化。这使其成ؓҎ(gu)开发可Ud工具和应用的工具开发商来说Q一个有价值的目标q_?/p>
׃它是一个用JAVA~程语言对SQL的“调用”接口Q所以JDBC API也适用于更高别应用的底层Q如EJB 3.0容器理的持久性,SQLJ和JDBC的RowSet实现?/p>
7.保持?/p>
JDBC API意欲成ؓ一U用简单、直接的接口。在之上可以构徏更多复杂的实体。这个目标通过定义大量紧凑、单一目的Ҏ(gu)来代替少数带有控制标识参数的复杂、多目的的方法来实现?/p>
8.增强可靠性、可用行和可?/p>
可靠性、可用行和可性是J2EE和J2SEq_的主题,也是未来JAVAq_的主题。JDBC 4.0 API严格按照以上目标q行。它扩展支持了一些领域,包括资源理、对逻辑q接预备声明的复用和错误处理?/p>
9.支持对已有应用和驱动的向后兼?/p>
使用已有JDBC技术的驱动和应用必能够在支持JDBC 4.0 API的JAVA虚拟Zl箋工作。那些只使用更早版本中定义的JDBC APIQ不包括在JDBC 2.0中已废除的)的应用,应该不需要修改就可以l箋q行。已有的应用应该可以直接q移到JDBC 4.0技术?/p>
10.与JDBC RowSet工具紧密联系
J2SE 5.0包含一个标准JDBC RowSet工具Q在《JDBC RowSet工具集》中说明QJSR-114Q)。本规范会提供一个工具集包括工具cȝ别和元数据语aU别的工兗它允许开发者轻易的把用JDBC技术的应用q移到JDBC RowSet模型。该模型可以断开数据源访问连接,另外能够理来自于XMLȝ点的关系数据存储?/p>
11.允许对连接器的向前兼?/p>
q接器构架定义了一个标准方法来对资源适配器进行打包和布v。它允许一个J2EE容器整合它与外部资源的连接、处理和安全理。JDBC 4.0 API提供JDBC驱动到连接器架构的迁U\径。对那些产品中用JDBC技术的开发商来说Q应可以转向对连接器API的实现。希望这些实C重新包装已有数据源的实现。这样他们可以对q接器框架进行复用?
12.清晰的列明需?/p>
遵从JDBC要求的需求,要明和易于识别。JDBC 4.0规范和API文档QJavadocQ会明晰什么特性是需要的Q什么特性是可选的?/p>
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=629584
?大部分站友的jbuilderq接oracle的问题都是由于没有正配|classpath{引L?/p>
在windows下配|Oracle_XA时要注意两点Q?/p>
#ORACLE 10
Oracle_XA;xaosw;%ORACLE_HOME% dbms oraxa10.lib%ORACLE_HOME%precompibmsvcorasql10.lib
#oracle 9
Oracle_XA;xaosw;%ORACLE_HOME% dbms oraxa9.lib%ORACLE_HOME%precompibmsvcorasql9.lib
Unix?br />Oracle_XA:xaosw:....
W一Q在windows ?ORACLE_XA 和xaosw后面的是分号";"Q不是冒?:"
W二Q上面的q些LIB写在一行上Q中间用I格分开Q如果没有在pȝ的环境变量中讄ORACLE_HOMEQ就写绝对\径?/p>
可能是服务器的监听停掉了Q是数据库的问题Q与应用无关Q应该先查一下oracle是否正常Q用sql*plusq接一下数据库Q看能否正常q接Q?/p>
使用HP-UNIXQWeblogic 8.1,Oracle 9.2.0.5
配置了一个普通的q接?驱动E序采用oracle的Oracle’s Driver(Thin) version 9.0.1, 9.2.0
错误情况Q?br />l果使用数据库连接池时报错,说没有连接池资源了。实际上数据库的q接池完全空Ԍq且试也是对的QOracle也是正常可以q接、用的?/p>
问题Ҏ(gu)Q?br />通过层层排错Q发现原来后台在使用Oracle的exp备䆾一个只有同义词的用PDexpq程僉|?br />杀死exp、重启Oracle{无法解决问题,最l重启UNIXQ禁止备份只有同义词的用P问题解决?/p>
ȝQ?br />应该是Oracle9的exp BUGDq接池问题,不要使用exp倒出同义?/p>
Oracle Database Connection (from oracle.com)
PROBLEM
You are attempting to connect to an Oracle instance using JDBC and you are receiving the following error.
java.sql.SQLException: Io exception:
The Network Adapter could not establish connection
SQLException: SQLState (null) vendor code (17002)
Any or all of the following conditions may also apply:
1) You are able to establish a SQL*Plus connection from the same
client to the same Oracle instance.
2) You are able to establish a JDBC OCI connection, but not a Thin
connection from the same client to the same Oracle instance.
3) The same JDBC application is able to connect from a different
client to the same Oracle instance.
4) The same behavior applies whether the initial JDBC connection
string specifies a hostname or an IP address.
REDISCOVERY
To verify whether you are hitting this problem, verify whether the Oracle instance is configured for Multithreaded Server (MTS). If the Oracle instance is not configured for MTS, you are probably encountering a different problem. Otherwise, continue. Try forcing the JDBC connection to use a dedicated server instead of a shared server. This can be accomplished in several ways. For JDBC OCI or Thin, this can be done by reconfiguring the server for dedicated connections only. This approach, however, may not be feasible in many cases. In such cases, the following options apply: For JDBC OCI:
1) Add the (SERVER=DEDICATED) property to the TNS connect string
stored in the tnsnames.ora file on the client.
2) Set the user_dedicated_server=ON in sqlnet.ora on the client.
For JDBC Thin:
You must specify a full name-value pair connect string (the same as it might appear in the tnsnames.ora file) instead of the short JDBC Thin syntax. For example, instead of
"jdbc:oracle:thin::port:sid"
you would need to use a string of the form
"jdbc:oracle:thin:@(DESCRIPTION=" +
"(ADDRESS_LIST=" +
"(ADDRESS=(PROTOCOL=TCP)" +
"(HOST=host)" + =
"(PORT=port)" +
")" +
")" +
"(CONNECT_DATA=" +
"(SERVICE_NAME=sid)" +
"(SERVER=DEDICATED)" +
")" +
")"
If the connection works fine after having made these changes, it is very likely that this is the problem you are encountering. In this case, one last test will help to verify this fact.
Log into the remote host on which the Oracle instance is running and execute the appropriate command to determine what the server 'thinks' its hostname is (i.e. the name that was configured when the server was installed and configured). For example, on a Unix host the 'hostname' command can be used for this purpose.
Using the name displayed (e.g. by the hostname command), exactly as it appeared (i.e. if the output from the hostname command had the domain name included, then include it), return to the client which was unable to connect and try pinging the server.
NOTE: It is critical that you attempt to ping the server using EXACTLY the same hostname you got from the server.
If you are unable to ping the server via this hostname, then you almost certainly hitting this problem. If not, this may be a new issue, but at least you will have found a workaround (i.e. use a dedicated connection).
EXPLANATION
To understand why this problem occurs, one must first understand the differences in how the listener handles connections to shared servers versus dedicated servers.
When connecting to a dedicated server, the client connects to the listener (via hostname or IP address). The listener then spawns a dedicated server process and hands off the socket used to accept the client connection to that server. The client and server then start communicating via the endpoints established by the initial connection. NOTE: There is only one connection in this case. When connecting to a shared server, the initial client connection to the listener is the same. However, with MTS, there is no need to spawn a new server process; a pool of shared processes already exists. Also, clients do not communicate directly with the server processes in MTS; rather, they communicate with a dispatcher.
For this reason, when setting up an MTS connection, the listener sends a redirect message back to the client asking the client to close the connection to the listener and connect to a dispatcher. The information in this message includes the hostname and a port number for the appropriate dispatcher. The redirect message will ALWAYS specify a hostname, even if the client initially provided an IP address.
If, for any reason, the hostname provided to the listener (e.g. by the 'hostname' or another command) doesn't agree with the hostname by which the server is known on the client, the connection fails.
On the other hand, if "(SERVER=DEDICATED)" already appears in the TNS connect string in tnsnames.ora or if "use_dedicated_server=ON" already appears in the sqlnet.ora file, you may find that SQL*Plus and/or JDBC OCI work fine, while JDBC Thin fails.
SOLUTION
Obviously, one solution is to use dedicated servers. However, this may not always be feasible.
The key is to make sure the hostname on both the client and server agree. This can be accomplished by reconfiguring either the client or the server, but there are things to be aware of in both cases.
If the server is configured to return a different hostname, then it is possible that other clients which used to work will now fail.
In some cases, it may not be feasible to reconfigure the client. For example, if the server version of the hostname does not include the domain, you would need to remove the domain portion of the hostname on the client; but, if the client needs to connect to more than one server with the same base name in different domains, this may not be possible, as the hostname may be ambiguous.
REFERENCES
bug:1269734 java.sql.SQLException: Io exception: The Network Adapter could not be found.
问题描述Q配|完JDBC后,打开面的时候,报出如下错误信息Q?br />javax.naming.NameNotFoundException: Unable to resolve oracThin. Resolved: '' Unresolved:'oracThin' ; remaining name ''
JDBC配置如下Q?br />Connection Pools(q接?
Name:OracThin
URL:jdbc:oracle:thin.0.0.1:LYSIMIS
Driver Classname:oracle.jdbc.driver.OracleDriver
Properties:
user=system
password=manager
dll=ocijdbc8
protocol=thin
数据源配|如下:
Name:OracThin
JNDI Name:OracThin
Pool Name:OracThin
当程序执行到q一步时出错?br />ctx = new InitialContext();
ds = (javax.sql.DataSource)ctx.lookup ("OracThin");
问题解决后汉字是q
错误产生原因及解军_法:
问题描述QOracle_XA;xaosw;D:oracleora92 dbmsXAORAXA9.lib C:msvcoraSQL9.lib?br />xaosw是什么意?/p>
解答Q可以参考ORACLE的XA部分的文档?/p>
http://www-rohan.sdsu.edu/doc/oracle/server803/A54642_01/ch_xa.htm
问题描述Q每ơ重新启动服务器时oracle数据库若没有关闭Q则必须先关闭后在重新启动redhat advance serverQoracle才能够正常运?/p>
原因及解军_法参见:
http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=81&threadID=8839&messageID=43184#43184
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=579829
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=607570
目前的很多方法都是要求用户只能按规定Ҏ(gu)使用q接Q不能用直接关闭数据连接的Ҏ(gu)。解军_法就是用代理类Q来中间解决。可以参?a >http://www-900.ibm.com/developerWorks/cn/java/l-connpoolproxy/index.shtml
因ؓ针对数据库连接创建的资源Q如果不能及时的释放Q就会媄响下一ơ数据连接的使用。例如在sql 2k中,一个连接不同创建多条Statement否则操作时会有数据连接占U的异常Q所以必d归还q接以后释放q些资源?/p>
|
|
一个考虑是不能让用户随便用代理类Q而只能自׃用,一个就是用内部U有c,一个就是用只有指定类才能调用的标志。我的实现就是采用后者?/p>
|
使用静态方法创建工厂,然后来得到连接,使用完全和普通的ConnectionҎ(gu)一P没有限制。同时ؓ了方便,讄了连接参数类和工厂参数类?/p>
|
|
对于q接池的理Q我是设想用静态管理和动态管理两U策略,讄了最大限Ӟ和恒定的q接数。用了2个池Q一个空闲池Q一个用池。静态就是用的时候发现空闲连接不够再L查。动态就是用了一个线E定时检查?/p>
|
最后给出完整的源代码:
_Connectio.java
package scut.ailab.connectionpool; import java.lang.reflect.*; /** /**
/** /** |
package scut.ailab.connectionpool; /** public class ConnectionFactory { private ConnectionFactory() { |
package scut.ailab.connectionpool; import java.io.Serializable; /** public String getDriver() { public String getPassword() { public String getUrl() { public String getUser() { public void setDriver(String driver) { public void setPassword(String password) { public void setUrl(String url) { public void setUser(String user) { /** /** |
/* /** |
/* /** |
/* /** public class testmypool { public void test1() |
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=613371
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=629369
查询SQL语句分析与编译的旉Q?br />select * from v$sysstat
where name in ('parse time cpu','parse time elapsed','parse count (hard)')
一个SQL语句的响应时?elapsed time )应该是服务时?{待旉.
服务旉= CPU执行旉.
{待旉 可以从v$system_event
select total_waits, total_timeouts, time_waited, average_wait ,event
from v$system_event
where event='latch free'
所以解析一个SQL语句的^均等待时间是"{待旉/parse count" q个值接q?
通过数据字典v$sqlare,可以查询到频J被分析与编译的SQL语句.应该减少SQL语句的分析与~译的次?
2: 常用的实体ȝ内存.
Z减少分析与编译时?可以常用的的实体如: 存储q程,包等,可能驻留在内存区域.
1)预留内存I间. sql> show parameter shared_pool_reserved_size
2)频J用的实体ȝ在内存中. 在用DBMS_SHARED_POOLE序包前,必须首先q行pȝ提供的程序包: dbmspool.sql 和prvtpool.plb
在加载这两个E序包后,自动生成所需的包.
加蝲: sql> @/u01/app/oracle/product/8.17/rdbms/admin/dbmspool.sql
sql> @/u01/app/oracle/product/8.17/rdbms/admin/prvtpool.sql
包DBMS_SHARED_POOL包含以下存储q程.
dbms_shared_pool.keep 用于实体保存内? dbms_shared_pool.keep(object in varchar2,[type in char default p]);
object 表示参数? type 表示被驻留内存的实体cd;P 表示存储q程,C表示光标,R表示触发?默认P
dbms_shared_pool.unkeep 用于取消被设|进入内存的实体. dbms_shared_pool.unkeep(object in varchar2,[type in char default p]);
object 表示参数? type 表示被驻留内存的实体cd;P 表示存储q程,C表示光标,R表示触发?默认P
dbms_shared_pool.size(minsize in number)
select name ,type ,source_size+code_size+parsed_size+error_size "total bytes"
from dba_object_size
where owner='SCOTT'
3: 创徏索引.
select index_name,table_owner, table_name, tablespace_name from all_indexes
select user_indexes.TABLE_NAME, user_indexes.INDEX_NAME,uniqueness, column_name
from user_ind_columns ,user_indexes
where user_ind_columns.INDEX_NAME=user_indexes.INDEX_NAME
and user_ind_columns.TABLE_NAME=user_indexes.TABLE_NAME
order by user_indexes.TABLE_TYPE,user_indexes.TABLE_NAME,user_indexes.INDEX_NAME,user_ind_columns.COLUMN_POSITION
4: 创徏聚簇(cluster): 是一l存储在一L有共同列或经怸起用的?被聚的两个表只有一个数据段.聚簇表在存储?在物理层子表合q到父表?q样少了表的连接时?
5: 创徏哈希索引.
6: SQL优化? Z成本的优化器CBO(cose_based)和基于规则RBO(rule_based)
sql> show parameter OPTIMIZER_MODE
可以修改参数文g: initSID.ora,增加: optimizer_Mode={CHOOSE| RULE| FIRST_ROWS|ALL_ROWS}
all_rows , first_rows(n)Z成本; rule Z规则,chooseZ规则、成本?br /> /*+ ordered*/
/*+ rule */
/*+ first_rows(50) */
/*+ordered star*/
写发Q?
alter system flush shared_pool;
select /*+ rule */ aa from visit
原文链接:http://www.tkk7.com/yanmin/archive/2006/03/20/36332.html
1. CPU:在Q何机器中CPU的数据处理能力往往是衡量计机性能的一个标志,q且ORACLE是一个提供ƈ行能力的数据库系l,在CPU斚w的要求就更高了,如果q行队列数目过了CPU处理的数目,性能׃下降Q我们要解决的问题就是要适当增加CPU的数量了Q当然我们还可以需要许多资源的q程KILL?
2. 内存:衡量机器性能的另外一个指标就是内存的多少了,在ORACLE中内存和我们在徏数据库中的交换区q行数据的交换,L据时Q磁盘I(y)/O必须{待物理I/O操作完成Q在出现ORACLE的内存瓶颈时Q我们第一个要考虑的是增加内存Q由于I/O的响应时间是影响ORACLE性能的主要参敎ͼ我将在这斚wq行详细的讲?/P>
3. |络条g:NET*SQL负责数据在网l上的来往Q大量的SQL会o|络速度变慢。比?0M的网卡和100的网卡就对NET*SQL有非常明昄影响Q还有交换机、集U器{等|络讑֤的性能对网l的影响很明显,在Q何网l中不要试图?个集U器来将|段互联?/P>
OS参数的设|?/P>
下表l出了OS的参数设|及说明QDBA可以Ҏ(gu)实际需要对q些参数q行讄
内核参数?/P>
说明
bufpages
对bufferI间不按静态分配,采用动态分配,使bufpages值随nbuf一起对bufferI间q行动态分配?/P>
create_fastlinks
对HFS文gpȝ允许快速符号链?/P>
dbc_max_pct
加大最大动态bufferI间所占物理内存的癑ֈ比,以满_用系l的d命中率的需要?/P>
dbc_min_pct
讄最动态bufferI间所占物理内存的癑ֈ?/P>
desfree
提高开始交换操作的最低空闲内存下限,保障pȝ的稳定性,防止出现不可预见的系l崩?Crash)?/P>
fs_async
允许q行盘异步操作Q提高CPU和磁盘的利用?/P>
lotsfree
提高pȝ解除换页操作的空闲内存的上限|保证应用E序有够的可用内存I间?/P>
maxdsiz
针对pȝ数据量大的特点,加大最大数据段的大,保证应用的需要?32?
maxdsiz_64bit
maximum process data segment size for 64_bit
Maxssiz
加大最大堆栈段的大?32_bit)
maxssiz_64bit
加大最大堆栈段的大?64_bit)
Maxtsiz
提高最大代码段大小Q满_用要?/P>
maxtsiz_64bit
原D大,应调?yu)?/P>
Minfree
提高停止交换操作的自由内存的上限
Shmem
允许q行内存׃nQ以提高内存的利用率
Shmmax
讄最大共享内存段的大,完全满目前的需?/P>
Timeslice
׃pȝ的瓶颈主要反映在盘I(y)/O上,因此 降低旉片的大小Q一斚w可避免因盘I(y)/O不畅造成CPU的等待,从而提高了CPU的综合利用率。另一斚w减少了进E的d量?/P>
unlockable_mem
提高了不可锁内存的大,使可用于换页和交换的内存I间扩大,用以满pȝ对内存管理的要求?/P>
用户SQL质量
以上讲的都是g斚w的东西,在条件有限的条g下,我们可以调整应用E序的SQL质量:
1. 不要q行全表扫描(Full Table Scan):全表扫描D大量的I/O
2. 量建好和用好索引:建烦引也是有讲究的,在徏索引Ӟ也不是烦引越多越好,当一个表的烦引达?个以上时QORACLE的性能可能q是改善不了Q因为OLTPpȝ每表过5个烦引即会降低性能Q而且在一个sql 中, Oracle 从不能用超q?5个烦?当我们用到GROUP BY和ORDER BY?ORACLE׃自动Ҏ(gu)据进行排?而ORACLE在INIT.ORA中决定了sort_area_size区的大小,当排序不能在我们l定的排序区完成?ORACLE׃在磁盘中q行排序,也就是我们讲的时表I间中排? q多的磁盘排序将会o free buffer waits 的值变?而这个区间ƈ不只是用于排序的,对于开发h员我提出如下忠告:
1)、select,update,delete 语句中的子查询应当有规律地查扑ְ?0%的表?如果一个语句查扄行数过总行数的20%,它将不能通过使用索引获得性能上的提高.
2)、烦引可能生碎?因ؓ记录从表中删除时,相应也从表的索引中删?表释攄I间可以再用,而烦引释攄I间却不能再?频繁q行删除操作的被索引的表,应当阶段性地重徏索引,以避免在索引中造成I间片,影响性能.在许可的条g?也可以阶D|地truncate?truncate命o删除表中所有记?也删除烦引碎?
3)、在使用索引时一定要按烦引对应字D늚序q行引用?/P>
4)、用(+)比用NOT IN更有效率?/P>
降低ORACLE的竞?
先讲几个ORACLE的几个参敎ͼq几个参数关pdORACLE的竞?
1)、freelists ?freelist l?他们负责ORACLE的处理表和烦引的I间理;
2)、pctfree ?pctused:该参数决定了freelists ?freelist l的行ؓQpctfree 和pctused 参数的唯一目的是Z控制块如何在 freelists 中进?/P>
讄好pctfree ?pctused对块在freelists的移走和d很重要?/P>
其他参数的设|?/P>
1)、包括SGA?pȝ全局?:pȝ全局?SGA)是一个分配给Oracle 的包含一?Oracle 实例的数据库的控制信息内存段?/P>
主要包括数据库高速缓?the database buffer cache)Q?/P>
重演日志~存(the redo log buffer)Q?/P>
׃n?the shared pool)Q?/P>
数据字典~存(the data dictionary cache)以及其它各方面的信息
2)、db_block_buffers(数据高速缓冲区)讉Kq的数据都放在这一片内存区域,该参数越大,Oracle在内存中扑ֈ相同数据的可能性就大Q也卛_快了查询速度?/P>
3)、share_pool_size (SQL׃n~冲?:该参数是库高速缓存和数据字典的高速缓存?/P>
4)、Log_buffer (重演日志~冲?
5)、sort_area_size(排序?
6)、processes (同时q接的进E数)
7)、db_block_size (数据库块大小):Oracle默认块ؓ2KBQ太了Q因为如果我们有一?KB的数据,?KB块的数据库要?ơ盘Q才能读完,?KB块的数据库只?ơ就d了,大大减少了I/O操作。数据库安装完成后,׃能再改变db_block_size的gQ只能重新徏立数据库q且建库Ӟ要选择手工安装数据库?/P>
8)、open_links (同时打开的链接数)
9)、dml_locks
10)、open_cursors (打开光标?
11)、dbwr_io_slaves (后台写进E数)