打开一个与查询引擎的链接,须要调用DriverManager.getConnection()方法。经过调用该方法,能够取得一个Connection类的实例(Instance),这个实例就在应用程序和查询引擎创建了一个链接,使用这个链接,咱们就能经过查询引擎系统操做各个节点了。要获得Connection的实例,就须要应用程序输入用户名、密码、查询引擎 JDBC驱动特定的链接语句以及想要链接的查询引擎库名称。用户将有两种链接方法来与查询引擎创建链接。html
1. 指定URL、用户名和密码java
下面这个方法用URL、用户名、密码做为参数:程序员
Class.forName(“com.scistor.swift.jdbc.Driver”);sql
getConnection(String URL, String user, Stringpassword);编程
URL的格式是:swift
jdbc:swift://host/database数组
jdbc:swift://host:port/database服务器
其中:网络
参数函数 |
参数说明 |
host |
服务器的主机名。 |
port |
服务器监听的端口号。缺省时是查询引擎默认的端口号(2003) |
database |
查询引擎库名。此处的database就是在安装时建立的查询引擎库所对应的名字 |
好比想要链接查询引擎,它的URL、用户名、密码分别是:
Stringurl = “jdbc:swift://localhost/SYSTEM”;
Stringname = “SYSDBA”;
Stringpassword = “SYSDBA”;
那么就能够很容易的得到一个与查询引擎的链接了
Connectioncon = DriverManager.getConnection(url,name,password);
这就意味着用户经过用户名”SYSDBA”,密码”SYSDBA”链接到了本地的名称为“SYSTEM”的查询引擎。
2. 指定URL和Properties对象
指定URL的方法同上面同样,如今咱们就来指定Properties对象:
java.util.Properties info = newjava.util.Properties();
info.setProperty(“user”,”SYSDBA”);
info.setProperty(“password”,”SYSDBA”);
如今就能够得到链接了:
Connection con =DriverManager.getConnection(url,info);
一旦链接上了查询引擎,也就是说,已经得到了一个Connection的实例,那么就能够经过该Connection实例建立一个Statement对象。经过Statement对象来处理不一样的SQL语句。咱们就用前面得到的Connection实例con来建立一个Statement对象,下面就是一个建立Statement对象的例子:
Statement stmt = con.createStatement();
这个操做是彻底遵循JDBC标准规范的,没有任何要处理关于特定查询引擎 JDBC驱动的地方。
若是须要查询查询引擎中的数据,只须要调用Statement对象的executeQuery()方法。这个方法以SQL语句做为参数,方法执行完后返回一个JDBC的ResultSet对象。为了保持连续性,咱们就使用上面已经建立的Statement对象。好比咱们要从一张表名为TEMP的表中选出全部数据,咱们只要简单的调用executeQurey()方法:
ResultSet rs = stmt.executeQuery(“SELECT * FROMTEMP”);
同上面同样,这个操做也是彻底遵循JDBC标准规范的,没有任何要处理关于特定查询引擎 JDBC驱动的地方。
注:假如咱们已经在查询引擎中建立了一个名为TEMP的表,它有两列分别为ID(INT),VALUE(STRING)。后面的章节将屡次使用到这个表。
一旦执行了SQL语句,得到了ResultSet对象,那么就能够经过调用Resulset对象中的next()操做遍历ResultSet操做,以得到每条记录。若是next()方法返回为true,那么就意味着如今有记录能够读取出来,接着就能够调用ResultSet对象的getXXX()方法来取得对应列的值,XXX表明了要取得的列的类型,该方法是以列序号或列名为参数的,下面就从上面得到的ResultSet对象中取得数据:
while (rs.next())
System.out.println(rs.getString(2));
在这里TEMP表中第二列的类型STRING,因此咱们使用了rs对象的getString()方法。固然这里也能够经过调用rs.getString(paramName)来得到值。这个方法也是遵循JDBC标准的。若是一直向下作遍历,当没有记录的时候,next()就会返回false。
当再也不须要使用Statement和Resultset数据以后,就必须显式的关闭已经建立的Statement对象。JDBC驱动程序没有自动地释放这些对象的功能,应用程序必须显式的调用Statement的close()方法和ResultSet的close()方法。一旦已经显式的关闭了已经建立的对象,就不能再使用这些对象了。若是已经再也不使用某些Statement对象和Resultset对象,可是却不去释放它,那将会形成严重的内存泄漏。若是建立了大量的Statement和ResultSet对象,可是却不释放它们,应用程序可能最终会形成OUT OF MEMORY的后果。
好比应用程序中的Statement对象是stmt,ResultSet对象是rs,就能够这样关闭它:
rs.close();
stmt.close();
虽然关闭了Statement对象时,建立该Statement对象的Connection仍然与查询引擎保持链接,应用程序仍然能够用它建立其余的Statement对象。
最后,当再也不须要与查询引擎的链接时,就须要关闭Connection对象。调用Connection的close()方法,就会关闭链接,释放网络上的资源。
con.close();
JDBC驱动支持大多数由JDBC3.0规范所要求的类型。在类型映射中,咱们将讨论JAVA类型、JDBC类型以及查询引擎类型是如何进行相互映射的。好比前台的String对应于JDBC类型中的那种,又对应于查询引擎中的那种类型。
表3-1是查询引擎数据类型。
序号 |
类型 |
描述 |
有效范围 |
1 |
smallint |
整型数据 |
[-32768, 32767] |
2 |
int |
整型数据 |
[-2147483648, 2147483647] |
3 |
bigint |
整型数据 |
[-9223372036854775808, 9223372036854775807] |
4 |
double precision |
浮点双精度数 |
[2.2250738585072014e-308,1.7976931348623158e+308] |
5 |
real |
浮点精度数字 |
[-1E+308, 1E+308] |
6 |
text |
可变长度的字符数据 |
最大长度为1G个字符 |
7 |
char(n) |
定长字符串 |
长度为n |
8 |
varchar(n) |
变长字符串 |
最大长度为n |
9 |
bytea |
变长的二进制字串 |
理论上没有限制,能够达到4个G |
10 |
boolean |
布尔类型 |
TRUE/FALSE |
11 |
timestamp |
时间戳 |
‘2013-01-01 00:00:00’ |
查询引擎数据类型这一列列举了在查询引擎中的数据类型。
JDBC 类型这一列列举JDBC标准支持的,并在java.sql.Types类中有定义的类型。
标准JAVA类型这一列列举了在JAVA语言中定义的标准类型。
表3-2 查询引擎数据类型、JDBC类型和标准JAVA类型之间的映射。
序号 |
查询引擎 数据类型 |
JDBC类型 |
标准JAVA类型 |
1 |
smallint |
java.sql.Types.SMALLINT |
short |
2 |
Int |
java.sql.Types.INT |
int |
3 |
Bigint |
java.sql.Types.BIGINT |
long |
4 |
double precision |
java.sql.Types.DOUBLE |
double |
5 |
Real |
java.sql.Types.FLOAT |
double |
6 |
Text |
java.sql.Types.VARCHAR |
java.lang.String |
7 |
char(n) |
java.sql.Types.VARCHAR |
java.lang.String |
8 |
varchar(n) |
java.sql.Types.VARCHAR |
java.lang.String |
9 |
bytea |
java.sql.Types.BINARY |
byte[] |
10 |
boolean |
java.sql.Types.BOOLEAN |
boolean |
11 |
timestamp |
java.sql.Types.TIMESTAMP |
java.sql.Timestamp |
在运行应用程序的时候,可能会抛出不少异常。可能因为查询引擎没有打开致使链接不上,插入的数据类型不符,想要删除的表不存在等等。由JDBC抛出的异常大可能是java.sql.SQLException或者它的子类的对象。这些异常有多是从查询引擎中抛出来的,也有多是从前台的JDBC驱动抛出的。好比上面提到的服务器链接不上就是由JDBC驱动抛出的异常,想要删除的表不存在就是由查询引擎中抛出的错误。
那么如何处理这些由JDBC抛出的异常呢?由JDBC抛出的java.sql.SQLException和它的子类,通常都会包括错误描述,标准的SQL State和厂商特定的错误编码。错误描述、SQL State和错误编号会在附录中给出。
java.sql.SQLException提供了获取这些信息的方法。
经过调用SQLException的getMessage()方法,能够得到由JDBC驱动或者查询引擎报出的错误。经过这个错误描述,就能够知道错误的缘由了。
经过调用SQLException的getErrorCode()方法,能够得到由厂商特定错误编码,在有些状况下可能不返回错误描述,只返回一个空的字符串。
经过调用SQLException的getState()的方法,能够得到标准的SQL State。SQL State是由5个数字组成的字符串。
下面这例子打印出调用getMessage方法所获得的错误信息。
try{
<somecode>
}
catch(SQLException se){
System.out.println(“错误信息:”+se.getMessage());
}
SQLException类也容许打印出堆栈式的出错信息。打印的内容将包括错误描述,和这个错误从抛出一直到被捕捉到所通过的全部被调用的方法。
下面给出了如何打印出堆栈信息的方法。
try{
<somecode>
}
catch(SQLException se){
se.printStackTrace();}
查询引擎 JDBC驱动是基于JDBC3.0规范而实现的。在之前的JDBC2.0规范中,将API分为核心API和扩展API。JDBC3.0规范包含了JDBC2.0规范的核心API以及JDBC2.0的扩展API,并添加了一些新的特性。查询引擎 JDBC驱动实现了JDBC3.0规范中的大部分接口,主要包括下列接口:
l java.sql.Dirver
l java.sql.Connection
l java.sql.Statement
l java.sql.ResultSet
l java.sql.DatabaseMetaData
l java.sql.ResultSetMetaData
查询引擎 JDBC驱动对于上述每一个接口的方法,基本上提供了实现。除了JDBC要求的基本特性以外,好比执行通常的SQL语句,能够对从结果集取得数据等,遵守JDBC3.0的规范,查询引擎 JDBC驱动还提供了一些JDBC的特殊特性:
按照JDBC规范,提供了类型之间的相互转换,好比int和String之间的转化,String和java.sql.Date之间的转化,具体的内容,请参照《JDBC3.0规范》
实现了对ResultSet的各类特性的支持,这些特性是在建立Statement对象、PreparedStatement对象和CallableStatement对象时指定的。
Type包括:
l TYPE_FORWARDONLY
Concurrency包括:
l CONCUR_READ_ONLY
Holdability包括:
l 不支持
在查询引擎 JDBC驱动中对这些特性都给出了较好的实现。具体说明将在结果集一章中给出。
容许用户在Statement和ResultSet中设置fetchSize,经过设置fetchSize,对于记录数很大的状况下,能够极大的下降对内存的使用量。
查询引擎 JDBC驱动提供了Statement对象用于发送SQL语句到查询引擎。
创建了到查询引擎的链接以后,就可使用该链接发送SQL语句。Statement对象经过Connection接口的方法createStatement建立,例如:
Connection conn = DriverManager.getConnection(url,"SYSDBA","SYSDBA");
Statement stmt = conn.createStatement();
在建立Statement对象的时候,能够经过参数来指定产生结果集的属性,详见“结果集处理”一章。为了执行Statement对象,被发送到查询引擎的SQL语句将被做为参数提供给Statement的方法,例如:
String sql = “SELECT * FROM TEMP”;
ResultSet rs = stmt.executeQuery(sql);
Statement接口提供了三种执行SQL语句的方法:executeQuery、executeUpdate和execute。使用哪个方法由SQL语句执行后产生的结果而决定。
方法executeQuery用于产生单个结果集的语句,例如SELECT语句,执行executeQuery方法将返回一个结果集对象。方法executeUpdate用于执行INSERT、UPDATE或DELETE语句以及SQL DDL(数据定义语言)语句,例如CREATE TABLE和DROP TABLE。因为INSERT、UPDATE或DELETE语句的效果是修改表中若干行中的一列或多列,因此executeUpdate的返回值是一个整数,指示受影响的行数(即更新记录数);对于CREATETABLE或DROP TABLE等不操做行的语句,executeUpdate的返回值老是为零(咱们把这个零返回值也视为更新记录数,即没有记录受到影响)。当被执行的SQL语句返回一个更新记录数、一个结果集、多结果集或者SQL语句的类型未知,则使用execute方法。下面的例子演示了以上方法的使用。
使用executeQuery方法处理SQL数据查询语句:
Statement stmt = conn.createStatement();
String sql = “SELECT ID,VALUE FROM TEMP”;
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()){
// 处理得到的数据记录
}
使用executeUpdate方法处理SQL数据操纵语句:
Statement stmt = conn.createStatement();
String sql = “UPDATETEMPSETVALUE = ‘VALUE10’WHEREID = 10”
int rows = stmt.executeUpdate(sql);
if (rows >= 0) {
//<some code>
}
使用executeUpdate方法处理SQL数据定义语句:
Statement stmt = conn.createStatement();
String sql = “CREATE TABLE TEST(ID INT, VALUEVARCHAR(50))”;
int updcount = stmt.executeUpdate(sql);
if (updcount== 0) {
// <some code>
}
使用execute方法处理SQL语句:
String sql;
// 对字符串sql进行赋值,单条SQL语句
...
Statement stmt = conn.createStatement();
boolean b = stmt.execute(sql);
if (b) {
// 说明返回的是ResultSet对象
ResultSet rs;
rs = stmt.getResultSet();
while (rs.next()) {
//<some code>
}
}
else {
// 说明返回的是更新记录数
int rows = stmt.getUpdateCount();
if (rows >= 0) {
//<somecode>
}
}
须要说明的是,执行上面说起的任一种方法都将关闭所调用的Statement对象的当前打开结果集(若是存在)。这意味着在从新执行Statement对象以前,须要完成对当前ResultSet对象的处理。
当SQL语句执行后会返回ResultSet对象或更新记录数,一般使用execute方法。当同时执行多个SQL语句、执行某个存储过程或动态执行未知SQL字符串(即应用程序程序员在编译时未知)时,就有可能出现多个结果的状况,所以在这种状况下就须要使用execute(),由于execute()方法同时适用于对有ResultSet对象返回和有更新记录数返回的状况。
若是不知道返回结果的类型,则能够经过execute方法的返回值来进行判断。若是结果是ResultSet对象,则方法execute返回true;若是结果类型是更新纪录数,则返回false。若是返回int,则意味着结果是更新记录数或执行的语句是DDL命令。在调用方法execute以后能够调用getResultSet()或getUpdateCount()。其中getResultSet()方法得到当前结果集,而getUpdateCount()得到记录的更新数。
当SQL语句的返回结果不是结果集时,则方法getResultSet将返回null。这可能意味着结果是一个更新记录数或没有其它结果。在这种状况下,判断null真正含义的方法是调用方法getUpdateCount(),它将返回一个整数。这个整数为调用语句所影响的行数;若是为-1则表示结果是结果集或没有结果。若是方法getResultSet已返回null(表示结果不是ResultSet对象),则返回值-1表示没有其它结果。也就是说,当下列条件((stmt.getResultSet()==null)&&(stmt.getUpdateCount()==-1))为真时表示没有结果(或没有其它结果)。
下面给了一个示例,用于执行未知sql语句的状况下做判断:
boolean retVal = stmt.execute( sql);
if (retVal){
//有结果集返回
ResultSet rs = stmt.getResultSet();
//处理结果集
//<somecode>
}
else {
//说明可能有更新记录
intupdateCount = stmt.getUpdateCount();
if(updateCount != -1) {
//对有更新记录的状况做处理
//<somecode>
}
}
做为一种好的编程风格,对于再也不使用的Statement对象应显式地关闭它们,这可使得Statement对象使用的外部资源当即被释放。同时,应显示关闭由Statement对象所建立的Resultset对象,可是ResultSet对象使用的资源只有到垃圾收集机制启动时,才会真正的释放他们。因此,当一个对象不须要时,不管是ResultSet对象仍是Statement对象,都应该尽早地释放他们。
本章内容包括:
在JDBC3.0规范中结果集的特性,包括可滚动性(scrollability)、可定位(positioning)、敏感性(sensitivity)、可更新性(updatability)和可保持性(holdability)。这些特性能够分为Type,Concurrency和Holdability三大类,下表为查询引擎对各特性的支持状况定义:
ResultSet Types |
支持程度 |
ResultSet Concurrency |
支持程度 |
ResultSet Holdability |
支持程度 |
TYPE_FORWARD_ONLY |
支持 |
CONCUR_READ_ONLY |
支持 |
HOLD_CURSOR_OVER_COMMIT |
不支持 |
TYPE_SCROLL_INSENSITIVE |
不支持 |
CONCUR_UPDATABLE |
不支持 |
CLOSE_CURSOR_AT_COMMIT |
不支持 |
TYPE_SCROLL_SENSITIVE |
不支持 |
|
|
|
|
查询引擎 JDBC驱动提供了容许用户设置结果集大小(即上面结果集的敏感性中提到的窗口的大小)的方法。经过设置结果集的大小,驱动每次从查询引擎取得的记录数将不超过用户设置的大小。好比TEMP表的实际记录数有100万条,用户若是把它一次所有取出来,就会耗用大量的内存;用户能够设置结果集的大小,好比为1万,那么查询引擎 JDBC驱动将每次只从后台查询引擎取1万条。当用户做游标移动操做时,若是JDBC发现那条记录还没从查询引擎取出来,就会从查询引擎取出那条记录。
stmt.setFetchSize(10000);
ResultSet rs = stmt.executeQuery(“SELECT * FROMTEMP”);
while(rs.next()) {
//若是调用到第10001次,驱动程序会再从后台取10000条,把原来的记录
//覆盖掉,这样内存中始终只是用了10000条记录内存的大小
}
在缺省状况下,即用户不设fetchSize时, JDBC驱动会将全部记录一次取出来。所以对于记录数极大的状况下(好比100万条)可能会耗用大量的内存。可是若是用户将fetchSize设得不够大,会增长网络的开销和查询引擎的查询操做,所以在这种状况下应用程序的执行速度将不如缺省的状况。用户对于内存耗用量和执行速度必须有一个折中的考虑,取得最好的平衡点。
MetaData是一种重要的机制,能够供用户来获取相应对象(目标数据源、结果集,参数信息等)的详细描述信息。在JDBC驱动中,有三个接口专门提供相应的MetaData信息:
DatabaseMetaData:用于描述查询引擎的元数据信息;
ResultSetMetaData:用于描述ResultSet对象的元数据信息;
ParameterMetaData:用于描述PreparedStatement、CallableStatement对象参数属性的元数据信息。
下面将分别介绍这三个接口相应方法的使用。
DatabaseMetaData接口的实现是为了给用户提供目标数据源的信息,应用程序根据接口中的各类方法获得相应的信息,进而决定如何与之交互。
获取DatabaseMeta信息的步骤是:首先建立DatabaseMetaData对象:
DatabaseMetaData dbmd = conn.getMetaData();
利用dbmd对象,调用DatabaseMetaData接口的相应方法就能够得到查询引擎和JDBC驱动程序的一些信息,例如:
int majorVersion = dbmd.getJDBCMajorVersion(); // 得到JDBC 驱动程序的主版本号
DatabaseMetaData接口包括了超过150种的方法,根据提供信息的类型,能够把这些方法分为五类:
提供数据源整体信息的方法:好比得到查询引擎的主版本号版本信息的getDatabaseMajorVersion();
说明数据源是否支持某一特定特征的方法:好比根据方法supportsANSI92EntryLevelSQL()的返回值能够知道查询引擎是否支持ANSI92入门级SQL语法;
说明数据源限制的方法:好比经过getMaxConnections()方法能够获得查询引擎支持的最大链接数;
说明数据源支持哪些SQL对象,他们的属性是什么:好比getTables()、getPrimaryKeys()方法;
说明数据源提供的事务支持:好比经过getDefaultTransactionIsolation()方法能够获得查询引擎缺省的事务隔离级别。
建议支持接口以下:
函数 |
功能 |
intgetJDBCMajorVersion() |
获取JDBC主版本号 |
String getDatabaseProductName() |
获取系统名称 |
String getDatabaseProductVersion() |
获取版本号 |
String getDriverName() |
获取驱动名称 |
String getDriverVersion() |
获取驱动版本号 |
String getURL() |
获取引擎URL |
关于各类方法的具体说明请参阅JAVA2 SDK DOCUMENT。
ResultSetMetaData接口提供的方法用于获取一个ResultSet对象各个列的类型和属性,好比列名、列数据类型、列所属的表、以及列是否容许值为 NULL等等。
下面的例子演示了ResultSetMetaData的建立和使用:
假若有一个表StudentInfo(StuIDINT,StuName VARCHAR(10)),下面的例子能够获得这个表的各个列的类型名称:
String sql = “SELECT StuID, StuName FROMStudentInfo”;
ResultSet rs = stmt.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
for(int i = 1; i <= rsmd.getColumnCount(); i++)
{
//依次打印出列的类型名称
StringtypeName = rsmd.getColumnTypeName(i);
System.out.println(typeName);
}
建议支持接口以下:
函数 |
功能 |
intgetColomnCount() |
获取字段个数 |
String getColumnName(int column) |
根据结果集中字段索引获取字段名 |
intgetColumnType(int column) |
获取字段的类型代码 |
String getColumnTypeName(int column) |
获取字段类型的名称 |
关于各类方法的具体说明请参阅JAVA2 SDK DOCUMENT。
批处理更新机制容许多个更新操做提交给数据源一次处理。相比于一次次单独执行更新,这样的处理方式能够大大的提升效率和性能。Statement、PreparedStatement对象都可以经过addBatch、executeBatch等方法使用批处理更新方式。
当一个Statement对象建立的时候,它的批处理队列是空的。经过调用addBatch()方法,能够将做为参数的SQL语句加入队列中。特别须要指出的是,遵守JDBC3.0规范,全部加入队列的SQL语句必须是执行后返回结果为更新记录数的语句(即insert,delete, update语句和DDL语句),不然将抛出SQLException异常。
若是不打算提交批更新队列中的SQL语句,须要调用clearBatch方法来清空批处理队列。执行批处理更新使用executeBatch方法便可。须要注意的一点:在使用批处理更新以前必须先禁用AutoCommit模式。
下面是一个例子:
//改变auto-commit模式
conn.setAutoCommit(false);
Statementstmt = conn.createStatement();
//设置SQL语句
stmt.addBatch("INSERTINTO employee VALUES (1024, 'Joe Jones')");
stmt.addBatch("INSERTINTO department VALUES (6, 'Shoe')");
stmt.addBatch("INSERTINTO emp_dept VALUES (1024, 6)");
//执行批处理更新
int[]updateCounts = stmt.executeBatch();
conn.commit();
最后说明一点,在批处理队列当中不容许设置保存点(savepoint)。若是要设置,必须在第一条SQL语句被添加到批处理队列中以前。
在PreparedStatement对象中使用批处理更新机制,是指先对SQL语句执行查询优化,而后在批处理队列中置入多组输入参数,然后提交数据源一次处理。下面是一个例子:
//改变auto-commit模式
conn.setAutoCommit(false);
Stringsql = “INSERT INTO TEMP(ID,VALUE) VALUES(?,?)”;
//先作查询优化
PreparedStatementpstmt = conn.prepareStatement("sql”);
//设置参数值
pstmt.setInt(1,200);
pstmt.setString(2,"Tom Kaufmann");
pstmt.addBatch();
//设置参数值
pstmt.setInt(1,300);
pstmt.setString(2,"Mike Barnes");
pstmt.addBatch();
//执行,取得更新记录
int[]updateCounts = pstmt.executeBatch();
conn.commit();
在批处理执行过程当中,若是有一条语句执行出错,执行将再也不继续下去,查询引擎JDBC将会抛出BatchUpdateException,该异常是SQLException的子类。在BatchUpdateException中提供了getUpdateCounts()方法,该方法的返回值是一个int数组。同前面executeBatch()方法同样,该返回数组是一个记录的更新数,数组中的每一个值,都是相应SQL语句在查询引擎中更新的记录数。不过getUpdateCounts()返回的数组长度,为正确执行的SQL语句数,而不是批处理中全部的SQL语句数。所以,getUpdateCounts()中包含的记录更新数,将只包含正确执行的SQL语句,而不包含错误执行或没有执行到的SQL语句。
关于更详细的JDBC Driver 的信息,能够参考JAVA2 SDK DOCUMENT和JDBC3.0规范.能够在http://java.sun.com/products/jdbc/index.html得到相关文档。