Java MySQL 完全手册

时间:2021-07-26 00:49:05

Java连接Mysql详解

Part I: 驱动/数据源 类名, URL语法, Connector/J的属性配置.

在查看本文档时, 假设你应经安装好了mysql, 和mysql-connector-java-X.X.X-bin.jar

Mysql Connector/J通过com.mysql.jdbc.Driver来实现java.sql.Driver, 同时类名org.gjt.mm.mysql.Driver依旧可用, 以保持向前兼容MM.Mysql.

MySQL的JDBC URL格式如下:

Java MySQL 完全手册

如果没有明确指定host(主机名), 默认为127.0.0.1, 端口号默认是3306

如果不指定数据库名, 不会有默认的数据库, 这样的话, 你可以调用Connection的setCatalog()方法, 或者在SQL中明确指定所用的数据库. 这种情况只在为多个数据库建立工具时有用. 例如建立GUI数据库管理器.

JDBC应该永远不使用USE database来指定数据库, 应该用Connection.setCatalog()方法.

MySQL Connector/J支持fail-over模式, 使用fail-over模式, 必须将connection的autoCommit设置为true.

如果URL的autoReconnect设置为false: Failover会发生在连接初始化时, failback出现在驱动器使第一个主机在此可用时.

如果URL的autoReconnect属性时true, Failover发生在驱动决定connection失败时(在每次查询之前), falls back到第一个主机, 当它决定这个主机在此可用时.

在以上提到的两种情况中, 无论何时你连接到一个"failed-over"服务器, 这个连接将会是制度的, 因此, 修改数据的查询, 将会引发异常.

Configuration properties定义Connctor/J将怎样连接到MySQL服务器. 除了特别声明, 这些属性可以设置在DataSource或Connection object中.

Configuration properties可以按照下面的方式进行设置:

①使用MysqlDataSource或MysqlConnectionPoolDataSource的set*()方法.

②以java.util.Properties的key/value对的形式传递给DriverManager.getConnection() 或Driver.connect()

③作为JDBC URL的参数传给java.sql.DriverManger.getConnection()

java.sql.Driver.connect()或MySQL实现的javax.sql.DataSource setURL() 方法.

注意: 如果你用来确定JDBC URL的机制是XML-based, 你需要使用XML字符 &来分隔参数.

属性列举如下:

Connection/Authentication

Java MySQL 完全手册

NetWorking:

Java MySQL 完全手册

Java MySQL 完全手册

Hign Availability and Clustering:

Java MySQL 完全手册

Java MySQL 完全手册

Security:

Java MySQL 完全手册Java MySQL 完全手册

Performance Extensions:

Java MySQL 完全手册

Java MySQL 完全手册

Java MySQL 完全手册

Debugging/Profiling:

Java MySQL 完全手册

Java MySQL 完全手册

Miscellaneous:

Java MySQL 完全手册

Java MySQL 完全手册

Java MySQL 完全手册

Java MySQL 完全手册

Java MySQL 完全手册

Java MySQL 完全手册

Connector/j也支持在Windows NT/2000/XP中通过命名的pipes来访问MySql,具体方法是, 把NamedPipeSocketFactory当作一个plugin-socket factory使用socketFactory属性. 如果你没有使用namedPipepath, 默认的'\\.\pipe\MySQL'将会被使用. 如果你使用NamedPipeSocketFactory,JDBC url中的host名字和port号将会被忽略.

可以通过如下方法使用:

socketFactory=com.mysql.jdbc.NamedPipeSocketFactory

Named pipes只能够工作在连接的MySQL server同时使用JDBC driver时.

JDBC API实现的注意事项

Blob: 从3.1.0版本开始, 你就能够通过在JDBC URL中添加 'emulateLocators=true'属性使用locator来模仿Blobs. 通过这种方式, driver知道你通过查询过方法来获取blob数据流的时候才会加载真正的Blob数据.

为了使用这种方式你必须使用列的别名:

SELECT id, 'data' as blob_data from blobtable

你必须遵守如下的规定:

1)SELECT语句必须只查询一张表, 且表具有主键.

2) SELECT语句必须定义原始blob列的别名.

3)SELECT语句必须包含主键的各列.

Blob实现不允许in-place修改(他们是copies,通过DatabaseMetaData.locatorsUpdateCopies()可以查询到),因此,你不许使用对应的PreparedStatement.setBlob()或ResultSet.updateBlob()(如果结果集是可修改的)来将变化存储到数据库中.

CallableStatement:

从version3.1.1开始支持, 从version5.0开始支持存储过程, 目前不支持getParameterMetaData()方法.

Clob

不支持in-place修改, 可以通过PreparedStatement.setClob()方法修改, JDBC API没有定义ResultSet.updateClob()方法.

Connection: isClosed方法不会通过ping server来确定是否(connection)可用, 为了和JDBC定义一致, 只用调用了closed()方法之后才会返回true, 如果你想确定连接是否可用, 你可以使用一个简单的SELECT语句, 比如SELECT 1, 如果连接不可用了driver会抛出异常.

DatabaseMetaData:

外键信息(getImportedKeys()/getExportedKeys() and getCrossReference())只能过从InnoDB表中获取, 然而, driver使用SHOW CREATE TALBLE获取这些信息. 如果别的storage engine支持foreign key, driver会透明的支持.

PreparedStatement:

MySQL实现的PrepareStatement没有prepared statement特征, 因此, driver没有实现getParameterMetaData()或getMetaData(), 需要在客户端有一个完整的SQL parser.

从3.1.0版本开始, 服务器端的prepared statements和二进制的编码被使用, 如果其支持的话.

当对通过setBinaryStream(),setAsciiStream(),setUnicodeStream() ,setBlob(), or setClob 方法设置的large对象参数使用sever-side prepared statement的时候,如果你需要将large参数修改为nonlarge参数重新执行, 你必须先调用clearParameter(), 然后重新设定所有的参数. 这样做的原因如下:

1) 在server-side preparedstatements和client-side emulation, large数据只有在调用了PreparedStatement.execute()后有所交换.

2) 一旦完毕, 客户端用来读取数据的stream将被关闭(as per JDBC spec), 不能再从中读取数据.

3) 如果参数由large转化到nonlarge, driver需要重置server-side的prepared statement的状态,以便改变的参数值取代以前的large值. 这将清除已经发送到server的所有的large data, 而且需要使用setBinaryStream(), setAsciiStream(), setUnicodeStream(), setBlob() or setClob()方法重新发送数据.

所以, 如果你想更改nonlarge参数的类型, 你必须在执行prepared statement之前调用clearParameters(),重新设定prepared statement的参数.

ResultSet:

一般ResultSet都被存储在内存中, 通常这是最高效的处理方式. 如果ResultSet中包含很多行结果或large值, 不能够在JVM中分配足够的内存, 你可以让driver每次返回一行结果.

使用这种功能你需要用如下方式定义Statement实例:

stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,

java.sql.ResultSet.CONCUR_READ_ONLY);

stmt.setFetchSize(Integer.MIN_VALUE);

关于该方式的警告: 在你进行别的查询之前你需要读取结果集中的所有行(或者关闭它), 不然会抛出异常.

statements持有的最早的锁(不管是MyISAM表级别的锁, 还是别的存储引擎(other storage engine such as InnoDB)行级别的锁)将会在statement执行完之后释放.

如果语句位置transaction范围内, 当transaction结束时, 这些锁会被释放(意味着statement要先执行完). 和大多数别的数据库相同, 只用所有结果被确定或者当前结果集被关闭, statement才算执行完毕.

因此, 如果使用流式的结果, 如果你想保持对statement指向的产生结果集的数据表并发的访问, 你应该尽快的处理它们.

ResultSetMetaData:

isAutoIncrement()方法只在MySQL servers 4.0或更新版本可用.

Statement:

MySQL不支持SQL cursor, 因此, setCursorName()没有效果.

Java, JDBC and MySQL Types

MySQL Connector/J在MySQL数据类型和Java数据类型之间进行转化的时候是很灵活的.

通常, 任何MySQL数据类型可以转换为java.lang.String. 任何numeric类型可以转化为任何Java numeric类型, 尽管可能四舍五入(round-off), 溢出, 或丢失精度.

从C/J 3.1.0开始, JDBC driver将会发出警告或抛出DataTruncattion异常, 除非connection将jdbcCompliantTruncation属性设置为false.

These MySQL Data Types

Can always be converted to these Java types

CHAR, VARCHAR, BLOB, TEXT, ENUM, and SET

java.lang.String, java.io.InputStream, java.io.Reader, java.sql.Blob, java.sql.Clob

FLOAT, REAL, DOUBLE PRECISION, NUMERIC, DECIMAL, TINYINT, SMALLINT, MEDIUMINT, INTEGER, BIGINT

java.lang.String, java.lang.Short, java.lang.Integer, java.lang.Long, java.lang.Double, java.math.BigDecimal

DATE, TIME, DATETIME, TIMESTAMP

java.lang.String, java.sql.Date, java.sql.Timestamp

注意: 如果目标Java数据类型的精度小于MySqL数据类型的精度, 有可能四舍五入或溢出.

ResultSet.getObject()同样遵循JDBC定义的转化规则进行MySQL和Java type之间的类型转化, MySQl类型和Java类型的对应详情请查看附录中的Types定义.

Using Character Sets and Unicode

JDBC driver发送给server的所有字符串都自动的从native Java Unicode form转化到了client character encoding.

包括所有的Statement.execute(), Statement.executeUpdate(), Statement.executeQuery(), PreparedStatement和CallableStatement参数和其他的通过setBytes(), setBinaryStream(), setAsciiStream(), setUnicodeStream和setBlob()设置的参数.

从MySQL Server 4.1开始, C/J开始支持客户端和服务器端得单字符编码, 在ResultSet中从服务器返回的任意数量字符的编码.

客户端和服务器之间的字符编码是根据connection自动探测到的. 在URL中可以设置characterEncoding属性从而改变客户端自动检测到的编码方式.

在client-side确定字符编码的时候, 应该使用Java风格的名字. MySQL字符集和Java-style名字对应表如下:

MySQL to Java Encoding Name Translations.

MySQL Character Set Name

Java-Style Character Encoding Name

ascii

US-ASCII

big5

Big5

gbk

GBK

sjis

SJIS (or Cp932 or MS932 for MySQL Server < 4.1.11)

cp932

Cp932 or MS932 (MySQL Server > 4.1.11)

gb2312

EUC_CN

ujis

EUC_JP

euckr

EUC_KR

latin1

Cp1252

latin2

ISO8859_2

greek

ISO8859_7

hebrew

ISO8859_8

cp866

Cp866

tis620

TIS620

cp1250

Cp1250

cp1251

Cp1251

cp1257

Cp1257

macroman

MacRoman

macce

MacCentralEurope

utf8

UTF-8

ucs2

UnicodeBig

警告: 不要用C/J 'set names' 的查询,

Connection Security Using SSL

在MySQL中使用SSL将加密所有的的JDBC driver和server之间的所有数据. 使用SSL会增加35%到50%的处理时间, 具体与查询的规模和返回的数据量有关.

使用SSL需要如下条件:

1) 包含JSSE的JDK(JDK-1.41以上)

2) MySQL-4.0.4以上.

3)客户端证书.

系统通过两个truststore文件工作, 一个存有server的certificate information, 一个存有客户端的certificate. 当你创建Java truststore文件时,提供适当的密码对其进行保护. 你需要文件名和关联的密码来创建SSL连接.

Connecting to MySQL Using the DriverManager Interface

DriverManager用来建立连接.

DriverManager需要知道使用哪一个JDBC driver来创建连接. 最简单的方法就是在实现了java.sql.Driver接口的类上使用Class.forName()方法. 使用MySql Connector/J, 类的名字是com.mysql.jdbc.Driver. 通过这个方法, 你可以使用外部的配置文件来提供用来连接数据库的driver名字和driver参数.

如下Java代码演示了怎样在main()方法中注册MySQL Connector/J.

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.SQLException;

// Notice, do not import com.mysql.jdbc.*

// or you will have problems!

public class LoadDriver {

public static void main(String[] args) {

try {

// The newInstance() call is a work around for some

// broken Java implementations

Class.forName("com.mysql.jdbc.Driver").newInstance();

} catch (Exception ex) {

// handle the error

}

}

}

下面的代码演示如何从DriverManager创建一个Connection, getConnection()方法有不同的参数形式, 具体查看附录的DriverManager的详细介绍.

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.SQLException;

Connection conn = null;

...

try {

conn =

DriverManager.getConnection("jdbc:mysql://localhost/test?" +

"user=monty&password=greatsqldb");

// Do something with the Connection

...

} catch (SQLException ex) {

// handle any errors

System.out.println("SQLException: " + ex.getMessage());

System.out.println("SQLState: " + ex.getSQLState());

System.out.println("VendorError: " + ex.getErrorCode());

}

一旦建立了连接就可以用来建立Statement和PreparedStatement对象, 也可以获取数据库的metadata.

通过Statement执行SQL

Statement对象用来执行基本的SQL语句, 通过ResultSet返回结果.

通过调用Connection的createStatement()方法创建Statement实例, Connection对象是通过前面讲过的DriverManager.getConnection()或DataSource.getConnection方法.

获得Statement之后, 可以使用executeQuery(String)方法用想用的SQL执行SELECT查询.

更新数据库中的数据, 应该使用executeUpdate(String SQL)方法. 这个方法返回与update语句匹配的行数. 不是被更改的行数.

如果之前不清楚SQL是一个SELECT还是UPDATE/INSERT, 可以使用execute(String SQL)方法. 如果是SQL查询是个SELECT, 返回true, 如果是UPDATE, INSERT, DELETE语句, 返回false. 如果是SELECT查询, 你能够通过调用getResultSet()方法返回结果. 可以调用getUpdateCount()获得受影响的行数.

下面的例子演示使用java.sql.Statement执行一个SELECT查询.

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.SQLException;

import java.sql.Statement;

import java.sql.ResultSet;

// assume that conn is an already created JDBC connection (see previous examples)

Statement stmt = null;

ResultSet rs = null;

try {

stmt = conn.createStatement();

rs = stmt.executeQuery("SELECT foo FROM bar");

// or alternatively, if you don't know ahead of time that

// the query will be a SELECT...

if (stmt.execute("SELECT foo FROM bar")) {

rs = stmt.getResultSet();

}

// Now do something with the ResultSet ....

}

catch (SQLException ex){

// handle any errors

System.out.println("SQLException: " + ex.getMessage());

System.out.println("SQLState: " + ex.getSQLState());

System.out.println("VendorError: " + ex.getErrorCode());

}

finally {

// it is a good idea to release

// resources in a finally{} block

// in reverse-order of their creation

// if they are no-longer needed

if (rs != null) {

try {

rs.close();

} catch (SQLException sqlEx) { } // ignore

rs = null;

}

if (stmt != null) {

try {

stmt.close();

} catch (SQLException sqlEx) { } // ignore

stmt = null;

}

}

Using CallableStatements to Execute Stored Procedures

从MySQL server 5.0 Connector/J 3.1.1开始,除了getParameterMetaData()方法外, java.sql.CallableStatement接口被完全实现.

The following example shows a stored procedure that returns the value of inOutParam incremented by 1, and the string passed in using inputParam as a ResultSet:

Example 5.3. Connector/J: Calling Stored Procedures

CREATE PROCEDURE demoSp(IN inputParam VARCHAR(255),\ INOUT inOutParam INT)

BEGIN

DECLARE z INT;

SET z = inOutParam + 1;

SET inOutParam = z;

SELECT inputParam;

SELECT CONCAT('zyxw', inputParam);

END

Connector/J通过如下步骤使用demoSp过程:

1) 通过使用Connection.prepareCall()来准备callable statement.

注意, 你必须使用JDBC转移字符. 圆括号包围的参数占位符不是可选的.

import java.sql.CallableStatement;

...

//

// Prepare a call to the stored procedure 'demoSp'

// with two parameters

//

// Notice the use of JDBC-escape syntax ({call ...})

//

CallableStatement cStmt = conn.prepareCall("{call demoSp(?, ?)}");

cStmt.setString(1, "abcdefg");

注意: Connection.prepareCall()是一个代价昂贵的方法, due to the metadata retrieval that the driver performs to support output parameters. 为了获得更好的性能, 你应该通过重用CallableStatement实例从而减少不必要的Connection.preparedCall()调用.

2) 注册输出参数(任何存在的):

为了获取输出参数(在定义存储过程的时候,被标识为OUT或INOUT的参数)的值, JDBC要求使用CallableStatement接口中丰富的registerOutputParameter()方法来确定这些输出参数.

Example 5.5. Connector/J: Registering output parameters

import java.sql.Types;

...

//

// Connector/J supports both named and indexed

// output parameters. You can register output

// parameters using either method, as well

// as retrieve output parameters using either

// method, regardless of what method was

// used to register them.

//

// The following examples show how to use

// the various methods of registering

// output parameters (you should of course

// use only one registration per parameter).

//

//

// Registers the second parameter as output, and

// uses the type 'INTEGER' for values returned from

// getObject()

//

cStmt.registerOutParameter(2, Types.INTEGER);

//

// Registers the named parameter 'inOutParam', and

// uses the type 'INTEGER' for values returned from

// getObject()

//

cStmt.registerOutParameter("inOutParam", Types.INTEGER);

...

3)设置输入参数(任何存在的)

输入和in/out参数像PreparedStatement那样赋值, 但是, CallableStatement也支持通过名字设置参数.

Example 5.6. Connector/J: Setting CallableStatement input parameters

...

//

// Set a parameter by index

//

cStmt.setString(1, "abcdefg");

//

// Alternatively, set a parameter using

// the parameter name

//

cStmt.setString("inputParameter", "abcdefg");

//

// Set the 'in/out' parameter using an index

//

cStmt.setInt(2, 1);

//

// Alternatively, set the 'in/out' parameter

// by name

//

cStmt.setInt("inOutParam", 1);

...

4) 执行CallableStatement, 返回结果集或输出参数.

CallableStatement支持Statement的所有执行方法(executeUpdate(), executeQuery or execute()), 最灵活的方法是execute(). 不需要提前知道存储过程是否会返回结果集.

boolean hadResults = cStmt.execute();

//

// Process all returned result sets

//

while (hadResults) {

ResultSet rs = cStmt.getResultSet();

// process result set

...

hadResults = cStmt.getMoreResults();

}

//

// Retrieve output parameters

//

// Connector/J supports both index-based and

// name-based retrieval

//

int outputValue = cStmt.getInt(2); // index-based

outputValue = cStmt.getInt("inOutParam"); // name-based

...

查询AUTO_INCREMENT列的值

JDBC API 3.0之前, 没有标准的方式从数据库中获取自增或标识(identity)列. 在相对较老的JDBC driver for MySQL中, 在向带有AUTO_INCREMENT键的表中执行了INSERT后, 你能够对Statement使用MySQL-specific方法, 或使用SELECT LAST_INSERT_ID(), MySQL-specific方法移植性差, 用SELECT获取AUTO_INCREMENT键值需要到数据库的往复, 效率不是很好. 下面的三种代码说明了三种获取AUTO_INCREMENT值的方法. 第一种使用了getGeneratedKeys(), 这是一个现在推荐用的方法. 第二种使用了标准的SELECT LAST_INSERT_ID() 查询. 最后一个例子演示了可更改结果集当使用insertRow()方法时, 怎样获得AUTO_INCREMENT的值.

Example 5.8. Connector/J: Retrieving AUTO_INCREMENT column values using Statement.getGeneratedKeys()

Statement stmt = null;

ResultSet rs = null;

try {

//

// Create a Statement instance that we can use for

// 'normal' result sets assuming you have a

// Connection 'conn' to a MySQL database already

// available

stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,

java.sql.ResultSet.CONCUR_UPDATABLE);

//

// Issue the DDL queries for the table for this example

//

stmt.executeUpdate("DROP TABLE IF EXISTS autoIncTutorial");

stmt.executeUpdate(

"CREATE TABLE autoIncTutorial ("

+ "priKey INT NOT NULL AUTO_INCREMENT, "

+ "dataField VARCHAR(64), PRIMARY KEY (priKey))");

//

// Insert one row that will generate an AUTO INCREMENT

// key in the 'priKey' field

//

stmt.executeUpdate( "INSERT INTO autoIncTutorial (dataField) " + "values ('Can I Get the Auto Increment Field?')", Statement.RETURN_GENERATED_KEYS);

//

// Example of using Statement.getGeneratedKeys()

// to retrieve the value of an auto-increment

// value

//

int autoIncKeyFromApi = -1;

rs = stmt.getGeneratedKeys();

if (rs.next()) {

autoIncKeyFromApi = rs.getInt(1);

} else {

// throw an exception from here

}

rs.close();

rs = null;

System.out.println("Key returned from getGeneratedKeys():"

+ autoIncKeyFromApi);

} finally {

if (rs != null) {

try {

rs.close();

} catch (SQLException ex) {

// ignore

}

}

if (stmt != null) {

try {

stmt.close();

} catch (SQLException ex) {

// ignore

}

}

}

Example 5.9. Connector/J: Retrieving AUTO_INCREMENT column values using SELECT LAST_INSERT_ID()

Statement stmt = null;

ResultSet rs = null;

try {

//

// Create a Statement instance that we can use for

// 'normal' result sets.

stmt = conn.createStatement();

//

// Issue the DDL queries for the table for this example

//

stmt.executeUpdate("DROP TABLE IF EXISTS autoIncTutorial");

stmt.executeUpdate(

"CREATE TABLE autoIncTutorial ("

+ "priKey INT NOT NULL AUTO_INCREMENT, "

+ "dataField VARCHAR(64), PRIMARY KEY (priKey))");

//

// Insert one row that will generate an AUTO INCREMENT

// key in the 'priKey' field

//

stmt.executeUpdate(

"INSERT INTO autoIncTutorial (dataField) "

+ "values ('Can I Get the Auto Increment Field?')");

//

// Use the MySQL LAST_INSERT_ID()

// function to do the same thing as getGeneratedKeys()

//

int autoIncKeyFromFunc = -1;

rs = stmt.executeQuery("SELECT LAST_INSERT_ID()");

if (rs.next()) {

autoIncKeyFromFunc = rs.getInt(1);

} else {

// throw an exception from here

}

rs.close();

System.out.println("Key returned from " +

"'SELECT LAST_INSERT_ID()': " +

autoIncKeyFromFunc);

} finally {

if (rs != null) {

try {

rs.close();

} catch (SQLException ex) {

// ignore

}

}

if (stmt != null) {

try {

stmt.close();

} catch (SQLException ex) {

// ignore

}

}

}

Example 5.10. Connector/J: Retrieving AUTO_INCREMENT column values in Updatable ResultSets

Statement stmt = null;

ResultSet rs = null;

try {

//

// Create a Statement instance that we can use for

// 'normal' result sets as well as an 'updatable'

// one, assuming you have a Connection 'conn' to

// a MySQL database already available

//

stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,

java.sql.ResultSet.CONCUR_UPDATABLE);

//

// Issue the DDL queries for the table for this example

//

stmt.executeUpdate("DROP TABLE IF EXISTS autoIncTutorial");

stmt.executeUpdate(

"CREATE TABLE autoIncTutorial ("

+ "priKey INT NOT NULL AUTO_INCREMENT, "

+ "dataField VARCHAR(64), PRIMARY KEY (priKey))");

//

// Example of retrieving an AUTO INCREMENT key

// from an updatable result set

//

rs = stmt.executeQuery("SELECT priKey, dataField "

+ "FROM autoIncTutorial");

rs.moveToInsertRow();

rs.updateString("dataField", "AUTO INCREMENT here?");

rs.insertRow();

//

// the driver adds rows at the end

//

rs.last();

//

// We should now be on the row we just inserted

//

int autoIncKeyFromRS = rs.getInt("priKey");

rs.close();

rs = null;

System.out.println("Key returned for inserted row: "

+ autoIncKeyFromRS);

} finally {

if (rs != null) {

try {

rs.close();

} catch (SQLException ex) {

// ignore

}

}

if (stmt != null) {

try {

stmt.close();

} catch (SQLException ex) {

// ignore

}

}

}

使用SELECT LAST_INSERT_ID()有时候时需要技巧的, 该方法的返回值是和connection有关的, 因此, 如果连接上碰巧有别的查询, 这个值会被重写. 因为getGeneratedKeys()是工作在Statement实例上的, 因此即使同样的connection上有别的queries, 不是相同的Statement就可以放心使用.

Connector/J Java EE中的应用暂略

Part II

JDK sql接口定义:

Class DriverManager:

管理JDBC驱动的基础服务.

当调用getConnection方法的时候, DriverManager会试着从初始化时加载的和通过当前applet或application相同classloader显式加载的驱动中确定.

Connection:和指定数据库的连接(会话).

getMetaData():返回DatabaseMetaData, 包含所连接数据库的信息.

close()关闭数据库连接.

commit():提交所有在上次commit/rollback后的变化. 释放所有的database locks.

createStatement():生成一个Statement对象, 用来像数据库发送SQL语句.

getCatalog():获取Connection对象的当前目录.

isClosed():

isReadOnly():

isValid(int timeout)

rollback():撤销当前事务的所有改变, 释放database locks.只有auto-commit mode关闭时, 可用.

setAutoCommit(boolean autoCommit)

Statement:

用来执行静态SQL语句, 返回执行结果的对象.正常情况下, Statement只能打开一个ResultSet对象, 因此, 如果对一个ResultSet对象的读与另一个ResultSet对象交叉, 每一个ResultSet应该由不同的Statement对象产生. Statement的execution方法将隐式的关闭Statement当前已打开的ResultSet对象.

executeQuery(String sql):执行指定的SQL语句, 返回单行的ResultSet对象.参数一般是select语句.

executeUpdate(String sql):执行指定的SQL语句, 可以使INSERT,UPDATE或者DELETE语句或者是不返回值的SQL语句, 例如SQL DDL语句.返回值是:①DML语言影响的行数. ②0,SQL语句不返回任何值.

close():立即关闭Statement对象的database和JDBC资源,关闭已关闭Statement没有影响, 如果有ResultSet对象, 同样会关闭.

cancel():

boolean execute(String sql):执行特定的可能返回多行结果的SQL statement, execute方法执行一个SQL Statement并指示第一个结果的格式. 你必须使用getResultSet或getUpdateCount来获得结果, 用getMoreResults获得剩余的结果.如果第一个结果是ResultSet对象, 返回true, 果敢是update count或没有结果返回false.

getResultSet():以ResultSet对象的形式返回当前的结果集, 对每个结果, 这个方法应该只用一次.

getUpdateCount():以update count的形式返回当前当前结果.如果结果是ResultSet或没有更多结果, 返回-1. 这个方法对每个结果应该只调用一次.

boolean getMoreResults():

获得Statement对象的下一个结果. 如果是ResultSet对象, 返回true, 并关闭所有通过getResultSet()方法获得的ResultSet()对象.

setFetchDirection():指定驱动处理行的方向. 默认的值是ResultSet.FETCH_FORWORD.

addBatch(String sql):将命令添加到当前Statement对象的命令列. 通过条用executeBatch方法,命令列能够作为批处理执行

clearBatch():清空Statement对象的当前SQL命令列表.

executeBatch():提交批处理命令,如果执行成功,返回一个更改列数的数组, 数组元素和批处理的命令相同. 数组元素可能的值如下:

①大于等有0的数, 表示命令成功执行, 且该数是命令影响的行数.

② SUCCESS_NO_INFO表示命令被正常执行,但是被影响的行数未知.

③EXECUTE_FAILED: 表示命令执行失败(只有当驱动在遇到错误后依旧继续执行时, 出现这个问题).

getConnection(int current): 返回这个指令产生的Statement对象. current参数表示对当前的通过getResultSet()方法获得的ResultSet对象的处理. 可能的值如下: Statement.CLOSE_CURRENT_RESULT,Statement.KEEP_CURRENT_RESULT或者Statement.CLOSE_ALL_RESULTS.

getGeneratedKey():返回通过执行这个Statement对象自动生成的key. 如果Statement没有产生任何key, 将返回一个空的ResultSet对象.

executeUpdate(String sql, int autoGeneratedKeys):

Executes the given SQL statement and signals the driver with the given flag about whether the auto-generated keys produced by this Statement object should be made available for retrieval. 驱动器会忽略flag, 如果SQL语句不是一个INSERT语句. autoGeneratedKeys:标识是否自动产生key的标记, 可能的值如下: Statement.RETURN_GENERATED_KEYS, Statement.NO_GENERATED_KEYS

返回值可能是: ①DML语句返回的行数.②0如果SQL语句不返回任何值.

getMoreResults(): 移动到Statement对象的下一个结果. 如果下一个结果是ResultSet时返回true.

executeUpdate(String sql, int[] columnIndexes): columnIndexes: 包含目的表中列下标(这些列包含自动产生的key)的数组

int executeUpdate(String sql, String[] columnNames):

参数数组包含目标表的列(包含自动生成的key)的名字,

execute(String sql, int autoGeneratedKeys):

执行语句SQL语句,可能返回多个结果.

isClosed():

setPoolable():

isPoolable():

PreparedStatement:

代表预编译的SQL语句对象.

SQL语句被预编译并存储在PreparedStatement对象中, 这个对象可以用来多次高效的执行该语句.

注意: 用于设置IN参数值的setter方法必须制定与输入参数的已定义SQL类型相兼容的类型. 例如IN参数具有SQL INTEGER, 那么应该使用setInt方法.

如果需要任意类型转化, setObject方法应该使用目标SQL type.

下面的例子假设conn是活动连接:

PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES

SET SALARY = ? WHERE ID = ?");

pstmt.setBigDecimal(1, 153833.00)

pstmt.setInt(2, 110592)

ResultSet executeQuery():

int executeUpdate():

void setNull(int parameterIndex,

int sqlType):

将指定的参数设置为NULL.

void setBoolean(int parameterIndex,

boolean x)

void setByte(int parameterIndex,

byte x)

void setShort(int parameterIndex,

short x)

void setInt(int parameterIndex,

int x)

void setLong(int parameterIndex,

long x)

void setFloat(int parameterIndex,

float x)

void setDouble(int parameterIndex,

double x)

void setBigDecimal(int parameterIndex,

BigDecimal x)

void setString(int parameterIndex,

String x)

void setBytes(int parameterIndex,

byte[] x)

void setDate(int parameterIndex,

Date x)

void clearParameters(): 清除当前的所有参数.

void setObject(int parameterIndex,

Object x,

int targetSqlType):

boolean execute():

void addBatch()

void setDate(int parameterIndex,

Date x,

Calendar cal): void setNull(int parameterIndex,

int sqlType,

String typeName)

void setURL(int parameterIndex,

URL x)

void setRowId(int parameterIndex,

RowId x)

void setNString(int parameterIndex,

String value)

void setNCharacterStream(int parameterIndex,

Reader value,

long length)

void setNClob(int parameterIndex,

Reader reader)

CallableStatement

用来存储SQL存储过程的接口

JDBC API提供了SQL存储过程转移语法, 可以对所有的RDBMS使用相同的过程调用方式. 这种转移语法, 一种形式包含结果参数, 一种不包含. 如果使用结果参数必须将其注册为OUT参数, 其他参数可以用于输入, 输出或同时用于二者, 参数是通过连续的数字引用的, 第一个是1.

{?= call <procedure-name>[(<arg1>,<arg2>, ...)]}

{call <procedure-name>[(<arg1>,<arg2>, ...)]}

IN参数使用从PreparedStatement继承来的set方法. OUT参数必须在执行存储过程前注册. 执行之后通过此处的get方法, 获得它们的值.

CallableStatement可以返回一个或多个ResultSet对象. 多个ResultSet对象是通过从Statement继承来的操作进行处理的.

为了最大的可移植性, 调用的结果集合修改技术应该在获取输出参数值之前处理.

void registerOutParameter(int parameterIndex,

int sqlType):

按照顺序位置parameterIndex将OUT参数注册为JDBC类型sqlType. 在存储过程执行之前, 所有的OUT参数必须注册.

OUT参数的JDBC类型决定了读取参数值时get方法必须使用的Java类型.

如果output参数要返回的JDBC type是本数据库特有的, sqlType影视是java.sql.Types.OTHER. 通过getObject(int)获得该值.

void registerOutParameter(int parameterIndex,

int sqlType,

int scale): 如果输出参数是NUMERIC或DECIMAL类型时, 应该使用这种形式的registerOutParameter.

boolean wasNull(): 获取最后读取的OUT参数值是否是SQL NULL. 注意: 这个方法应该在getter方法后调用, 不然的话, 没有用来判定是不是NULL的值.

String getString(int parameterIndex): 以字符串的形式获取JDBC CHAR, VARCHAR, LONGVARCHAR类型参数的值.

void registerOutParameter(int parameterIndex,

int sqlType,

String typeName): 这一形式的registerOutParameter用于用户自定义或REF输出参数.

void registerOutParameter(String parameterName,

int sqlType):

void setNull(String parameterName,

int sqlType):

javax.sql.Interface DataSource:

到本DataSource对象代表物理数据源的连接工厂. DriverManager的替代.

DataSource interface由驱动厂家实现. 有三种类型的实现:

1. 基本实现 -- 产生标准的连接对象.

2. 连接池实现 -- 产生一个自动参与连接池的Connection对象. 此实现与中间层连接池管理器协同.

3. 分布式事务实现 -- 产生一个可用于分布式事务的连接, 而且总是参与连接池. 此实现和中间层事务管理器和几乎总是和连接池管理器协同工作. DataSource拥有可以在必要时被改变的properties. 如果data source被迁移到不同的服务器, server属性可以被改变. 好处就是因为data source的属性可以被改变, 任何处理data source的代码不必给改变.

通过DataSource获得的driver, 不必在DriverManager中注册. DataSource对象是通过lookup操作获得的, 然后被用来生成Connection对象.

在基本实现中, 通过DataSource获得的connection对象和通过DriverManager获得connection对象相同.

Method Detail:

Connection getConnection():

试着建立一个到本DataSource对象代表的数据源的连接.

Connection getConnection(String username,

String password): 使用给定的用户名密码, 试着建立到本DataSource对象代表的真实数据源之间的连接.

java.sql

Interface Driver

每一个driver必须实现的interface.

Java SQL框架允许多database drivers.

每一个driver应该提供一个实现Driver interface的类.

DriverManager会加载所有它能能找到的driver, 然后请求给点的连接, 它会依次询问每个driver试着连接到目的URL.

强烈建议每个Driver类小而独立, 以便于加载和查询Driver class时, 不必附带大量的支持代码.

当Driver class被加载了, 它应该产生自己的一个实例并且在DriverManager中注册, 这就是说, 用户可以调用如下方法加载和注册一个驱动:

Class.forName("foo.bah.Driver")

Method Detail:

Connection connect(String url, Properties info): 试着连接到给定的URL. 如果不是正确的driver, 应该返回null, 如果是正确的driver, 但是不能连接到数据库, 应该抛出异常.

boolean acceptsURL(String url): 确定driver是否能够理解所给的url.

DriverPropertyInfo[] getPropertyInfo(String url, Properties info) :

boolean jdbcCompliant(): 报告该driver是否是genuine JDBC Compliant driver .

java.sql

Interface Wrapper

当问题中的实例时proxy类的时候,有获取delegate实例能力的接口.

许多JDBC driver实现通过包装模式提供了超出传统JDBC API的扩展. 开发者希望能够访问到以proxy class instances的形式被包装的实际资源. 本接口描述了访问被包装资源的标准机制, 即允许直接访问resource delegates.

<T> T unwrap(Class<T> iface):返回通过实现给定接口从而允许访问非标注方法, 或代理没公开的方法的对象. 如果receiver实现了接口, 那么结果是receiver或receiver的代理. 如果receiver是一个包装切包装实现了接口, 那么结果是包装对象或包装对象的代理. 不然, 结果将对包装对象或结果代理递归的调用unwrap方法. 如果receiver不是包装切没有实现接口, 那么 将抛出SQLException异常.

boolean isWrapperFor(Class<?> iface): 如果实现了该接口, 或者直接或间接的是那个对象的包装, 返回true. 否走返回false. 该方法应该相比较unwrap代价更小, 以避免可能失败的昂贵的unwrap调用 , 如果该方法返回true, 那么unwrap同样的参数应该成功.

Types:

该类中定义了表示一般SQL类型的常量, 也叫JDBC类型.

Field Detail:

BIT, TINYINT, SMALLINT, INTEGER, BIGINT, FLOAT, REAL, DOUBLE, NUMBERIC, DECIMAL, CHAR, VARCHAR, LONGVARCHAR, DATE, TIME, TIMESTAMP, BINARY, VARBINARY, LONGVARBINAY, NULL,

OTHER: 表示SQL类型和具体数据库有关, gets方法映射到Java Object对象, 可以通过getObject和setObject方法访问. 

JAVA_OBJECT, DISTINCT,STRUCT,ARRAY,BLOB, CLOB, REF, DATALINK, BOOLEAN, ROWID, NCHAR,

NVARCHAR, LONGNVARCHAR, NCLOB, SQLXML.

ResultSet:

表示数据库结果集的表, 通常由查询语句的执行产生.

ResultSet对象包含一个指针, 指向当前行数据, 起始时, 指针指向第一行之前, next方法移动指针到下一行, 当ResultSet中没有更多行时, 返回false, 因此可以用在While循环中来迭代整个结果集.

ResultSet默认不可更新, 包含一个指针只能前移,因此只能够从头到尾遍历一次,

ResultSet接口提供了getter方法获得当前行的列的值,可以使用列的索引(index)或列名来获取列的值, 通过索引(index)效率更高, 列号从1开始.

JDBC驱动通过个getter方法,将递呈的数据转化为特定的Java类型, 返回适当的Java值, JDBC的定义包含一个表, 表示了课用在ResultSet类的getter方法中的SQL类型和Java数据类型的映射关系.

列名不是大小写敏感的, 如果通过一个列名调用getter方法, 如果多列有相同的名字, 第一个匹配的值会返回.

对于没有在SQL中明确指定名字的列, 最好使用编号. 如果使用列名, 程序员应该注意列名是对目标列的唯一引用, 可以通过SQL AS子句确定.

JDBC 2.0 API中新增加了一系列updater方法, 参数可以参考getter方法.

updater有如下两种使用方式:

1)更新当前行的列值, 在可滚动的ResultSet中, 指针可以向前向后移动, 到一个绝对或相对的位置.

rs.absolute(5); // moves the cursor to the fifth row of rs

rs.updateString("NAME", "AINSWORTH"); // updates the

// NAME column of row 5 to be AINSWORTH

rs.updateRow(); // updates the row in the data source

2) 插入数据到输入行. 可更新的ResultSet对象有一个特殊的行, 可以用来存储将被插入的行.

rs.moveToInsertRow(); // moves cursor to the insert row

rs.updateString(1, "AINSWORTH"); // updates the

// first column of the insert row to be AINSWORTH

rs.updateInt(2,35); // updates the second column to be 35

rs.updateBoolean(3, true); // updates the third column to true

rs.insertRow();

rs.moveToCurrentRow();

当生成ResultSet对象的Statement对象关闭, 重新运行, 或者查询下一个结果时,ResultSet对象自动关闭.

ResultSet对象列的数字, 类型和属性时ResultSetMetaData对象提供的, 这个对象可以通过ResultSet.getMetaData方法返回.

方法详解:

next():

让指针从当前位置前进一行, ResultSet指针初始时只在第一行之前, 第一次调用这个方法会使第一行成为当前行, 第二次调用时使第二行成为当前行. 当返回false时, 指针指向最后一行之后. 任何需要对当前行的操作都会引发SQLEXception异常.如果result set的 类型是TYPE_FORWARD_ONLY, 由JDBC驱动的实现决定是返回false还是返回SQLEXception.

如果有个输入流(input stream)为当前的行打开, 对next()方法的调用将会隐含的关闭这个流, ResultSet对象的waring chain将会被清除.

close():

立即释放ResultSet对象的数据库和JDBC资源,而不是等待其自动关闭.

ResultSet对象的关闭不会关闭这个ResultSet对象产生的Blob, Clob或Nclob对象, 这些对象会在本次交易过程中一直有效, 知道它们调用了自己的free()方法.

注意: ResultSet对象会被产生它的Statement对象自动关闭, 当这个Statement对象关闭, 重新执行,或者从多个结果序列中获取下一个结果时.

boolean wasNull():

返回最后一个读取的column的值是不是SQL NULL, 注意: 你必须先调用一个列的getter方法试着去读取列的值, 然后调用wasNULL看一下该值是否是SQL NULL. 如果最后读取列的值是SQLNULL, 返回true, 否则返回false.

getString(int columnIndex):以Java语言中String类型返回当前ResultSet对象的当前行的指定类的值

boolean getBoolean(int columnIndex):

以Java语言中的boolean类型返回ResultSet对象的当前行指定列的值.

如果指定的列是数据类型是CHAR或VARCHER并且包含"0", 或者 是数据库类型的BIT, TINYINT, SMALLINT, INTEGER或BIGINT 且 包含一个0, 返回false, 如果上述的情况包含的分别是"1"和1, 将返回true.

getByte():以byte类型返回当前ResultSet对象的当前行的指定列的值.

getShort(int colomn):

getInt(int colomn):

getLong(int colomn):

getFloat(int colomn):

getDouble(int colomn):

getBigDecimal(int colomn)(不建议)以BigDecimal类型返回指定的值.

getBytes(int colomn):将驱动的字节数据返回到byte[]中.

getDate(int colomn):

getTime(int colomn):

getAsciiStream(int colomn): 这个方法特别适合查询LONGVARCHAR的值.

getBinaryStream(int colomn): 适合返回LONGVARBINARY的值.

getStream():

getBoolean():

getByte(String columnLabel): 以byte类型返回当前行指定列的值.

columnLabel1: SQL AS子句指定的类的别名. 如果没有定义别名, 则label就是列名.

getShort(String columnLabel):

getInt(String columnLabel):

getLong(String columnLabel):

getFloat(String columnLabel):

getDouble(String columnLabel):

getBigDecimal(String columnLabel, int scale):

scale: 精度(小数点右边的位数).

getBytes(String columnLabel):

getDate(String columnLabel):

getTime(String columnLabel):

getTimestamp(String columnLabel):

getAsciiStream(String columnLabel):

getBinaryStream(String columnLabel):

getWarnings():

clearWarnings():

getCursorName():

ResultSet的当前行同样也是SQL游标的当前行.

getMetaData():

getObject(int columnIndex):

getObject(String columnLabel):

int findColumn(String columnLabel): 通过别名返回列的索引.

Reader getCharacterStream(int columnIndex):

以java.io.Reader返回ResultSet对象当前行指定列的值.

Reader getCharacterStream(String columnLabel):

BigDecimal getBigDecimal(int columnIndex):

BigDecimal getBigDecimal(String columnLabel)

boolean isBeforeFirst(): 查询指针是否在第一行之前.

boolean isAfterLast(): 查询指针是否在最后一行之后.

boolean isFirst():

boolean isLast():查询是否是ResultSet的最后一行. 调用isLast代价相当巨大. 驱动需要在往前获取一行, 以确定是不是最后一行.

void beforeFirst():

void afterLast():

boolean first(): 如果指针移动到了有效行, 返回true, 如果result set中没有行, 返回false.

boolean last():

int getRow(): 返回当前的行号, 第一行是1, 第二行时2, 一次类推.

boolean absolute(int row): row是正数时, 指针移动到以结果集开头为参考的行. 第一行是row 1, 第二行是row 2, 以此类推.

如果row是负数时, 指针移动到以结果集结尾为参考行, 比如: 调用absolute(-1)将指针移动到最后一行. absolute(-2) 把指针移动到倒数第二行.

boolean relative(int rows): 移动指针到相对位置, 试图将指针移动到超出first/last范围的行, 将把指针移动到first/last行. 调用relative(0)也是有效的, 但是不会移动指针.

row表示指针需要移动的行数. 正值向前移动指针. 负值向后移动指针.

boolean previous() : 将指针移动到结果集的前一行. 如果返回false, 说明指针被移动到了第一行之前, 任何对当前行的操作都会返回SQLException异常.

setFetchDirection(int direction): 设定ResultSet中行的读取方向. 初始值是有Statement对象决定的, fetch direction可以在任何时间改变. fetch direction可能的值由ResultSet.FETCH_FORWARD, ResultSet.FETCH_REVERSE或ResultSet.FETCH_UNKNOWN.

int getFetchDirection():

void setFetchSize(int rows): 设定每次从数据库中读取的行数. 如果fetch size被设定为0, JDBC将自主决定最佳的fetch size. 默认值是Statement对象设定的.

int getFetchSize():

返回结果集的类型, 返回的值可能是:

ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE, or ResultSet.TYPE_SCROLL_SENSITIVE

int getConcurrency(): 返回当前结果集的concurrency模式. 可能的值有: ResultSet.CONCUR_READ_ONLY or ResultSet.CONCUR_UPDATABLE

boolean rowUpdated(): 查看当前的行是否被修改. 返回值依赖于结果集支不支持修改查询.

boolean rowInserted():

boolean rowDeleted(): 删除行会造成结果集的空洞, 该方法检测这些空洞.

void updateNull(int columnIndex):可用在当前行和插入行中, 将指定的列设置为NULL. 该方法不会修改底层的数据库. 可有调用updateRow或insertRow来修改底层的数据库.

void updateBoolean(int columnIndex, boolean x):

void updateByte(int columnIndex,

byte x):

void updateShort(int columnIndex,

short x):

void updateInt(int columnIndex,

int x):

void updateLong(int columnIndex,

long x):

void updateFloat(int columnIndex,

float x)

void updateDouble(int columnIndex,

double x)

void updateBigDecimal(int columnIndex,

BigDecimal x)

void updateString(int columnIndex,

String x)

void updateBytes(int columnIndex,

byte[] x)

void updateDate(int columnIndex,

Date x)

void updateTime(int columnIndex,

Time x)

void updateTimestamp(int columnIndex,

Timestamp x):

void updateAsciiStream(int columnIndex,

InputStream x,

int length):

void updateBinaryStream(int columnIndex,

InputStream x,

int length):

void updateCharacterStream(int columnIndex,

Reader x,

int length):

void updateObject(int columnIndex,

Object x,

int scaleOrLength):

如果第二个参数是一个InputStream, 那么这个输入流必须包含scaleOrLength个字节数. 如果是一个Reader, 那么这个Reader必须包含scaleOrLength个字符. 上述条件不满足, 将会产生SQLException.

void updateObject(int columnIndex,

Object x)

void updateNull(String columnLabel):

void updateBoolean(String columnLabel,

boolean x):

void updateByte(String columnLabel,

byte x):

void updateShort(String columnLabel,

short x):

void updateInt(String columnLabel,

int x):

void updateLong(String columnLabel,

long x):

void updateFloat(String columnLabel,

float x):

void updateDouble(String columnLabel,

double x)

void updateBigDecimal(String columnLabel,

BigDecimal x):

void updateString(String columnLabel,

String x):

void updateBytes(String columnLabel,

byte[] x):

void updateDate(String columnLabel,

Date x):

void updateTime(String columnLabel,

Time x):

void updateTimestamp(String columnLabel,

Timestamp x):

void updateAsciiStream(String columnLabel,

InputStream x,

int length):

void updateBinaryStream(String columnLabel,

InputStream x,

int length):

void updateCharacterStream(String columnLabel,

Reader reader,

int length):

void updateObject(String columnLabel,

Object x,

int scaleOrLength):

void updateObject(String columnLabel,

Object x):

void insertRow(): 将ResultSet对象的插入行内容, 插入到数据库中. 调用这个指针时, 光标必须指在插入行上.

void updateRow(): 当对ResultSet当前行的更新添加到数据库中. 当指针指向出入行时, 此方法不能调用.

void deleteRow(): 删除ResultSet中的当前行,同时从底层数据库中删除. 当指针指向插入行时, 不能调用这个方法.

void refreshRow(): 用数据库中的最新数据刷新当前行. 当指针指向insert row时, 该方法不能被调用. 如果fetch size大于1, JDBC可能实际上一次更新多行.

所有的值都是根据事务的隔离级别和光标敏感度被更新. 如果refreshRow在Updater方法之后, updateRow方法之前被调用, 所有对行的更新都会丢失. 频繁的调用refreshRow将会降低性能.

void cancelRowUpdates(): 可以在Updater之前, 和updateRow之后, 调用, 回滚对当前行的修改. 如果没有修改或者已经调用了updateRow, 这个方法没有什么影响.

void moveToInsertRow(): 将光标移动到插入行.

当光标被移动到插入行时, 当前的光标位置被记住. insert row是可修改结果集的特殊行. 它本质上是一个缓冲区, 在这个缓冲区中, 新行在被插入Resultset之前, 可以在调用updater方法后被建立. 当光标在插入行时, 只有updater, getter, insertRow可以被调用. 在调用insertRow方法之前调用本方法要求结果集所有列必须有给定的值. 必须在updater方法之后才能调用getter方法.

moveToCurrentRow(): 将光标移动到被记住的位置, 通常是当前行, 如果光标没有指向插入行,该方法不会起作用.

Statement getStatement(): 获取产生该结果集的Statement对象. 如果结果集是通过其他方式产生的, 例如通过DatabaseMetaData的方法, 本方法将返回null.

Ref getRef(int columnIndex): 以Ref对象的形式返回结果集中当前行的指定列.

Blob getBlob(int columnIndex):

Clob getClob(int columnIndex)

Date getDate(int columnIndex,

Calendar cal):

Date getDate(String columnLabel,

Calendar cal):

Time getTime(int columnIndex,

Calendar cal):

Time getTime(String columnLabel,

Calendar cal):

Timestamp getTimestamp(int columnIndex,

Calendar cal):

Timestamp getTimestamp(String columnLabel,

Calendar cal):

URL getURL(int columnIndex)

throws SQLException:

URL getURL(String columnLabel):

void updateRef(int columnIndex,

Ref x):

void updateRef(String columnLabel,

Ref x):

void updateBlob(int columnIndex,

Blob x):

void updateBlob(String columnLabel,

Blob x):

void updateClob(int columnIndex,

Clob x):

void updateClob(String columnLabel,

Clob x):

void updateArray(int columnIndex,

Array x):

void updateArray(String columnLabel,

Array x):

RowId getRowId(int columnIndex):

RowId getRowId(String columnLabel):

RowId getRowId(String columnLabel):

void updateRowId(int columnIndex,

RowId x):

void updateRowId(String columnLabel,

RowId x):

int getHoldability():either ResultSet.HOLD_CURSORS_OVER_COMMIT or ResultSet.CLOSE_CURSORS_AT_COMMIT

boolean isClosed():

void updateNString(int columnIndex,

String nString): 被用来更新NCHAR,NVARCHAR和LONGNVARCHAR.

void updateNString(String columnLabel,

String nString):

void updateNClob(int columnIndex,

NClob nClob):

void updateNClob(String columnLabel,

NClob nClob):

NClob getNClob(int columnIndex):

NClob getNClob(String columnLabel):

SQLXML getSQLXML(int columnIndex)

SQLXML getSQLXML(String columnLabel):

void updateSQLXML(int columnIndex,

SQLXML xmlObject):

void updateSQLXML(String columnLabel,

SQLXML xmlObject):

String getNString(int columnIndex):

String getNString(String columnLabel):

Reader getNCharacterStream(int columnIndex):

Reader getNCharacterStream(String columnLabel):

Reader getNCharacterStream(String columnLabel):

void updateNCharacterStream(int columnIndex,

Reader x,

long length):

void updateNCharacterStream(String columnLabel,

Reader reader,

long length):

void updateAsciiStream(int columnIndex,

InputStream x,

long length):

void updateBinaryStream(int columnIndex,

InputStream x,

long length):

void updateCharacterStream(int columnIndex,

Reader x,

long length):

void updateAsciiStream(String columnLabel,

InputStream x,

long length)

void updateBinaryStream(String columnLabel,

InputStream x,

long length):

void updateCharacterStream(String columnLabel,

Reader reader,

long length):

void updateBlob(int columnIndex,

InputStream inputStream,

long length):

void updateBlob(String columnLabel,

InputStream inputStream,

long length):

void updateClob(int columnIndex,

Reader reader,

long length):

void updateClob(String columnLabel,

Reader reader,

long length):

void updateNClob(int columnIndex,

Reader reader,

long length):

void updateNClob(String columnLabel,

Reader reader,

long length):

void updateNCharacterStream(int columnIndex,

Reader x):

void updateNCharacterStream(String columnLabel,

Reader reader):

void updateAsciiStream(int columnIndex,

InputStream x):

void updateBinaryStream(int columnIndex,

InputStream x):

void updateCharacterStream(int columnIndex,

Reader x):

void updateAsciiStream(String columnLabel,

InputStream x):

void updateBinaryStream(String columnLabel,

InputStream x):

void updateCharacterStream(String columnLabel,

Reader reader):

void updateBlob(int columnIndex,

InputStream inputStream):

void updateBlob(String columnLabel,

InputStream inputStream):

void updateClob(int columnIndex,

Reader reader):

void updateClob(String columnLabel,

Reader reader):

void updateNClob(int columnIndex,

Reader reader):

void updateNClob(String columnLabel,

Reader reader):

附录:

java.util.Date类详解:

该类代表一个特定时刻的时间,精读为毫秒级. 尽管Date类本意是反映coordinated universal time(UTC)(标准时间), 但是它并不是那么精确. 原因是几乎所用的现在操作系统都假定1 day = 24 * 60 * 60 = 86400 seconds, 但是在UTC中, 大约一年或两年就会多余一秒, 叫做"leap second", 多出来的一秒, 一般加在一天的最后一秒, 而且总是December 31 or June 30. 一些电脑是参考格林威治时间(GMR, Greenwich mean time)来定义的, 即universal time(UT). GMT是民间说法, UT是科学说法, 两种说法都是指同一种标准. UTC和UT的区别如下: UTC基于原子时钟, 而UT是基于天文观测

因为地球的不规则旋转(地球以复杂的方式时快时慢),UT运行也不是很一致,UTC引入Leap seconds一遍是UTC和UT1保持在0.9S内.

在Date的所有方法中:年份y用整数y表示. 月份使用0~11的整数表示, 0是January, 1是February, 等等, 11是December.

每月的日期是用1~31的整数表示的,

hour(小时): 是用0~23的整数表示的, 从物业到1 a.m是hour 0, 正午到1 p.m是hour 12.

minute(分钟)是用0 ~ 59的整数表示的.

second(秒)是用0 ~ 61的整数表示的, 60和61只在出现leap second的时候使用,

getTime():返回一个自January 1, 1970, 00:00:00 GMT以来的毫秒数.

setTime():

boolean before(Date when):

boolean after(Date when):

boolean equals(Object obj):

int compareTo(Date anotherDate):返回值: 如果时间相同返回0, 如果返回负数, 表示的是当前的Date比参数Date要早. 如果返回值是整数, 表示当前Date比参数Date要晚.

hashCode():返回Date对象的hash code, 返回值是getTime()方法返回值两部分的异或. 表达式如下:

(int)(this.getTime()^(this.getTime() >>> 32))

toString(): 以如下格式返回Date()对象:

dow mon dd hh:mm:ss zzz yyyy

dow: 表示day of the week(Sun, Mon, Tue, Wed, Thu, Fri, Sat)

java.util.Calendar类详解:

Calendar类是一个提供特定时间和calender fields之间进行转化和对calender fields进行操作的抽象类. 时间可以使用millisecond值(is an offset from the Epoch, January 1, 1970 00:00:00.000 GMT (Gregorian))表示

Calendar提供一个getIntance方法, 获得一个Calendar对象, 该对象的calendar fields已经被初始化为当前的时间和日期.

Calendar rightNow = Calendar.getInstance();

获取和设置Calendar Field值:

Calendar有两种模式来翻译calendar fields, 一种是lenient模式, 一种是nonlenient, 当一个Calendar对象出于lenient模式时, 它可以接受一个更加宽泛的值, 相比较它可以产生的. 当使用get() 方法时, 所有的calendar fields将会被规范化. 例如 a lenient GregorianCalendar interprets MONTH == JANUARY, DAY_OF_MONTH == 32 as February 1.

当Calendar不处于non-lenient mode时, calendar fields中的任何不一致, 都将引发异常.

First Week:

Calendar通过如下参数定义一个本地化的七天制星期: 每周的第一天 和 第一周的最小天数限制(1~7).

当设置WEEK_OF_MONTH或WEEK_OF_YEAR域是, Calendar必须决定月或年的第一周作为参考点. 月或年的第一周是年或月的指从getFirestDayOfWeek() 开始, 包含至少getMinimalDaysInFirstWeek()天数的最早的七天. 第一周之前的周别编码为…, -1, 0; 之后的周被编码为2, 3, …

注意: get() 返回的标准编号可能不同. 例如特定的Calendar子类, 可能将本年第一周之前的周, 作为去年的第n个周.

Calendar Fields Resolution:

通过Calendar fields计算日期和时间的时候, 可能遇到信息不足和格式不一致的情况, calendar将会按照下面的方式处理这些情况:

如果calendar field的值发生冲突, Calendar优先处理最近设置的字段. 将使用最近设置的单个字段所确定的最近组合. calendar fields默认的组合如下:

For the date fields:

YEAR + MONTH + DAY_OF_MONTH

YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK

YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK

YEAR + DAY_OF_YEAR

YEAR + DAY_OF_WEEK + WEEK_OF_YEAR

For the time of day fields:

HOUR_OF_DAY

AM_PM + HOUR

在选择的组合方式中,任何没有设置值的calendar fields将使用他们默认的值. 每个默认值和具体的calendar systems有关.

注意: 对于解析有歧义的特定时间点, 采用如下的处理方法:

1) 23:59 is the last minute of the day and 00:00 is the first minute of the next day. Thus, 23:59 on Dec 31, 1999 < 00:00 on Jan 1, 2000 < 00:01 on Jan 1, 2000.

2) Although historically not precise, midnight also belongs to "am", and noon belongs to "pm", so on the same day, 12:00 am (midnight) < 12:01 am, and 12:00 pm (noon) < 12:01 pm

Field Manipulation(域的操作):

calendar fields可以通过三种方法进行改变: set(), add(), 和roll().

set(f, value)改变calendar field f到value. 此外, 它还设定了内部变量, 表示f应经被修改. 虽然f的值立即被修改了, 但是calendar的时间值不会被重新计算, 知道下次调用get(), getTime(), getTimeInMillis(), add(), roll()方法. 因此, 多次调用set()不会导致多次, 不必要的计算. 通过set() 修改一个值, 其余的值也可能(根据calendar field, calendar field value, calendar field system)变化. get(f)返回的值不一定是set()设定的值. 具体值由具体calendar类决定.

例如: 假如GregorianCalendar被设置为August 31, 1999. 调用set(Calendar.MONTH, 假定 GregorianCalendar 最初被设置为 1999 年 8 月 31 日。调用 set(Calendar.MONTH, Calendar.SEPTEMBER) 将该日期设置为 1999 年 9 月 31 日。如果随后调用 getTime(),那么这是解析 1999 年 10 月 1 日的一个暂时内部表示。但是,在调用 getTime() 之前调用 set(Calendar.DAY_OF_MONTH, 30) 会将该日期设置为 1999 年 9 月 30 日,因为在调用 set() 之后没有发生重新计算。

add(f, delta): 等效于 调用set(f, get(f) + delta)

Add rule1: f调用后的值减去调用前的值就是增加的值delta. 对所有的溢出取模, 当一个域(field)的值超出了它值的范围就会溢出, 当出现溢出时, 相邻的高位增加或减少, field的值会被调整到它的范围内.

Add rule2: 如果更小的字段被设定为不可变的, 当field f或其他约束发生变化,它的最大值和最小值会发生变化, 因此不可能和之前的值保持一样. 它的值被调整为尽量接近期望值. 更小的字段(smaller field)是指更小的时间单位. HOUR是一个比DAY_OF_MONTH. 对于不期望是可变的更小字段(smaller field), 不必进行调整. calendar系统会决定哪些字段是不可变的.

另外, 不像set(), add()方法强制要求一个立即的对calendar的milliseconds和all fields的recomputation

roll(f, delata): 添加delta值到字段f, 不改变更大的字段. 这个等效于调用add(f, data)除了以下的规则.

Roll rule: 调用该方法后, 不会改变更大字段的值. 更大的字段表示更大的时间单位. 例如DAY_OF_MONTH是比HOUR更大的字段.

Usage model: 为了形象的说明add() 和roll()的行为, 假定如下场景, 一个用户界面包含年月日的增加减少按钮, 当当前的现实是January 31, 1999时, 用户点击增加月份的按钮时, 现实February 28, 1999显然更加合理, 而不是现实March 3,1999. 当再次点击月份增加按钮时, 应该显示March 31, 1999, 而不是March 28, 1999. 通过保存出事date, 根据更大字段是否应该被影响决定使用add()或roll(), 可以使界面表现的更加直观合理.

Field Detail:

ERA: 用来表示纪元得字段数. 例如Julian calendar中的AD或BC.

YEAR表示年份, 与具体的calendar类有关.

MONTH:表示月份, 与具体的类有关, 例如Gregorian和Julian历法的JANUARY是0, 但是最后一个月份的数字跟该年中包含的月份数有关.

WEEK_OF_YEAR:

表示当前年份的周数, 本年的第一周是由getFirstDayOfWeek() 和getMinimalDaysInFirstWeek()定义的, 有值1, 子类定义第一周之前的天数, 即WEEK_OF_YEAR的值.

WEEK_OF_MONTH:

表示当前月的周数, 每月的第一个周由getFirstDayOfWeek()和getMinimalDaysInFirstWeek(), 值为1, 子类以本月第一周之前的天数定义WEEK_OF_MONTH.

DATE: 表示本月的几号, 是DAY_OF_MONTH的同义词. 每月的第一天是1.

DAY_OF_MONTH: 同上.

DAY_OF_YEAR: 表示当前年份的第几天, 一年的第一天值为1.

DAY_OF_WEEK:

表示星期几, 可能的取值是: SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, and SATURDAY

DAY_OF_WEEK_IN_MONTH:

用于表示当前天数所处第几个星期. 和DAY_OF_WEEK可以唯一的确定一周的一天. 和WEEK_OF_MONTH和WEEK_OF_YEAR不同, 这个字段的值不依赖于getFirestDayofWeek()或getMimimalDaysInFirstWeek(), DAY_OF_MONTH 1到7总是和DAY_OF_WEEK_IN_MONTH 1, 8 ~14和2 DAY_OF_WEEK_IN_MONTH 2对应.

DAY_OF_WEEK_IN_MONTH 0表示 DAY_OF_WEEK_IN_MONTH 1之前的那周, 一次类推. 负数表示从从当前月末倒序计数. 所以一个月的最后一个星期天可以如下确定: DAY_OF_WEEK = SUNDAY, DAY_OF_WEEK_IN_MONTH = -1. 因为负数是倒序计数的, 所以他们和正值的排列方式不同, 例如, 如果如果一个月包含31天, DAY_OF_WEEK_IN_MONTH -1会跨越 DAY_OF_WEEK_IN_MONTH 5和 DAY_OF_WEEK_IN_MONTH 4末尾.

AM_PM:表示HOUR是午前还是午后.

HOUR: 表示上午或下午的小时数, HOUR使用12小时制(0
~11), 正午和午夜用0, 不用12表示.

HOUR_OF_DAY: 表示全天的小时数, 使用24小时制.

MINUTE: 表示小时内的分数.

SECOND: 表示分钟内的秒数.

MILLISECOND: 表示秒里面的毫秒数.

ZONE_OFFSET: 表示到GMT时间的用毫秒表示的偏移量. 如果TimeZone的实现子类支持历史的GMT偏移改变, 这个字段反映该Calendar的正确GMT偏移.

DST_OFFSET: 该字段表示到daylight saving的偏移量, 用毫秒表示. 如果子类支持历史的Daylight Saving Time schedule改变, 这个字段可以正确表示正确的daylight saving offset值.

FIELD_COUNT: 表示可以由get和set识别的独立的字段. Field标号从0到FIELD_COUNT-1 .

SUNDAY:

MONDAY:

TUESDAY:

WEDNESDAY:

THURSDAY:

FRIDAY:

SATURDAY:

JANUARY:

FEBRUARY:

MARCH:

APRIL:

MAY:

JUNE:

JULY:

AUGUST:

SEPTEMBER:

OCTOBER:

NOVEMBER:

DECEMBER:

UNDECIMBER: 表示第13个月份, 肯能在农历中使用.

AM:

PM:

ALL_STYLES: 指示所有风格名称的 getDisplayNames 的风格说明符,比如 "January" 和 "Jan"。

SHORT: getDisplayName and getDisplayNames的风格说明符, 表示一个短的名字.

LONG: etDisplayName and getDisplayNames的风格说明符, 表示长名字.

数组fields: 表示当前日历的各字段的值, 这是FIELD_COUNT的整数序列, 索引的范围是ERA到DST_OFFSET

boolean[] isSet :

time: 当前的时间. 用从January 1, 1970, 0:00:00 GMT开始的毫秒数表示.

isTimeSet:

areFieldsSet: 如果 fields[] 与当前的设置时间同步,则返回 true。如果返回 false,则在下一次试图获得某一字段的值时,将强行重新计算 time 当前值中的所有字段。

Method detail:

getInstance():

public static Locale[] getAvailableLocales(): 返回所有可用用于getInstance方法返回本地化的实例的locales, 本数组一定至少返回一个Locale实例, 这个实例时Locale.US

computeTime(): 将field[]内的值, 转化为毫秒数.

computeField(): 将毫秒数转化为fields[]的值.

getTime(): 返回Date实例来表示从Epoch开始的时间毫秒值.

setTime(Date date):

getTimeInMillis():

setTimeInmillis():

get(int field): 返回已给calendar指定的字段的值. In lenient mode, 所有的字段被规范化. 在non-lenient模式, 没有字段值被验证, 如果字段的值超出范围, 将抛出异常. 规范化和验证是由complete()处理的.

internalGet(int field):

获取给定calendar字段的值, 这个方法不进行规范化和验证.

set (int field, int value): 将给定的calendar值设定为给定的值. 这个值不会被解释, 不管在何种leniency模式.

set(int year, int month, int date):

设定calendar字段的YEAR, MONTH, DAY_OF_MONTH值. 其他字段的值被保留.

set(int year, int month, int date, int hourOfDay, int minute)

public final void set(int year, int month, int date, int hourOfDay, int minute, int second)

clear(): 将calendar的各字段和time值设置为"undefined", 对所有calendar字段, isSet()将返回false, date和time运算都把它们当做从来没有设定过. Calendar实现类会使用特定默认字段值参与运算.

clear(int field):

isSet(int field): 查看特定的calendar字段是否已经设置了一个值.

getDisplayName(int field, int style, Locale locale): 使用给定的style和locale返回给定的calendar字段值.

getDisplayNames(int field, int style, Locale locale): 返回一个包含所有calendar用特定风格和地域表示字段名和字段值的映射.

complete(): 填充所有没有设置的calendar字段.

boolean equals(Object obj): 只有obj和当前对象是同样的calendar system, 表示同样的值.

boolean before(Object when):

boolean after(Object when):

int compareTo(Calendar anotherCalendar): 返回值: 0: 表示参数表示的时间和当前calendar表示的时间相同. <0: 当前calendar表示的时间早于参数表示的时间. >0: 表示当前calendar表示的时间晚于参数表示的时间.

add(int field, int amout):

roll(int field, boolean up): 在不改变高位的情况下, 增加或减少当前field一单位值.

roll(int field, int amout):

setTimeZone(TimeZone value):

getTimeZone():

setLenient(boolean lenient):

isLenient():

setFirstDayOfWeek(int value): 设定每周的第一天, 例如: 美国是SUANDAY, 法国是MONDAY.

getFirstDayOfWeek():

setMinimalDayOfWeek():

getMinimalDayOfWeek():

getMinimun(int field):

getMaximum(int field):

getGreatestMinimum(int field):

getLeastMaximum():

getActualMinimum():

getActualMaximum():

DateFormat类详解

语言独立的格式化和解析日期和时间的类. 其子类,可以格式化(formatting), 解析(parsing), 和规范化(normalization). 日期是用Date对象或者自January 1, 1970, 00:00:00 GMT以来的毫秒数来表示的.

用当前位置格式化date, 使用如下工厂方法:

myString = DateFormat.getDateInstance().format(myDate);

这样可以在不获取本地语言和国家风俗条件下,就可以格式化为本地格式. 当多次需要格式时, 可以此案获得一个DateFormat实例, 然后多次调用它.

DateFormat df = DateFormat.getDateInstance();

for (int i = 0; i < myDate.length; ++i) {

output.println(df.format(myDate[i]) + "; ");

}

如果需要用别的地点来格式化Date对象, 可以在调用getDateInstance()时声明.

DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, Locale.FRANCE);

也可以使用DateFormat进行解析:

myDate = df.parse(myString);

有很多可用的工厂方法: getDateInstance获得该国正常的date格式. getTimeInstance获得该国的time format, 使用getDateTimeInstance获得日期和时间格式. 可以向不同的工厂方法传递不同的选项从而控制结果的长度; 从SHORT到MEDIUM,从 LONG到FULL. 具体结果与locale有关, 不过一般如下:

SHORT: 完全是数字, 比如12.13.52或3:30pm.

MEDIUM: 稍微长一点, 比如Jan 12, 1952.

LONG: 更长一点, 比如January 12, 1952或3:30:32pm.

FULL: 相当详尽,如果: Tuesday, April 12, 1952 AD or 3:30:42pm PST

如果你乐意, 你也能在format中设置time zone. 如果你还想控制format和parsing的更多细节, 你可以试着将从工厂方法得来的DateFormat转化成SimpleDateFormat. 这对大多数国家都是有效的. 记住要将其放在try块中.

对ParsePosition和FieldPosition使用parse和format, 可以使你:

①渐进的解析一个字符串.

②对齐任何特殊字段, 或者找出在屏幕上的选择位置.

同步:

日期格式不是同步的, 建议为每个线程创建独立的格式实例, 如果多个线程同时访问一个格式, 则它必须保持外部同步.

Field Detail:

calendar:产生field values的calendar对象, 这个对象被DateFormat用来镜像date和time的格式化. 子类应该正确的本地化格式初始化该DateFormat的calendar对象.

numberFormat: DateFormat用来初始化date和time数字的number formatter.

ERA_FIELD:

YEAR_FIELD:

MONTH_FIELD:

DATE_FIELD:

HOUR_OF_DAY1_FIELD:

HOUR_OF_DAY0_FIELD:

MINUTE_FIELD:

SECOND_FIELD:

MILLISECOND_FIELD:

DAY_OF_WEEK_FIELD:

DAY_OF_YEAR_FIELD:

DAY_OF_WEEK_IN_MONTH_FIELD:

WEEK_OF_YEAR_FIELD:

WEEK_OF_MONTH_FIELD:

AM_PM_FIELD:

HOUT1_FIELD:

HOUR0_FIELD:

TIMEZONE_FIELD:

FULL:

LONG:

MEDIUM:

SHORT:

DEFAULT:

Class Locale

Locale对象, 代表了一个特定的地利, 政治或文化区域. 如果一个操作需要一个Locale来执行任务, 叫做locale-sensitive(地域敏感), 使用Locale来为用户修饰信息. 构造方法如下:

Locale(String language)

Locale(String language, String country)

Locale(String language, String country, String variant)

Locale类提供了一些方便的静态变量, 方便你生成常用的locale.

Properties

Properties: 代表一组持久的properties. Properties可以保存到stream中, 或者从stream中加载. 在property列表中的key和其对应的值都是字符串.

java.sql.Date类简介:一个对简单毫秒数的封装, 一遍JDBC当做SQL DATE值进行识别. 毫秒数是从January 1, 1970 00:00:00.000 GMT的经过的值, static valueOf(String s):将一个JDBC日期格式的日期转换为Date值.

class Timestamp

是对java.util.Date类的简易包装, 可以让JDBC API将此类是为SQL TIMESTAMP值. 它增加了保存SQL TIMESTAMP极小时间的能力. 精确到纳秒.

Interface Ref

SQL REF值在Java语言中的映射, 指向数据库中的SQL structured type value.

Interface Blob:

SQL BLOB值的Java语言表示. An SQL BLOB是用来存储二进制大对象(Binary Large Object)内建类型. 默认的, 驱动器通过SQL locator来实现Blob对象, 这意味着Blob对象包含一个逻辑的指向SQL BLOB指针, 而不是包含数据本身. Blob对象, 在整个事务处理过程中都有效.

Interface Clob

SQL CLOB类型的Java实现. An SQL CLOB是用来在数据库中存储字符大对象(Character Large Object)的内建类型. 驱动默认使用SQL locator(CLOB)来实现Clob, 也就说, Clob对象包含一个指向SQL CLOB数据的指针, 而不是数据本身. Clob对象在整个事务期间有效.

Interface Array

SQL ARRAY类型的Java实现. 默认Array值是transaction-type的对SQL ARRAY值的引用. 默认使用SQL LOCATOR(array)实现.

Interface RowID

SQL ROWID值的Java实现. SQL ROWID是一个内置类型, 表示database table中一个特定行的地址. 该地址是逻辑的还是物理的是由初始数据源决定的.

Interface SQLXML

SQL XML类型的Java实现. XML是用来存储XML值的内置对象. 默认情况下驱动使用逻辑指针指向XML数据, 而不是数据本身. SQLXML在事务处理期间有效.