JDBC 驱动程序
什么是JDBC驱动程序?
JDBC驱动程序实现JDBC API中定义的接口,用于与数据库服务器进行交互。
例如,使用JDBC驱动程序可以打开数据库连接,并通过发送SQL或数据库命令,然后在收到结果与Java进行交互。
java.sql包中附带的JDK包含定义各种类与他们的行为和实际实现在第三方驱动程序。第三方供应商实现了他们的数据库驱动程序的java.sql.Driver接口。
JDBC驱动程序类型:
JDBC驱动程序实现,因为各种各样的操作系统和Java运行在硬件平台的不同而不同。 Sun已经划分了实现类型分为四大类,类型1,2,3,4,其解释如下:
类型1:JDBC-ODBC桥驱动程序:
在类型1驱动程序,一个JDBC桥接器是用来访问安装在每个客户机上的ODBC驱动程序。使用ODBC,需要配置系统数据源名称(DSN),表示在目标数据库上。
当Java刚出来时,这是一个有用的驱动程序,因为大多数的数据库只支持ODBC访问,但现在建议使用此类型的驱动程序仅用于实验用途或在没有其他选择的情况。
自带JDK 1.2中的JDBC-ODBC桥是这类驱动程序的一个很好的例子。
类型2:JDBC-Native API调用:
在类型2驱动程序,JDBC API调用转换成原生的C / C+ + API调用都有它独特的数据库。这些通常由数据库厂商提供,并以相同的方式将JDBC-ODBC桥驱动程序使用,特定供应商的驱动程序必须安装在每台客户机上。
如果改变了数据库,那么必须改变本机API,因为它是具体到一个数据库,他们大多是过时了,但现在可以实现一些速度增加了类型2驱动程序,因为它消除了数据库的开销。
Oracle调用接口(OCI)驱动程序是一个类型2驱动程序的一个示例。
类型3:JDBC网络纯Java:
在类型3驱动程序,一个三层的方法来访问数据库。在JDBC客户端使用标准的网络套接字与中间件应用服务器进行通信。套接字的相关信息,然后由中间件应用服务器进入由DBMS所需要的的调用格式转换,并转发到数据库服务器。
这种驱动器是非常灵活的,因为它不需要安装在客户端上的代码和一个单一的驱动器实际上可以提供访问多个数据库。
可以将应用服务器作为一个JDBC“代理”,这意味着它会调用客户端应用程序。因此,需要应用服务器的配置,以有效地使用此驱动程序类型的一些知识。
应用服务器可能使用类型1,2,或4驱动程序与数据库进行通信,了解细微之处将证明是有益的。
类型4:100%纯Java:
在一个类型4驱动程序,直接与供应商的数据库进行通信,通过socket连接一个纯粹的基于Java的驱动程序。这是可用于数据库的最高性能的驱动程序,并且通常由供应商本身提供。
这种驱动器是非常灵活的,不需要在客户端或服务器上安装特殊的软件。此外,这些驱动程序可以动态下载。
MySQL的Connector/J的驱动程序是一个类型4驱动程序。因为他们的网络协议的专有性的,数据库厂商通常提供类型4的驱动程序。
其中驱动器应使用?
如果正在访问一个类型的数据库,如Oracle,Sybase或IBM,首选驱动程序是类型4。
如果Java应用程序同时访问多个数据库类型,类型3是首选的驱动程序。
第2类驱动程序是在情况下:类型3或类型4驱动程序还没有提供数据库非常有用。
类型1驱动程序不被认为是部署级别的驱动程序,它通常仅用于开发和测试目的。
JDBC 连接数据库
在安装相应的驱动程序后,现在是时候建立使用JDBC的数据库连接。
涉及到建立一个JDBC连接的编程是相当简单的。下面是这些简单的四个步骤:
-
导入JDBC包: 添加import语句到Java程序导入所需的类在Java代码中。
-
注册JDBC驱动程序:这一步会导致JVM加载所需的驱动程序实现到内存中,因此它可以实现JDBC请求。
-
数据库URL制定:这是创建格式正确的地址指向到要连接的数据库。
-
创建连接对象:最后,代码调用DriverManager对象的getConnection()方法来建立实际的数据库连接。
导入JDBC包:
import 语句告诉Java编译器在哪里可以找到在代码中引用,并放置在您的源代码最开始的类。
使用标准的JDBC包,它允许选择,插入,更新和SQL表中删除数据,添加以下进口到您的源代码:
import java.sql.* ; // for standard JDBC programs import java.math.* ; // for BigDecimal and BigInteger support
注册JDBC驱动程序:
使用它之前,必须注册你的驱动程序在程序。注册驱动程序是由Oracle驱动程序的类文件被加载到内存中以便它可以被用作JDBC接口的实现过程。
需要做这个注册只能在你的程序一次。可以通过以下两种方式之一注册一个驱动程序。
方法(I)- Class.forName():
注册一个驱动程序中最常用的方法是使用Java的Class.forName()方法来动态加载驱动程序的类文件到内存中,它会自动将其注册。这种方法是可取的,因为它允许使驱动注册配置,便于携带。
下面的示例使用Class.forName()来注册Oracle驱动程序:
try { Class.forName("oracle.jdbc.driver.OracleDriver"); } catch(ClassNotFoundException ex) { System.out.println("Error: unable to load driver class!"); System.exit(1); }
可以使用getInstance()方法来解决不兼容的JVM,但要编写了两个额外的例外情况如下:
try { Class.forName("oracle.jdbc.driver.OracleDriver").newInstance(); } catch(ClassNotFoundException ex) { System.out.println("Error: unable to load driver class!"); System.exit(1); catch(IllegalAccessException ex) { System.out.println("Error: access problem while loading!"); System.exit(2); catch(InstantiationException ex) { System.out.println("Error: unable to instantiate driver!"); System.exit(3); }
方法(二) - DriverManager.registerDriver():
可以用它来注册一个驱动程序的第二种方法是使用staticDriverManager.registerDriver()方法。
应该,如果使用的是不兼容的JDK JVM,比如微软提供一个使用registerDriver()方法。
下面的示例使用registerDriver()来注册Oracle驱动程序:
try { Driver myDriver = new oracle.jdbc.driver.OracleDriver(); DriverManager.registerDriver( myDriver ); } catch(ClassNotFoundException ex) { System.out.println("Error: unable to load driver class!"); System.exit(1); }
数据库URL制定:
当加载的驱动程序,可以建立程序中使用DriverManager.getConnection()方法的连接。为方便参考,让列出了三个重载DriverManager.getConnection()方法:
-
getConnection(String url)
-
getConnection(String url, Properties prop)
-
getConnection(String url, String user, String password)
在这里,每个表单需要一个数据库URL。数据库的URL是指向数据库地址。
制定一个数据库URL是大多数用在建立连接相关。
下表列出了下来流行的JDBC驱动程序名和数据库的URL。
RDBMS | JDBC驱动程序的名称 | URL 格式 |
---|---|---|
MySQL | com.mysql.jdbc.Driver | jdbc:mysql://hostname/ databaseName |
ORACLE | oracle.jdbc.driver.OracleDriver | jdbc:oracle:thin:@hostname:port Number:databaseName |
DB2 | COM.ibm.db2.jdbc.net.DB2Driver | jdbc:db2:hostname:port Number/databaseName |
Sybase | com.sybase.jdbc.SybDriver | jdbc:sybase:Tds:hostname: port Number/databaseName |
以URL格式所有高亮的部分是静态的,需要改变只剩余部分按照数据库设置。
创建连接对象:
使用数据库URL的用户名和密码:
下面三种形式DriverManager.getConnection()方法来创建一个连接对象。getConnection()最常用形式要求传递一个数据库URL,用户名 username和密码 password:
对URL数据库部分databaseName的值:假设使用的是Oracle的瘦驱动程序,需要指定一个主机:端口。
假设有一台主机TCP/IP地址192.0.0.1 以及主机名和Oracle监听器被配置为在端口1521,数据库名称是EMP,然后完整的数据库URL是:
jdbc:oracle:thin:@amrood:1521:EMP
现在,必须调用适当的用户名和密码以及getConnection()方法来获得一个Connection对象,如下所示:
String URL = "jdbc:oracle:thin:@amrood:1521:EMP"; String USER = "username"; String PASS = "password" Connection conn = DriverManager.getConnection(URL, USER, PASS);
只使用一个数据库URL:
第二种形式 DriverManager.getConnection()方法只需要一个数据库URL:
DriverManager.getConnection(String url);
然而,在这种情况下,数据库的URL,包括用户名和密码,并具有以下的一般形式:
jdbc:oracle:driver:username/password@database
所以上面的连接可以创建如下:
String URL = "jdbc:oracle:thin:username/password@amrood:1521:EMP"; Connection conn = DriverManager.getConnection(URL);
使用数据库的URL和一个Properties对象:
第三种形式DriverManager.getConnection()方法需要一个数据库URL和一个Properties对象:
DriverManager.getConnection(String url, Properties info);
Properties对象,保存一组关键字 - 值对。它被用来调用getConnection()方法时驱动程序属性传递给驱动程序。
为了使通过前面的例子中所做的相同的连接,使用下面的代码:
import java.util.*; String URL = "jdbc:oracle:thin:@amrood:1521:EMP"; Properties info = new Properties( ); info.put( "user", "username" ); info.put( "password", "password" ); Connection conn = DriverManager.getConnection(URL, info);
关闭JDBC连接:
在JDBC程序的结束,它明确要求关闭所有的连接到数据库,以结束每个数据库会话。但是,如果忘了,Java垃圾收集器会关闭连接时,它会清除陈旧的对象。
依托垃圾收集,特别是在数据库编程,是非常差的编程习惯。应该总是在关闭与连接对象关联的close()方法连接的习惯。
为了确保连接被关闭,可以在代码中的finally块执行。 finally块都会执行,不管是否发生或也不例外。
要关闭上面打开的连接,应该调用close()方法,如下所示:
conn.close();
显式地关闭连接DBMS节约资源。
为了更好地理解,建议看看JDBC - 示例代码。
一旦获得一个连接,我们可以与数据库进行交互。在JDBC Statement, CallableStatement 和 PreparedStatement 接口定义的方法和属性,使可以发送SQL或PL/SQL命令和从数据库接收数据。
它们还定义方法,帮助Java和数据库使用SQL数据类型之间转换数据的差异。
下表提供了每个接口的用途概要,了解决定使用哪个接口?
接口 | 推荐使用 |
---|---|
Statement | 使用通用访问数据库。当在运行时使用静态SQL语句。 Statement接口不能接受的参数。 |
PreparedStatement | 当计划多次使用SQL语句。 那么可以PreparedStatement接口接收在运行时输入参数。 |
CallableStatement | 当要访问数据库中的存储过程中使用。 CallableStatement对象的接口还可以接受运行时输入参数。 |
Statement 对象:
创建Statement对象:
在可以使用Statement对象执行SQL语句,需要使用Connection对象的createStatement( )方法创建一个,如下面的示例所示:
Statement stmt = null; try { stmt = conn.createStatement( ); . . . } catch (SQLException e) { . . . } finally { . . . }
一旦创建了一个Statement对象,然后可以用它来与它的三个执行方法之一执行SQL语句。
-
boolean execute(String SQL) : 如果ResultSet对象可以被检索返回布尔值true,否则返回false。使用这个方法来执行SQL DDL语句,或当需要使用真正的动态SQL。
-
int executeUpdate(String SQL) : 返回受影响的SQL语句执行的行的数目。使用此方法来执行,而希望得到一些受影响的行的SQL语句 - 例如,INSERT,UPDATE或DELETE语句。
-
ResultSet executeQuery(String SQL) : 返回ResultSet对象。当希望得到一个结果集使用此方法,就像使用一个SELECT语句。
关闭 Statement 对象:
正如关闭一个Connection对象来保存数据库资源,出于同样的原因,也应该关闭Statement对象。
close()方法简单的调用将完成这项工作。如果关闭了Connection对象首先它会关闭Statement对象也是如此。然而,应该始终明确关闭Statement对象,以确保正确的清除。
Statement stmt = null; try { stmt = conn.createStatement( ); . . . } catch (SQLException e) { . . . } finally { stmt.close(); }
为了更好地理解,建议研究和学习 Statement 实例代码.
PreparedStatement 对象:
PreparedStatement接口扩展了Statement接口,让过一个通用的Statement对象增加几个高级功能。
statement 提供动态参数的灵活性。
创建PreparedStatement 对象:
PreparedStatement pstmt = null; try { String SQL = "Update Employees SET age = ? WHERE id = ?"; pstmt = conn.prepareStatement(SQL); . . . } catch (SQLException e) { . . . } finally { . . . }
在JDBC中所有的参数都被代表?符号,这是已知的参数标记。在执行SQL语句之前,必须提供值的每一个参数。
setXXX()方法将值绑定到参数,其中XXX表示希望绑定到输入参数值的Java数据类型。如果忘了提供值,将收到一个SQLException。
每个参数标记是由它的序号位置引用。第一标记表示位置1,下一个位置为2 等等。这种方法不同于Java数组索引,以0开始。
所有的Statement对象的方法来与数据库交互(a) execute(), (b) executeQuery(), 及(c) executeUpdate() 也与PreparedStatement对象的工作。然而,该方法被修改为使用SQL语句,可以利用输入的参数。
关闭PreparedStatement对象:
正如关闭Statement对象,出于同样的原因,也应该关闭的PreparedStatement对象。
close()方法简单的调用将完成这项工作。如果关闭了Connection对象首先它会关闭PreparedStatement对象。然而,应该始终明确关闭PreparedStatement对象,以确保正确的清除。
PreparedStatement pstmt = null; try { String SQL = "Update Employees SET age = ? WHERE id = ?"; pstmt = conn.prepareStatement(SQL); . . . } catch (SQLException e) { . . . } finally { pstmt.close(); }
为了更好地理解,建议学习Prepare 例子代码.
CallableStatement 对象:
正如一个Connection对象创建Statement和PreparedStatement对象,它也创造了CallableStatement对象这将被用来执行调用数据库存储过程。
创建CallableStatement 对象:
假设,需要执行以下Oracle存储过程:
CREATE OR REPLACE PROCEDURE getEmpName (EMP_ID IN NUMBER, EMP_FIRST OUT VARCHAR) AS BEGIN SELECT first INTO EMP_FIRST FROM Employees WHERE ID = EMP_ID; END;
注:上面的存储过程已写入用于Oracle,但我们正在使用MySQL数据库,以便让我们写相同的存储过程对于MySQL如下,以EMP数据库中创建它:
DELIMITER $$ DROP PROCEDURE IF EXISTS `EMP`.`getEmpName` $$ CREATE PROCEDURE `EMP`.`getEmpName` (IN EMP_ID INT, OUT EMP_FIRST VARCHAR(255)) BEGIN SELECT first INTO EMP_FIRST FROM Employees WHERE ID = EMP_ID; END $$ DELIMITER ;
三种类型的参数有:IN,OUT和INOUT。 PreparedStatement对象只使用IN参数。 CallableStatement对象可以使用所有三个。
这里是每个的定义:
参数 | 描述 |
---|---|
IN | 它的值是在创建SQL语句时未知的参数。将值绑定到与setXXX()方法的参数。 |
OUT | 其值由它返回的SQL语句提供的参数。从OUT参数的getXXX()方法检索值。 |
INOUT | 同时提供输入和输出值的参数。绑定的setXXX()方法的变量,并使用getXXX()方法检索值。 |
下面的代码片段显示了如何使用该Connection.prepareCall()方法实例化基于上述存储过程CallableStatement对象:
CallableStatement cstmt = null; try { String SQL = "{call getEmpName (?, ?)}"; cstmt = conn.prepareCall (SQL); . . . } catch (SQLException e) { . . . } finally { . . . }
String变量的SQL表示存储过程,使用参数占位符。
使用CallableStatement对象是就像使用PreparedStatement对象。必须将值绑定到所有的参数执行该语句之前,否则将收到一个SQLException。
如果有IN参数,只要按照适用于PreparedStatement对象相同的规则和技巧;使用对应于要绑定的Java数据类型的setXXX()方法。
当使用OUT和INOUT参数就必须采用额外的CallableStatement及registerOutParameter()方法。registerOutParameter()方法JDBC数据类型绑定到数据类型的存储过程应返回。
一旦调用存储过程,用适当的getXXX()方法的输出参数检索值。这种方法投射SQL类型的值检索到Java数据类型。
关闭CallableStatement 对象:
正如关闭其他Statement对象,出于同样的原因,也应该关闭CallableStatement对象。
close()方法简单的调用将完成这项工作。如果关闭了Connection对象首先它会关闭CallableStatement对象为好。然而,应该始终明确关闭CallableStatement对象,以确保正确的清除。
CallableStatement cstmt = null; try { String SQL = "{call getEmpName (?, ?)}"; cstmt = conn.prepareCall (SQL); . . . } catch (SQLException e) { . . . } finally { cstmt.close(); }
为了更好地理解,建议学习 Callable实例代码。