第十一讲 JDBC JDBC基础 JDBC驱动程序 JDBC编程 示例
JDBC ——基础 JDBC(Java Database Connectivity)是一个独立于特定数据库管理系统的、通用的SQL数据库存取和操作的公共接口(一组API),定义了用来访问数据库的标准Java类库,使用这个类库可以以一种标准的方法、方便地访问数据库资源(在java.sql类包中)。 JDBC为访问不同的数据库提供了一种统一的途径,象ODBC(Open Database Connectivity)一样,JDBC对开发者屏蔽了一些细节问题。 JDBC的目标是使应用程序开发人员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,这样就使得程序员无需对特定的数据库系统的特点有过多的了解,从而大大简化和加快了开发过程。
JDBC ——基础 开放数据库互连(ODBC)是为了实现异构数据库互连而由Microsoft公司推出的一种标准,它是一个单一的、公共的编程接口。ODBC提供不同的程序以存取不同的数据库,但只提供一种应用编程接口(API)给应用程序。 应用程序 驱动程序管理器 驱动程序 数据源 ODBC的体系结构含有四个部件: 应用程序(Application):执行ODBC函数的调用和处理,提交SQL语句并检索结果。 驱动程序管理器(Driver Manager):为应用程序装载驱动程序。 驱动程序(Driver):驱动程序是实现ODBC函数调用和同数据源交互作用的动态连接库,它执行ODBC函数调用,提交SQL请求到指定的数据源,并把结果返回给应用程序。如果需要,驱动程序也可改变应用程序的请求,以和特定的DBMS的语法匹配。 数据源(Data Source):由用户需要存取的数据和与之相连的操作系统、DBMS及存取DBMS的网络平台组成。 ODBC
JDBC ——基础 与ODBC相类似,JDBC接口(API)也包括两个层次: 面向应用的API:Java API,抽象接口,供应用程序开发人员使用(连接数据库,执行SQL语句,获得结果)。 面向数据库的API:Java Driver API,供开发商开发数据库驱动程序用。 与ODBC相比,JDBC没有了定制的“数据源”的概念,而是直接在应用程序中加载驱动程序并连接特定的数据库。
JDBC ——基础:主要概念 Driver Manager(java.sql.DriverManager) 装载驱动程序,管理应用程序与驱动程序之间的连接。 Driver(由驱动程序开发商提供) 将应用程序的API请求转换为特定的数据库请求。 Connection(java.sql.Connection) 将应用程序连接到特定的数据库 Statement(java.sql.Statement) 在一个给定的连接中,用于执行一个静态的数据库SQL语句。 ResultSet(java.sql.ResultSet) SQL语句中心完后,返回的数据结果集(包括行、列)。 Metadata(java.sql.DatabaseMetadata; java.sql. ResultSetMetadata) 关于查询结果集、数据库和驱动程序的元数据信息。
JDBC ——基础:基本工作步骤 Import the necessary classes Load the JDBC driver Identify the database source Allocate a “Connection” object (create) Allocate a “Statement” object (create) Execute a query using the “Statement” object Retrieve data from the returned “ResultSet” object Close the “ResultSet” object Close the “Statement” object Close the “Connection” object
JDBC ——基础:基本工作步骤 Driver Manager Connection Statement ResultSet Database Creates SQL Result (tuples) Establish Link to DB
JDBC ——基础:基本工作步骤 Driver Manager Driver Connection Statement Result Set Database 1. Load the JDBC driver class: Class.forName(“driverName”); 2. Open a database connection: DriverManager.getConnection (“jdbc:xxx:datasource”); 3. Issue SQL statements: stmt = con.createStatement(); stmt.executeQuery (“Select * from myTable”); 4. Process result set: while (rs.next()) { name = rs.getString(“name”); amount = rs.getInt(“amt”); }
JDBC ——驱动程序 JDBC支持四种类型的驱动程序: JDBC-ODBC Bridge, plus ODBC driver (Type 1) Simplest JDBC methods -> Translate JDBC methods to ODBC methods -> ODBC to native methods -> Native methods API Native-API, partly Java driver (Type 2) JDBC methods -> Map JDBC methods to native methods (calls to vendor library) -> Native methods API (vendor library) JDBC-net, pure Java driver (Type 3) JDBC methods -> Translate to Native API methods through TCP/IP network -> Native API methods Native-protocol, pure Java driver (Type 4) Java methods -> Native methods in Java
JDBC ——驱动程序 JDBC-ODBC Bridge, plus ODBC driver (Type 1) Application Space Java Application JDBC – ODBC Bridge Database SQL Command Result Set ODBC Driver Proprietary Protocol JDBC-ODBC Bridge, plus ODBC driver (Type 1) 由 Sun的Java2 JDK提供(sun.jdbc.odbc.JdbcOdbcDriver) 通过ODBC驱动程序来获得对数据库的JDBC访问 必须先安装ODBC驱动程序和配置ODBC数据源。 仅当特定的数据库系统没有相应的JDBC驱动程序时使用。
JDBC ——驱动程序 Native-API, partly Java driver (Type 2) Application Space Java Application Type 2 JDBC Driver Database SQL Command Result Set Native Database Library Proprietary Protocol Native-API, partly Java driver (Type 2) Native-API driver 将JDBC命令转换为特定数据库系统的本地库方法。 与Type1相类似,必须先安装特定数据库的库方法(二进制代码,非Java)。
JDBC ——驱动程序 JDBC-net, pure Java driver (Type 3) Database Application Space Java Application Type 3 JDBC Driver Database SQL Command Result Set Middleware Space Proprietary Protocol JDBC Driver JDBC-net, pure Java driver (Type 3) 将JDBC命令转换为与数据库系统无关的网络协议,并发送给一个中间件服务器。 中间件服务器再将数据库系统无关的网络协议转换为特定数据库系统的协议,并发送给数据库系统。 从数据库系统获得的结果先发送给中间件服务器,并进而返回给应用程序。
JDBC ——驱动程序 Application Space Native-protocol, pure Java driver (Type 4) 纯Java的驱动程序,直接与特定的数据库系统通信。 直接将JDBC命令转换为数据库系统的本地协议。 优点:没有中间的转换或者是中间件。 通常用于提高数据库访问的性能。 Application Space Java Application Type 4 JDBC Driver SQL Command Using Proprietary Protocol Result Set Using Proprietary Protocol Database
JDBC ——驱动程序
JDBC ——编程 任何一个JDBC应用程序,都需要以下四个步骤: 加载JDBC驱动程序 建立与数据库的连接 进行数据库操作 关闭相关连接
JDBC ——编程:加载JDBC驱动程序 在应用程序中,有三种方法可以加载驱动程序: 利用System类的静态方法setProperty() System.setProperty(“jdbc.drivers”, “sun.jdbc.odbc.JdbcOdbcDriver”); 利用Class类的静态方法forName() Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”); Class.forName(“oracle.jdbc.driver.OracleDriver”); 直接创建一个驱动程序对象 new sun.jdbc.odbc.JdbcOdbcDriver();
jdbc:driverType:dataSource ——编程:建立与数据库的连接 利用DriverManager类的静态方法getConnection()来获得与特定数据库的连接实例(Connection实例)。 Connection conn = DriverManager.getConnection(source); Connection conn = DriverManager.getConnection(source, user, pass); 这三个参数都是String类型的,使用不同的驱动程序与不同的数据库建立连接时,source的内容是不同的,但其格式是一致的,都包括三个部分: jdbc:driverType:dataSource 对于JDBC-ODBC Bridge,driverType为odbc, dataSource则为ODBC数据源:“jdbc:odbc:myDSN”。 对于其他类型的驱动程序,根据数据库系统的不同driverType和dataSource有不同的格式和内容。
Connection是用来表示数据库连接的对象,对数据库的一切操作都是在这个连接的基础上进行的。 JDBC ——编程:建立与数据库的连接 Connection Connection是用来表示数据库连接的对象,对数据库的一切操作都是在这个连接的基础上进行的。 Connection类的主要成员方法有: Statement createStatement()——创建一个执行SQL 语句的Statement对象。
JDBC ——编程:建立与数据库的连接 void setAutoCommit(boolean autoCommit)——设置操 作是否自动提交到数据库,默认情况下为true。 void commit()——提交对数据库的更改,使更改生效。 只有将setAutoCommit方法设置为false后才有效。 void rollback()——回滚当前事务中的所有改动,只 有将setAutoCommit方法设置为false时才可以使用。 String getCatalog()——获取连接对象的当前目录名。 boolean isClosed()——判断连接是否已关闭。 boolean isReadOnly()——判断连接是否为只读模式。 void setReadOnly()——设置连接的只读模式。 void close()——关闭数据库连接,立即释放连接对象 的数据库和JDBC资源。
JDBC ——编程:建立与数据库的连接 Statement Statement用于在已经建立的连接的基础上向数据库发送SQL语句的对象。它只是一个接口的定义,其中包括了执行SQL语句和获取返回结果的方法。 JDBC API中有3种Statement对象,它们都作为在给定连接上执行 SQL语句的容器,每种对象都专用于发送特定类型的 SQL 语句 : Statement对象用于执行不带参数的简单SQL语句; PreparedStatement对象用于执行带或不带IN 参数的预编译SQL语句; CallableStatement对象用于执行对数据库已存储过程的调用,包括了IN和OUT类型的参数。
JDBC ——编程:建立与数据库的连接 Statement提供了3种执行SQL语句的方法:execute、 executeQuery 和 executeUpdate。使用哪一个方法由SQL语句所产生的内容决定。 ResultSet executeQuery(String sql)——用于执行查询 操作,并返回一个ResultSet对象格式的查询结果。 int executeUpdate(String sql)——用于执行更新操作并 返回更新的行数。它可以执行CREATE TABLE、DROP TABLE和ALTER TABLE等SQL DDL语句,还可以执行 INSERT、DELETE和UPDATE等SQL DML语句。 boolean execute(String sql)——用于执行SQL语句,并 返回是否有结果集。主要用于不知道将要执行的SQL是 查询还是更新的情况下。
JDBC ——编程:建立与数据库的连接 Statement还提供了其他很多方法,常用的方法如下: void addBatch(String sql)——在Statement语句中增加 用于数据库操作的SQL批处理语句。 void clearBatch()——清除Statement中SQL批处理语句。 void cancel()——取消Statement中的SQL语句指定的 数据库操作命令。 void close()——关闭Statement语句指定的数据库连接。 int[] executeBatch()——执行多个SQL语句。 Connection getConnection()——获取对数据库的连接。 int getFetchDirection()——获取从数据库表中获取行 数据的方向。 int getFetchSize()——获取返回的数据库结果集行数。 int getQueryTimeout()——获取查询超时设置。
JDBC ——编程:建立与数据库的连接 int getMaxFieldSize()——获取返回的数据库结果集最 大字段数。 int getMaxRows()——获取返回的结果集最大行数。 ResultSet getResultSet()——获取结果集。 int getUpdateCount()——获取更新记录的数量。 void setFetchDirection(int dir)——设置数据库表中获取 行数据的方向。 void setFetchSize(int rows)——设置返回的数据库结果 集行数。 void setMaxFieldSize(int max)——设置最大字段数。 void setMaxRows(int max)——设置最大行数。 void setQueryTimeout(int seconds)——设置查询的超时 时间。
JDBC ——编程:建立与数据库的连接 PreparedStatement与Statement的区别在于它构造的 SQL语句不是完整的语句,要在程序中进行动态设置。 这一方面增强了程序设计的灵活性;另一方面,由于PreparedStatement语句是经过预编译的,因此它构造的SQL语句的执行效率比较高。所以对于某些使用频繁的SQL语句,用PreparedStatement语句比用Statement具有明显的优势。 PreparedStatement对象的创建方法如下: PreparedStatement pstmt = con.prepareStatement (“update tbl_User set reward = ? where userId = ?”); 在该语句中,包括两个可以进行动态设置的字段: reward和userId。
JDBC ——编程:建立与数据库的连接 PreparedStatement使用举例 例如,我们想给第一个注册的用户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(); }
JDBC ——编程:建立与数据库的连接 CallableStatement 对象用于执行对数据库中存储过程 存储过程。在存储过程的调用中,可以通过设置IN参数 向调用的存储过程提供执行所需的参数,还可以通过 OUT参数获取存储过程的执行结果。 调用存储过程的语法为: {call procedure_name} // 过程不需要参数 {call procedure_name[(?,?,?,...)]} //过程需要若干个参数 {? = call procedure_name[(?,?,?,...)]} //过程需要若干个 参数并返回一个参数 CallableStatement对象的创建方法如下: CallableStatement cstmt = con.prepareCall (“{call getData (?, ?)}”);
JDBC ——编程:建立与数据库的连接 CallableStatement使用举例 向存储过程传递执行需要参数的方法是通过setXXX 方法完成的。例如,我们可以将两个参数设置如下: cstmt.setByte(1, 25); cstmt.setInt(2,64.85); 如果需要存储过程返回运行结果,则需要调用 registerOutParameter方法设置存储过程的输出参数,然 后调用getXXX方法来获取存储过程的执行结果。 cstmt.registerOutParameter(1, java.sql.Types.TINYINT); cstmt.registerOutParameter(2, java.sql.Types.INTEGER); cstmt.executeUpdate(); byte a = cstmt.getByte(1); int b = cstmt.getInt(2);
JDBC ——编程:建立与数据库的连接 ResultSet 结果集(ResultSet)用来暂时存放数据库查询操作获得的结果。它包含了符合 SQL 语句中条件的所有行,并且它提供了一套get方法对这些行中的数据进行访问。 ResultSet类的主要成员方法及其含义见下页。 ResultSet类不仅提供了一套用于访问数据的get方法,还提供了很多移动指针(cursor,有时也译为光标)的方法。cursor是ResultSet维护的指向当前数据行的指针。 最初它位于第一行之前,因此第一次访问结果集时通常调用next()方法将指针置于第一行上,使它成为当前行。 随着每次调用next()方法使指针向下移动,这样就可以按照从上至下的次序获取ResultSet对象中的所有行。
JDBC ——编程:建立与数据库的连接 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)——获取当前行中某一 列的值,返回一个短整型值
JDBC ——编程:建立与数据库的连接 int getInt(int columnIndex)——获取当前行中某一列的 值,返回一个整型值 long getLong(int columnIndex)——获取当前行中某一 列的值,返回一个长整型值 double getDouble(int columnIndex) ——获取当前行中 某一列的值,返回一个双精度型值 float getFloat(int columnIndex) ——获取当前行中某一 列的值,返回一个浮点型值 String getString(int columnIndex)——获取当前行中某 一列的值,返回一个字符串 Date getDate(int columnIndex) ——获取当前行中某一 列的值,返回一个日期型值
JDBC ——编程:进行数据库操作 参数: int colIndex 或 String colName
JDBC ——编程:建立与数据库的连接 Object getObject(int columnIndex)——获取当前行中某 一列的值,返回一个对象 Statement getStatement()——获得产生该结果集的 Statement对象 boolean isBeforeFirst()——判断指针是否在结果集头部 boolean isAfterLast()——判断指针是否在结果集末尾 boolean isFirst()——判断指针是否在结果集的第一行 boolean isLast()——判断指针是否在结果集的最后一行 boolean last()——将指针移动到结果集的最后一行 boolean next()——将指针移动到当前行的下一行 boolean previous()——将指针移动到当前行的前一行
JDBC ——编程:进行数据库操作 通过ResultSetMetadata来获得查询结果的元数据信息: ResultSet提供了一个方法getMetadata()来获得结果集的元数据信息,它返回的是一个ResultSetMetaData实例。 通过ResultSetMetadata实例,就可以获得结果集中字段的详细信息,如字段总数,每个字段的名称、类型等。 getColumnCount() // # of columns in the row getColumnName( i ) // returns column name getColumnType ( i ) // returns column data type getColumnLabel ( i ) //suggested label for a column when print getTableName() //returns the name of the table 确定了字段类型,获取字段数据时,就可以明确如何使用ResultSet中的getXXX()方法了。
JDBC ——编程:进行数据库操作 通过DatabaseMetadata来获得数据库的元数据信息: Connection提供了一个方法getMetadata()来获得数据库的元数据信息,它返回的是一个DatabaseMetadata实例。 通过DatabaseMetadata实例,就可以获得数据库的各种信息,如数据库厂商信息、版本信息、数据表数目、每个数据表名称等。 getDatabaseProductName() getDatabaseProductVersion() getDriverName() getTables()
JDBC ——编程