JDBC Connection Statement ResultSet DatabaseMetaData

来源:互联网 发布:巧克力知乎 编辑:程序博客网 时间:2024/05/16 23:57

 JDBC API中的重要接口
接    口                                    作    用
java.sql.DriverManager    处理驱动程序的加载和建立新数据库连接
java.sql.Connection         处理与特定数据库的连接
java.sql.Statement          算是一个连接的实例在指定连接中处理SQL语句
java.sql.ResultSet           处理数据库操作结果集

DatabaseMetaData 有关整个数据库的信息:表名、表的索引、数据库产品的名称和版本、数据库支持的操作。 


ResultSet 关于某个表的信息或一个查询的结果。您必须逐行访问数据行,但是您可以任何顺序访问列。 

ResultSetMetaData 有关 ResultSet 中列的名称和类型的信息。 

尽管每个对象都有大量的方法让您获得数据库元素的极为详细的信息,但在每个对象中都有几种主要的方法使您可获得数据的最重要信息。然而,如果您希望看到比此处更多的信息,建议您学习文档以获得其余方法的说明。 

Connection 
     Connection是用来表示数据库连接的对象,对数据库的一切操作都是在这个连接的基础上进行的。Connection类的主要成员方法

方    法                                                         含    义
void clearWarnings                             清除连接的所有警告信息
Statement createStatement()           创建一个statement对象
Statement createStatement(int resultSetType, int resultSetConcurrency)
创建一个statement对象,它将生成具有特定类型和并发性的结果集
void commit()                                       提交对数据库的改动并释放当前连接持有的数据库的锁
void rollback()                                     回滚当前事务中的所有改动并释放当前连接持有的数据库的锁
String getCatalog()                              获取连接对象的当前目录名
boolean isClosed()                              判断连接是否已关闭
boolean isReadOnly()                         判断连接是否为只读模式
void setReadOnly()                            设置连接的只读模式
void close()                                           立即释放连接对象的数据库和JDBC资源

 Statement 
     Statement用于在已经建立的连接的基础上向数据库发送SQL语句的对象。它只是一个接口的定义,其中包括了执行SQL语句和获取返回结果的方法。实际上有3种 Statement 对象:Statement、PreparedStatement(继承自Statement )和 CallableStatement(继承自PreparedStatement)。它们都作为在给定连接上执行 SQL 语句的容器,每个都专用于发送特定类型的 SQL 语句: Statement 对象用于执行不带参数的简单 SQL 语句;PreparedStatement 对象用于执行带或不带 IN 参数的预编译 SQL 语句;CallableStatement 对象用于执行对数据库已存储过程的调用。Statement 接口提供了执行语句和获取结果的基本方法;PreparedStatement 接口添加了处理 IN 参数的方法;而 CallableStatement 添加了处理 OUT 参数的方法。 
    创建statement对象的方法如下:
     Statement stmt = con.createStatement(); 
     Statement接口定义中包括的方法如

Statement接口的主要成员方法及其含义
方    法                                                         含    义
void addBatch(String sql)        在Statement语句中增加用于数据库操作的SQL批处理语句
void cancel()                          取消Statement中的SQL语句指定的数据库操作命令
void clearBatch()                  清除Statement中的SQL批处理语句
void clearWarnings()            清除Statement语句中的操作引起的警告
void close()                           关闭Statement语句指定的数据库连接
boolean execute(String sql)    执行SQL语句
int[] executeBatch()                  执行多个SQL语句
ResultSet executeQuery(String sql)    进行数据库查询,返回结果集
int executeUpdate(String sql) 进行数据库更新
Connection getConnection()     获取对数据库的连接
int getFetchDirection()             获取从数据库表中获取行数据的方向
int getFetchSize()                 获取返回的数据库结果集行数
int getMaxFieldSize()      获取返回的数据库结果集最大字段数
int getMaxRows()                获取返回的数据库结果集最大行数
boolean getMoreResults()             获取Statement的下一个结果
int getQueryTimeout()                   获取查询超时设置
ResultSet getResultSet()                      获取结果集
int getUpdateCount()                     获取更新记录的数量
void setCursorName(String name)       设置数据库Cursor的名称
void setFetchDirection(int dir)             设置数据库表中获取行数据的方向
void setFetchSize(int rows)                 设置返回的数据库结果集行数
void setMaxFieldSize(int max)               设置最大字段数
void setMaxRows(int max)                    设置最大行数
void setQueryTimeout(int seconds)       设置查询超时时间

值得注意的是,Statement 接口提供了3种执行SQL语句的方法:executeQuery、executeUpdate和execute。使用哪一个方法由SQL语句所产生的内容决定。executeQuery方法用于产生单个结果集的SQL语句,如SELECT语句。executeUpdate方法用于执行INSERT、UPDATE、DELETE及DDL(数据定义语言)语句,例如CREATE TABLE 和 DROP TABLE。executeUpdate 的返回值是一个整数,表示它执行的SQL语句所影响的数据库中的表的行数(更新计数)。execute 方法用于执行返回多个结果集或多个更新计数的语句。 

     PreparedStatement接口继承了Statement接口,但PreparedStatement语句中包含了经过预编译的SQL语句,因此可以获得更高的执行效率。在PreparedStatement语句中可以包含多个用"?"代表的字段,在程序中可以利用setXXX方法设置该字段的内容,从而增强了程序设计的动态性。PreparedStatement接口的主要成员方法及其含义

 PreparedStatement接口的主要成员方法及其含义
方    法                                                      含    义
void addBatch(String sql)             在Statement语句中增加用于数据库操作的SQL批处理语句
void clearparameters ()                                   清除PreparedStatement中的设置参数
ResultSet executeQuery(String sql)                       执行SQL查询语句
ResultSetMetaData getMetaData()                      进行数据库查询,获取数据库元数据
void setArray(int index,Array x)                            设置为数组类型
void setAsciiStream(int index,InputStream stream,int length)         设置为ASCII输入流
void setBigDecimal(int index,BigDecimal x)                             设置为十进制长类型
void setBinaryStream
(int index,InputStream stream,int length)                      设置为二进制输入流
void setCharacterStream
(int index,InputStream stream,int length)                    设置为字符输入流
void setBoolean(int index, boolean x)                        设置为逻辑类型
void setByte(int index,byte b)                                    设置为字节类型
void setBytes(int byte[] b)                                          设置为字节数组类型
void setDate(int index,Date x)                                   设置为日期类型
void setFloat(int index,float x)                                    设置为浮点类型
void setInt(int index,int x)                                           设置为整数类型
void setLong(int index,long x)                                    设置为长整数类型
void setRef(int index,int ref)                                       设置为引用类型
void setShort(int index,short x)                                  设置为短整数类型
void setString(int index,String x)                               设置为字符串类型
void setTime(int index,Time x)                                  设置为时间类型

PreparedStatement与Statement的区别在于它构造的SQL语句不是完整的语句,而需要在程序中进行动态设置。这一方面增强了程序设计的灵活性;另一方面,由于PreparedStatement语句是经过预编译的,因此它构造的SQL语句的执行效率比较高。所以对于某些使用频繁的SQL语句,用PreparedStatement语句比用Statement具有明显的优势。 

     PreparedStatement对象的创建方法如下:
     PreparedStatement pstmt = con.prepareStatement("update tbl_User set reward = ? where userId = ?"); 

    在该语句中,包括两个可以进行动态设置的字段:reward和userId。 
    例如,我们想给第一个注册的用户5000点奖励,则可以用下面的方法设置空字段的内容: 
    pstmt.setInt(1, 5000);
    pstmt. setInt (2, 1);

    如果我们想给前50个注册的用户每人5000点奖励,则可以用循环语句对空字段进行设置: 

pstmt.setInt(1, 5000);for (int i = 0; i < 50; i++){   pstmt.setInt(2,i);   int rowCount = pstmt.executeUpdate();}
    如果传递的数据量很大,则可以通过将 IN 参数设置为 Java 输入流来完成。当语句执行时,JDBC驱动程序将重复调用该输入流,读取其内容并将它们当做实际参数数据传输。JDBC 提供了3种将IN参数设置为输入流的方法:setBinaryStream用于含有未说明字节的流;setAsciiStream用于含有ASCII字符的流;setUnicodeStream用于含有Unicode字符的流。这些方法比其他的setXXX方法要多一个用于指定流的总长度的参数,因为一些数据库在发送数据之前需要知道它传送的数据的大小。 
    下面是一个使用流作为 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 table set stuff = ? where index = 4");

pstmt.setBinaryStream (1, fin, fileLength);

pstmt.executeUpdate();

    当语句执行时,将反复调用输入流 fin 以传递其数据。 

 CallableStatement对象用于执行对数据库已存储过程的调用。在CallableStatement对象中,有一个通用的成员方法call,这个方法用于以名称的方式调用数据库中的存储过程。在数据库调用过程中,可以通过设置IN参数向调用的存储过程提供执行所需的参数。另外,在存储过程的调用中,通过OUT参数获取存储过程的执行结果。 

     CallableStatement 接口的主要成员方法及其含义如所示。 

方    法                                        含    义

Array getArray(int I)                    获取数组

BigDecimal getBigDecimal(int index) 

BigDecimal getBigDecimal(int index,int scale)        获取十进制小数

boolean getBoolean(int index)  获取逻辑类型

byte getByte(int index)            获取字节类型

Date getDate(int index)

Date getDate(int index,Calendar cal)       获取日期类型

double getDouble(int index)    获取日期类型双精度类型

float getFloat(int index)        获取日期类型浮点类型

int getint(int index)             获取日期类型整数类型

long getLong(int index)       获取日期类型长整数类型

Object getObject(int index) 

Object getObject(int index,Map map) 获取对象类型

Ref getRef(int I)                   获取日期类型Ref类型

short getShort(int index)     获取日期类型短整数类型

String getString(int index)    获取日期类型字符串类型

Time getTime(int index) Time 

getTime(int index,Calendar cal)      获取时间类型

void registerOutputParameter(int index)

void registerOutputParameter(int index,int type)

void registerOutputParameter

(int index,int type,int scale)   注册输出参数


     调用存储过程的语法为:

{call procedure_name}              // 过程不需要参数

{call procedure_name[(?,?,?,...)]}    // 过程需要若干个参数

{? = call procedure_name[(?,?,?,...)]} //过程需要若干个参数并返回一个参数

    其中procedure_name为存储过程的名字,方括号中的内容是可选的多个用于存储过程执行的参数。CallableStatement 对象的创建方法如下:

     CallableStatement cstmt = con.prepareCall("{call getData(?, ?)}"); 


    向存储过程传递执行需要参数的方法是通过setXXX语句完成的。例如,我们可以将两个参数设置如下: 

cstmt.setByte(1, 25);cstmt.setInt(2,64.85);

    如果需要存储过程返回运行结果,则需要调用registerOutParameter方法设置存储过程的输出参数,然后调用getXXX方法来获取存储过程的执行结果。例如: 

cstmt.registerOutParameter(1, java.sql.Types.TINYINT);cstmt.registerOutParameter(1, java.sql.Types. INTEGER);cstmt.executeUpdate();byte a = cstmt.getByte(1);int b = cstmt.getInt(2);

    从上面的程序可以看出,Java的基本数据类型和SQL中支持的数据类型有一定的对应关系。这种对应关系如表13-7所示。 

SQL的数据类型与Java数据类型的对应关系

SQL数据类型    Java数据类型

CHAR         String 

VARCHAR        String 

LONGVARCHAR String 

NUMERIC        java.math.BigDecimal 

DECIMAL        java.math.BigDecimal 

BIT          boolean 

TINYINT        byte 

SMALLINT       short 

INTEGER        int 

BIGINT      long 

REAL        float 

FLOAT     double 

DOUBLE     double 

BINARY         byte[] 

VARBINARY      byte[] 

LONGVARBINARY     byte[] 

DATE       java.sql.Date 

TIME        java.sql.Time 

TIMESTAMP      java.sql.Timestamp

    ResultSet 

    结果集(ResultSet)用来暂时存放数据库查询操作获得的结果。它包含了符合 SQL 语句中条件的所有行,并且它提供了一套 get 方法对这些行中的数据进行访问。ResultSet类的主要成员方法及其含义如表13-8所示。 

ResultSet类的主要成员方法及其含义

方    法                                           含    义

boolean absolute(int row)           将指针移动到结果集对象的某一行

void afterLast()                        将指针移动到结果集对象的末尾

void beforeFirst()                         将指针移动到结果集对象的头部

boolean first()                              将指针移动到结果集对象的第一行

Array getArray(int row)              获取结果集中的某一行并将其存入一个数组

boolean getBoolean(int columnIndex)     获取当前行中某一列的值,返回一个布尔型值

byte getByte(int columnIndex)                获取当前行中某一列的值,返回一个字节型值

short getShort(int columnIndex)           获取当前行中某一列的值,返回一个短整型值

int getInt(int columnIndex)                   获取当前行中某一列的值,返回一个整型值

long getLong(int columnIndex) 获取当前行中某一列的值,返回一个长整型值

double getDouble(int columnIndex)     获取当前行中某一列的值,返回一个双精度型值

float getFloat(int columnIndex)               获取当前行中某一列的值,返回一个浮点型值

String getString(int columnIndex)             获取当前行中某一列的值,返回一个字符串

Date getDate(int columnIndex)               获取当前行中某一列的值,返回一个日期型值

Object getObject(int columnIndex)       获取当前行中某一列的值,返回一个对象

Statement getStatement()                    获得产生该结果集的Statement对象

URL getURL(int columnIndex)    获取当前行中某一列的值,返回一个java.net.URL型值

boolean isBeforeFirst()                   判断指针是否在结果集的头部

boolean isAfterLast()                  判断指针是否在结果集的末尾

boolean isFirst()                    判断指针是否在结果集的第一行

boolean isLast()                  判断指针是否在结果集的最后一行

boolean last()                       将指针移动到结果集的最后一行

boolean next()                          将指针移动到当前行的下一行

boolean previous()                  将指针移动到当前行的前一行

    从中可以看出,ResultSet类不仅提供了一套用于访问数据的get方法,还提供了很多移动指针(cursor,有时也译为光标)的方法。cursor是ResultSet 维护的指向当前数据行的指针。最初它位于第一行之前,因此第一次访问结果集时通常调用 next方法将指针置于第一行上,使它成为当前行。随后每次调用 next 指针向下移动一行。

ResultSet 

ResultSet 对象是 JDBC 中最重要的单个对象。从本质上讲,它是对一个一般宽度和未知长度的表的一种抽象。几乎所有的方法和查询都将数据作为 ResultSet 返回。ResultSet 包含任意数量的命名列,您可以按名称访问这些列。它还包含一个或多个行,您可以按顺序自上而下逐一访问。在您使用 ResultSet 之前,必须查询它包含多少个列。此信息存储在 ResultSetMetaData 对象中。 

 

//从元数据中获得列数 

ResultSetMetaData rsmd; rsmd = results.getMetaData(); numCols = rsmd.getColumnCount(); 

当您获得一个 ResultSet 时,它正好指向第一行之前的位置。您可以使用 next() 方法得到其他每一行,当没有更多行时,该方法会返回 false。由于从数据库中获取数据可能会导致错误,您必须始终将结果集处理语句包括在一个 try 块中。 

 

您可以多种形式获取 ResultSet 中的数据,这取决于每个列中存储的数据类型。另外,您可以按列序号或列名获取列的内容。请注意,列序号从 1 开始,而不是从 0 开始。ResultSet 对象的一些最常用方法如下所示。 

getInt(int); 将序号为 int 的列的内容作为整数返回。 

getInt(String); 将名称为 String 的列的内容作为整数返回。 

getFloat(int); 将序号为 int 的列的内容作为一个 float 型数返回。 

getFloat(String); 将名称为 String 的列的内容作为 float 型数返回。 

getDate(int); 将序号为 int 的列的内容作为日期返回。 

getDate(String); 将名称为 String 的列的内容作为日期返回。 

next(); 将行指针移到下一行。如果没有剩余行,则返回 false。 

Close(); 关闭结果集。 

getMetaData(); 返回 ResultSetMetaData 对象。 

ResultSetMetaData 

您使用 getMetaData() 方法从 ResultSet 中获取 ResultSetMetaData 对象。您可以使用此对象获得列的数目和类型以及每一列的名称。 

getColumnCount(); 返回 ResultSet 中的列数。 

getColumnName(int); 返回列序号为 int 的列名。 

getColumnLabel(int); 返回此列暗含的标签。 

isCurrency(int); 如果此列包含带有货币单位的一个数字,则返回 true。 

isReadOnly(int); 如果此列为只读,则返回 true。 

isAutoIncrement(int); 如果此列自动递增,则返回 true。这类列通常为键,而且始终是只读的。 

getColumnType(int); 返回此列的 SQL 数据类型。这些数据类型包括 

BIGINT 

BINARY 

BIT 

CHAR 

DATE 

DECIMAL 

DOUBLE 

FLOAT 

INTEGER 

LONGVARBINARY 

LONGVARCHAR 

NULL 

NUMERIC 

OTHER 

REAL 

SMALLINT 

TIME 

TIMESTAMP 

TINYINT 

VARBINARY 

VARCHAR 

DatabaseMetaData 

DatabaseMetaData 对象可为您提供整个数据库的信息。您主要用它获取数据库中表的名称,以及表中列的名称。由于不同的数据库支持不同的 SQL 变体,因此,也有多种方法查询数据库支持哪些 SQL 方法。 

getCatalogs() 返回该数据库中的信息目录列表。使用 JDBC-ODBC Bridge 驱动程序,您可以获得用 ODBC 注册的数据库列表。这很少用于 JDBC-ODBC 数据库。 

getTables(catalog, schema,tableNames, columnNames) 返回表名与 tableNames 相符而且列名与 columnNames 相符的所有表的说明。 

getColumns(catalog, schema,tableNames, columnNames) 返回表名与 tableNames 相符而且列名与 columnNames 相符的所有表列说明。 

getURL(); 获得您所连接的 URL 名称。 

getDriverName(); 获得您所连接的数据库驱动程序的名称。 

获取有关表的信息 

您可以使用 DataBaseMetaData 的 getTables() 方法来获取数据库中表的信息。这个方法有如下4个 String 参数: 

results =dma.getTables(catalog, schema, tablemask, types[]); 

其中参数的意义是: 

Catalog 要在其中查找表名的目录名。对于 JDBC-ODBC 数据库以及许多其他数据库而言,可将其设置为 null。这些数据库的目录项实际上是它在文件系统中的绝对路径名称。 

Schema 要包括的数据库“方案”。许多数据库不支持方案,而对另一些数据库而言,它代表数据库所有者的用户名。一般将它设置为 null。 

Tablemask 一个掩码,用来描述您要检索的表的名称。如果您希望检索所有表名,则将其设为通配符 %。请注意,SQL 中的通配符是 % 符号,而不是一般 PC 用户的 * 符号。 

types[] 这是描述您要检索的表的类型的 String 数组。数据库中通常包括许多用于内部处理的表,而对作为用户的您没什么价值。如果它是空值,则您会得到所有这些表。如果您将其设为包含字符串“TABLES”的单元素数组,您将仅获得对用户有用的表格。 

一个简单的 JDBC 程序 

我们已经学习了 JDBC 的所有基本功能,现在我们可以编写一个简单的程序,该程序打开数据库,打印它的表名以及某一表列的内容,然后对该数据库执行查询。此程序如下所示: 

import java.sql.*; public class JdbcOdbc_test { ResultSet results; ResultSetMetaData rsmd; DatabaseMetaData dma; Connection con;  public JdbcOdbc_test() throws SQLException { String url = "jdbc:odbc:Northwind"; try { //加载 JDBC-ODBC 桥驱动程序 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); con = DriverManager.getConnection(url);//连接数据库 dma = con.getMetaData();//获取数据库的元数据 System.out.println("Connected to:" + dma.getURL()); System.out.println("Driver " + dma.getDriverName()); } catch (Exception e) { System.out.println(e); } try { Statement stmt = con.createStatement(); results = stmt.executeQuery("select * from 客户;"); ResultSetMetaData resultMetaData = results.getMetaData(); int cols = resultMetaData.getColumnCount(); String resultRow = ""; for (int i = 1; i < cols; i++) { resultRow += resultMetaData.getColumnName(i) + ";"; } System.out.println(resultRow); while (results.next()) { resultRow = ""; for (int i = 1; i < cols; i++) { try { resultRow += results.getString(i) + ";"; } catch (NullPointerException e) { System.out.println(e.getMessage()); } } System.out.println(resultRow); } } catch (Exception e) { System.out.println("query exception"); } finally { results.close(); } } } 

补充高级内容 

关于调用SQLServer存储过程的例子:(用到了我们开发的数据库连接类) 

CREATE PROCEDURE [dbo].[sp_getStudentByName](@name char(10)) AS Select * from Students where [Name]=@name GO 

DbObject DbO = new DbObject(new SqlServerConnectionFactory("localhost", 1433, "demo", "sa", "")); Connection con = DbO.getConnection(); CallableStatement pstmt = null; System.out.println("TestDB1()............"); /* try { pstmt = con.prepareCall("{call sp_getStudentById(?)}"); pstmt.setInt(1, 1); }*/ try { pstmt = con.prepareCall("{call sp_getStudentByName(?)}"); //注意参数如何传递 pstmt.setString(1, "Tom"); } …… 

使用输出参数: 

CREATE PROCEDURE [dbo].[sp_insertStudent](@name char(10),@age int,@id int OUTPUT) AS 

insert into Students([Name],[Age]) values (@name,@age) 

select @id=@@IDENTITY 

GO 

try { pstmt = con.prepareCall("{call sp_insertStudent(?,?,?)}"); pstmt.setString(1, "zengqingsong"); pstmt.setInt(2, 22);  pstmt.registerOutParameter(3, Types.INTEGER); pstmt.executeUpdate();  int id = pstmt.getInt(3); System.out.println(id); }

 

使用返回参数的例子: 

CREATE PROCEDURE [dbo].[sp_insertStudent](@name char(10),@age int,@id int OUTPUT) AS 

insert into Students([Name],[Age]) values (@name,@age) 

select @id=@@IDENTITY –测试输出参数 

return 30 –测试返回30 

GO 

try { pstmt = con.prepareCall("{?=call sp_insertStudent(?,?,?)}"); pstmt.setString(2, "zengqingsong"); pstmt.setInt(3, 22); pstmt.registerOutParameter(4, Types.INTEGER); pstmt.registerOutParameter(1, Types.INTEGER); int ret = pstmt.executeUpdate(); //执行影响的行数 int ret2 = pstmt.getInt(1); //返回参数(输出参数) int id = pstmt.getInt(4); //输出参数 System.out.println(ret); System.out.println(ret2); System.out.println(id);



                                             
0 0