目录
2.1 The JDBC-ODBC Bridge Driver
2.3The NetWork Protocol Driver
3.3Creating and Executing JDBC Statements
4.2Methods of ResultSet Interface
JDBC是Java Database Connectivity的缩写,它是Java编程语言中用于执行SQL语句的API,可以通过JDBC API连接和操作各种类型的关系型数据库,例如MySQL、Oracle和SQL Server等。JDBC提供了一种标准化的方式,使得Java应用程序能够使用统一的方式访问各种关系型数据库,并与它们进行交互。
1.识别 JDBC 体系结构中的层
1.1JDBC体系结构
-
JDBC API层:该层提供了接口和类,使Java应用程序能够访问和操作数据库。JDBC API层包括接口,如Connection、Statement和ResultSet,它们定义了与数据库交互的方法。
-
JDBC驱动程序层:该层为特定数据库管理系统提供了JDBC API接口的实现。它使Java应用程序能够连接到和使用特定数据库管理系统,比如MySQL、Oracle、PostgreSQL等。
2.识别 JDBC 驱动程序的类型
2.1 The JDBC-ODBC Bridge Driver
JDBC-ODBC Bridge Driver是一种JDBC驱动程序,它允许通过ODBC驱动程序连接到数据库。ODBC(Open Database Connectivity)是一种面向应用程序的标准数据库访问方法,它定义了一套API,以便在多个平台和语言之间提供一致的数据库访问接口。
JDBC-ODBC桥接驱动程序的工作方式是通过JDBC调用ODBC驱动程序来访问数据库。它允许使用JDBC API来访问不支持JDBC的数据库,例如Microsoft Access。在此过程中,JDBC-ODBC桥接驱动程序充当JDBC驱动程序和ODBC驱动程序之间的桥梁,从而允许Java应用程序通过JDBC API来访问ODBC数据源。
但是,JDBC-ODBC Bridge Driver存在一些限制和问题。首先,它需要安装和配置ODBC驱动程序,这可能会涉及到一些操作系统特定的细节。其次,它的性能比其他JDBC驱动程序要低,因为它需要转换JDBC调用为ODBC调用,并且需要额外的数据类型转换。最后,由于Oracle公司在Java SE 8中移除了JDBC-ODBC桥接驱动程序,因此在Java SE 8及更高版本中无法使用它。
因此,虽然JDBC-ODBC Bridge Driver在一些特定情况下是有用的,但是在大多数情况下,使用特定于数据库的JDBC驱动程序是更好的选择。
2.2The Native-API Driver
Native-API Driver是JDBC驱动程序的一种类型。这种驱动程序是由JDBC API和数据库特定的本机库(如OCI、libpq等)组成的组合。该驱动程序需要在每个客户端机器上安装适当的本机库,以便JDBC应用程序可以连接到数据库。
由于该驱动程序使用数据库特定的本机库,因此它通常具有最好的性能,并且允许JDBC应用程序使用数据库特定的功能和扩展。
然而,Native-API Driver的主要缺点是它依赖于本机库,因此它不是跨平台的。此外,由于需要在每个客户端机器上安装本机库,因此安装和配置过程可能会比其他驱动程序类型更加繁琐。
2.3The NetWork Protocol Driver
JDBC的Network Protocol Driver(或称为Type 3驱动程序)使用中间服务器来转换JDBC调用为DBMS特定的协议,而中间服务器必须能够与客户端和服务器都兼容的协议通信。这种驱动程序通常可以实现跨平台访问,并且可以访问不支持直接socket连接的数据库。
JDBC Network Protocol Driver的工作原理是将JDBC API调用发送到应用程序服务器上的中间层,该中间层解释调用并将它们转换为DBMS特定的协议,并将协议发送到DBMS以执行所请求的操作。然后,结果将被发送回到中间层,中间层再将结果转换回JDBC API调用的结果并将其发送回客户端。这种驱动程序需要客户端和应用程序服务器之间的网络连接。
这种驱动程序的优点是它们可以跨平台使用,并且不需要使用DBMS的客户端库。此外,由于JDBC API调用是在中间层上执行的,因此可以更好地控制访问和安全性。但是,与其他驱动程序相比,网络协议驱动程序的性能通常较慢,因为它们涉及更多的层,并且需要更多的网络通信。
2.4The Native Protocol Driver
The Native Protocol Driver是一种基于Java的数据库驱动程序,它直接通过数据库提供的本地协议与数据库进行通信,不依赖于其他外部软件或库。它是一种纯Java驱动程序,不需要在中间层添加额外的软件或硬件,因此可以提供更高的性能和更好的可移植性。
与其他驱动程序不同,The Native Protocol Driver直接调用数据库的本地API进行通信,而不是通过ODBC或JDBC-ODBC桥接程序。这种直接通信的方式可以减少通信层的开销,提高数据访问速度和响应时间。同时,它也可以支持更多的数据库特性和功能。
使用The Native Protocol Driver时,需要使用特定的数据库厂商提供的驱动程序。不同的数据库厂商会提供不同的驱动程序,因此需要根据所使用的数据库来选择相应的驱动程序。在使用该驱动程序时,需要将驱动程序的jar包添加到classpath中,并在程序中使用该驱动程序的类名来注册驱动程序。
总之,The Native Protocol Driver是一种高性能、可移植性好的Java数据库驱动程序,可以直接调用本地API与数据库进行通信,具有较好的可靠性和兼容性。
3.使用 JDBC API
DBC API 中常用的类和接口如下:
-
DriverManager
: 用于管理一组 JDBC 驱动程序的基本服务,包括注册、查找和选择适当的驱动程序。 -
Driver
: JDBC 驱动程序的基类,所有的驱动程序都必须实现这个接口。它包含了与数据库连接相关的一些方法。 -
Connection
: 表示与数据库的连接。可以用它来创建 Statement、PreparedStatement 和 CallableStatement 等对象,以及设置事务、提交和回滚等操作。 -
Statement
: 用于执行 SQL 语句并返回结果。Statement 接口有三个子接口,分别是 PreparedStatement、CallableStatement 和 BatchStatement。 -
PreparedStatement
: 可以预编译 SQL 语句,避免 SQL 注入攻击,并且执行效率高。 -
CallableStatement
: 用于调用存储过程。 -
ResultSet
: 封装了查询结果集,提供了对结果集的访问和操作方法。 -
ResultSetMetaData
: 用于获取 ResultSet 的元数据,例如列名、列类型、列的属性等。 -
DatabaseMetaData
: 用于获取数据库的元数据,例如数据库名称、驱动程序名称、数据库支持的功能等。 -
SQLException
: JDBC 操作过程中可能抛出的异常。
3.1Loading a Driver
在使用 JDBC 驱动程序之前,需要将驱动程序加载到 JVM 中。JVM 通过使用 Class.forName() 方法来加载驱动程序。
下面以MySQL为例:
Class.forName("com.mysql.cj.jdbc.Driver");
3.2Connecting to a Database
在加载驱动程序之后,可以使用 DriverManager 类的 getConnection() 方法来建立与数据库的连接。getConnection() 方法接受三个参数:数据库 URL、用户名和密码。例如:
import java.sql.*;
public class ConnectDatabaseExample {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/yourdatabase";
String username = "yourusername";
String password = "yourpassword";
try {
// Load the MySQL JDBC driver
Class.forName("com.mysql.cj.jdbc.Driver");
// Get a connection to the database
Connection conn = DriverManager.getConnection(url, username, password);
// Do something with the connection here...
// Close the connection
conn.close();
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
在MySQL Connector/J 8.0版本之后,使用了新的包名和类名。旧的包名和类名是com.mysql.jdbc.Driver
,新的包名和类名是com.mysql.cj.jdbc.Driver
。
所以,如果你使用MySQL Connector/J 8.0或以上版本,应该使用新的类名:com.mysql.cj.jdbc.Driver
。如果你使用旧版本的MySQL Connector/J,则应该使用旧的类名:com.mysql.jdbc.Driver
。
3.3Creating and Executing JDBC Statements
1.创建一个 Connection 对象,用于连接数据库。可以使用 DriverManager.getConnection() 方法创建一个连接,也可以使用 DataSource 对象连接。
2.创建一个 Statement 对象或者 PreparedStatement 对象,用于发送SQL语句给数据库。
- 如果需要动态设置SQL语句的参数,可以使用 PreparedStatement 对象。
- 如果SQL语句已经是固定的,可以使用 Statement 对象。
3.执行SQL语句。
- 对于 Statement 对象,可以使用 execute() 方法或者它的变体(如 executeUpdate()、executeQuery() 等)执行SQL语句。
- 对于 PreparedStatement 对象,可以使用它的变体(如 executeUpdate()、executeQuery() 等)执行SQL语句。
4.处理 SQL 语句的结果。
- 如果 SQL 语句是更新语句,则返回更新的记录数。可以使用 executeUpdate() 方法获得。
- 如果 SQL 语句是查询语句,则返回查询结果集。可以使用 executeQuery() 方法获得。
- 如果 SQL 语句没有返回任何结果,则返回 false。可以使用 execute() 方法获得。
5.关闭 Statement 对象和 Connection 对象,释放资源。可以使用 close() 方法。
import java.sql.*;
public class JdbcExample {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/yourdatabase";
String username = "yourusername";
String password = "yourpassword";
try {
// Load the MySQL JDBC driver
Class.forName("com.mysql.cj.jdbc.Driver");
// Get a connection to the database
Connection conn = DriverManager.getConnection(url, username, password);
// Create a statement object
Statement stmt = conn.createStatement();
// Execute a SELECT statement
ResultSet rs = stmt.executeQuery("SELECT * FROM employees");
// Iterate over the result set and print the data
while (rs.next()) {
System.out.println("ID: " + rs.getInt("id") + ", Name: " + rs.getString("name") + ", Age: " + rs.getInt("age"));
}
// Execute an INSERT statement
stmt.executeUpdate("INSERT INTO employees (id, name, age) VALUES (4, 'Jane Doe', 25)");
// Execute an UPDATE statement
stmt.executeUpdate("UPDATE employees SET age = 26 WHERE id = 1");
// Execute a DELETE statement
stmt.executeUpdate("DELETE FROM employees WHERE id = 2");
// Close the statement and connection
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
3.4Handing SQL Exceptions
1.使用try-catch块捕获异常并处理它们。可以使用多个catch块来处理不同类型的异常。例如:
try {
// 执行SQL语句
} catch (SQLException e) {
// 处理SQL异常
} catch (Exception e) {
// 处理其他异常
}
2.可以使用方法抛出异常。这样可以将异常传递给调用代码处理。例如:
public void executeSqlStatement(String sql) throws SQLException {
// 执行SQL语句
}
3.可以使用异常处理程序。可以注册一个或多个异常处理程序来处理未捕获的异常。例如:
Connection conn = null;
try {
// 获取数据库连接
conn = DriverManager.getConnection(url, username, password);
// 执行SQL语句
} catch (SQLException e) {
// 处理SQL异常
} catch (Exception e) {
// 处理其他异常
} finally {
// 关闭数据库连接
try {
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
// 处理SQL异常
}
}
4.访问结果集
4.1Types of Result Sets
1.在Java中,"scroll-sensitive"(可滚动敏感)是一种结果集类型,用于处理数据库查询结果。"Scroll-sensitive"结果集具有以下特点:
可以在结果集中以任意方向进行导航:与只能向前遍历的"scroll-forward-only"结果集相比,"scroll-sensitive"结果集可以在结果集中向前和向后导航,以及跳转到指定位置。
对结果集进行修改:"scroll-sensitive"结果集允许对结果集中的数据进行修改操作。你可以更新、插入或删除结果集中的记录,并将更改反映到底层数据库。
反映数据库变化:"scroll-sensitive"结果集具有敏感性,可以在结果集中感知到对底层数据库的变化。如果其他事务对数据库进行了更改,并且这些更改与结果集中的数据有关,"scroll-sensitive"结果集可以及时反映这些变化。
需要注意的是,"scroll-sensitive"结果集可能对系统资源的使用更高,因为它需要维护结果集与数据库之间的状态和同步。因此,如果你只需要单向、只读的结果集,使用"scroll-forward-only"类型可能更高效。
在Java中,要创建一个"scroll-sensitive"结果集,你可以使用JDBC API中的ResultSet.TYPE_SCROLL_SENSITIVE
常量来指定结果集类型。
例如:
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet resultSet = statement.executeQuery("SELECT * FROM my_table");
上述代码创建了一个"scroll-sensitive"和可更新的结果集(CONCUR_UPDATABLE
)。你可以使用resultSet
对象进行滚动、修改和获取结果集中的数据。
请注意,"scroll-sensitive"结果集的可用性取决于所使用的数据库驱动程序和数据库的支持情况。不是所有的数据库和驱动程序都提供对"scroll-sensitive"结果集的完全支持。
2.TYPE_SCROLL_INSENSITIVE(不敏感的可滚动):与"scroll-sensitive"不同,"scroll-insensitive"结果集对底层数据库的变化不敏感。即使其他事务对数据库进行了更改,结果集中的数据也不会自动更新。它支持向前和向后滚动。
3.TYPE_FORWARD_ONLY(只能向前滚动):这是最基本的结果集类型,只能以向前的方式遍历结果集。它在内存使用和性能方面通常是最高效的,适用于单向、只读的操作。
4.concur_read_only
是一个用于指定结果集并发性的参数,它表示结果集的并发性设置为只读,即只能进行读取操作,而不能进行修改操作。
5.CONCUR_UPDATABLE 是一个用于指定结果集并发性的参数,它表示结果集的并发性设置为可更新,即可以对结果集中的数据进行修改操作。
6.CLOSE_CURSOR_AT_COMMIT
是一个用于指定结果集的关闭行为的参数,它表示当事务提交时,结果集将自动关闭。
7.HOLD_CURSORS_OVER_COMMIT
是一个用于指定结果集的关闭行为的参数,它表示当事务提交时,结果集将保持打开状态而不关闭。
4.2Methods of ResultSet Interface
1.first()
是 ResultSet
接口中的一个方法,用于将光标移动到结果集的第一行,并返回一个布尔值表示操作是否成功。
2.isFirst()
是 ResultSet
接口中的一个方法,用于判断当前光标是否位于结果集的第一行。
具体而言,isFirst()
方法返回一个布尔值,如果光标位于结果集的第一行,则返回 true
,否则返回 false
。
3.beforeFirst()
是 ResultSet
接口中的一个方法,用于将光标定位到结果集的第一行之前。
4.isBeforeFirst()
是 ResultSet
接口中的一个方法,用于判断当前光标是否位于结果集的第一行之前。
5.last()
:将光标移动到结果集的最后一行,并返回一个布尔值表示操作是否成功。
6.isLast()
是 ResultSet
接口中的一个方法,用于判断当前光标是否位于结果集的最后一行。
7.afterLast()
是 ResultSet
接口中的一个方法,用于将光标定位到结果集的最后一行之后。
8.isAfterLast()
是 ResultSet
接口中的一个方法,用于判断当前光标是否位于结果集的最后一行之后。
9.previous()
: 将光标移动到结果集的上一行。通常与可滚动的结果集一起使用
10.next()
: 将光标移动到结果集的下一行。如果存在下一行,则返回 true
,否则返回 false
11.absolute(int row)
是 ResultSet
接口中的一个方法,用于将光标移动到指定的行号。
具体而言,absolute(int row)
方法接受一个整数参数 row
,表示要移动到的行号。如果 row
的值为正数,则光标将被定位到结果集的第 row
行;如果 row
的值为负数,则光标将被定位到结果集的倒数第 row
行;如果 row
的值为 0,则光标将被定位到结果集的开头(第一行之前)。
该方法返回一个布尔值,表示操作是否成功。如果移动到指定行号成功,则返回 true
,否则返回 false
。
12.relative(int rows)
是 ResultSet
接口中的一个方法,用于将光标相对于当前位置移动指定的行数。
具体而言,relative(int rows)
方法接受一个整数参数 rows
,表示要移动的行数。如果 rows
的值为正数,则光标向结果集的末尾方向移动 rows
行;如果 rows
的值为负数,则光标向结果集的开头方向移动 -rows
行;如果 rows
的值为 0,则光标保持不动。
该方法返回一个布尔值,表示操作是否成功。如果移动指定的行数成功,则返回 true
,否则返回 false
。
13.getXXX()
是 ResultSet
接口中的一组方法,用于获取结果集中当前行的不同类型的列值。
这里的 XXX
表示不同的数据类型,例如 getInt()
、getString()
、getDouble()
等。根据具体的数据类型,你可以使用相应的 getXXX()
方法来获取对应列的值。
以下是一些常用的 getXXX()
方法示例:
-
getInt(int columnIndex)
或getInt(String columnLabel)
:获取指定列的整数值。 -
getString(int columnIndex)
或getString(String columnLabel)
:获取指定列的字符串值。 -
getDouble(int columnIndex)
或getDouble(String columnLabel)
:获取指定列的双精度浮点数值。 -
getDate(int columnIndex)
或getDate(String columnLabel)
:获取指定列的日期值。 -
getBoolean(int columnIndex)
或getBoolean(String columnLabel)
:获取指定列的布尔值。
可被修改结果集的方法
1. updateRow()
是 ResultSet
接口中的一个方法,用于将当前行所做的更改更新到底层数据库。
具体而言,当你对结果集中的某一行进行了修改后,可以调用 updateRow()
方法来将修改后的数据更新到数据库中。该方法会将当前行的修改提交给数据库,并更新相应的数据库记录。
2.insertRow()
是 ResultSet
接口中的一个方法,用于向结果集插入一条新的行。
具体而言,insertRow()
方法用于将当前光标所在位置插入的数据作为一条新的行插入到结果集中。插入的数据必须通过使用 updateXXX()
方法修改了结果集中的列值之后才能调用该方法。
3.deleteRow()
是 ResultSet
接口中的一个方法,用于从结果集中删除当前行。
具体而言,deleteRow()
方法会删除结果集中当前光标所在的行,并从底层数据库中删除相应的记录。需要注意的是,此方法只能在可更新的结果集(如 ResultSet.CONCUR_UPDATABLE
)上使用。
4.updateXXX(int columnIndex, XXX value)
或 updateXXX(String columnLabel, XXX value)
:更新当前行指定列的值。其中,XXX
表示数据类型,可以是 int
、String
、double
等。