JDBC 与 Java 数据对象全解析
1. 数据检索与显示
1.1 数据检索
在与数据库管理系统(DBMS)交互时,我们常常需要从数据库中检索特定的数据。可以通过指定列名或列号来获取想要的值,这里以列名为例。
getString()
方法可用于返回指定列的值,并将其赋值给程序中预先声明的字符串变量。
以下是一个示例代码,展示了如何使用
getString()
方法从结果集中获取
FirstName
和
LastName
列的值,并将它们拼接后显示在屏幕上:
String firstName;
String lastName;
String printRow;
boolean records = results.next();
if (!records ) {
System.out.println( "No data returned");
return;
}
else
{
do {
firstName = results.getString ("FirstName");
lastName = results.getString ("LastName");
printRow = firstName + " " + lastName;
System.out.println(printRow);
} while ( results.next() );
}
1.2 关闭数据库连接
在完成数据检索和处理后,需要关闭
ResultSet
实例和与 DBMS 的连接。可以通过调用
close()
方法来实现:
result.close();
dB.close();
虽然在关闭与 DBMS 的连接时,
ResultSet
实例会自动关闭,但许多程序员还是倾向于显式地关闭它。
2. 异常处理
2.1 加载驱动时的异常处理
在加载驱动时,
Class.forName()
方法可能会抛出
ClassNotFoundException
异常。可以使用
catch
块来捕获该异常,并显示异常描述信息,然后终止程序:
try {
Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver");
}
catch (ClassNotFoundException e) {
System.err.println(
"Unable to load the JDBC/ODBC bridge." + e.getMessage());
System.exit(1);
}
2.2 连接数据库时的异常处理
在尝试连接到 DBMS 时,可能会出现各种问题,如数据库 URL 不准确、用户 ID 或密码错误等。
getConnection()
方法会抛出
SQLException
异常。可以使用
catch
块来捕获该异常,并显示异常信息,然后终止程序:
String url = "jdbc:odbc:Registration";
String userID = "jim";
String password = "keogh";
Connection dB;
try {
Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver");
dB = DriverManager.getConnection(url,userID,password);
}
catch (ClassNotFoundException e) {
System.err.println(
"Unable to load the JDBC/ODBC bridge." + e);
System.exit(1);
}
catch (SQLException e) {
System.err.println(
"Cannot connect to the database." + e);
System.exit(2);
}
finally {
dB.close();
}
3. 避免连接超时
在实际应用中,当程序尝试连接到 DBMS 时,DBMS 可能不可用,这通常是由于此时对 DBMS 的需求过高导致的。为了避免程序无限期等待,可以设置一个超时时间,当超过该时间后,
DriverManager
将停止尝试连接。
3.1 设置超时时间
可以通过调用
DriverManager.setLoginTimeout()
方法来设置超时时间,该方法需要传入等待的秒数:
DriverManager.setLoginTimeout(10); // 设置超时时间为 10 秒
3.2 获取当前超时时间
可以通过调用
DriverManager.getLoginTimeout()
方法来获取当前的超时时间,该方法返回一个整数,表示
DriverManager
等待的秒数:
int timeout = DriverManager.getLoginTimeout();
System.out.println("当前超时时间: " + timeout + " 秒");
4. 不同类型的 Statement 对象
4.1 三种 Statement 对象
有三种类型的
Statement
对象可用于执行查询:
Statement
、
PreparedStatement
和
CallableStatement
。它们的特点如下表所示:
| Statement 对象类型 | 特点 |
| — | — |
|
Statement
| 立即执行查询,查询在 DBMS 执行前会被编译 |
|
PreparedStatement
| 用于执行预编译的查询,适用于多次执行相似查询的场景 |
|
CallableStatement
| 用于执行存储过程 |
4.2
Statement
对象的使用
当需要立即执行查询时,可以使用
Statement
对象。通过调用
executeQuery()
方法来执行查询,如果查询是插入、更新或删除行,则使用
executeUpdate()
方法。
4.2.1
executeQuery()
示例
String url = "jdbc:odbc:Registration";
String userID = "jim";
String password = "keogh";
Statement dataRequest;
ResultSet results;
Connection dB;
try {
Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver");
dB = DriverManager.getConnection(url,userID,password);
}
catch (ClassNotFoundException e) {
System.err.println(
"Unable to load the JDBC/ODBC bridge." + e);
System.exit(1);
}
catch (SQLException e) {
System.err.println(
"Cannot connect to the database." + e);
System.exit(2);
}
try {
String query = "SELECT * FROM Registration";
dataRequest = dB.createStatement();
results = dataRequest.executeQuery (query);
//Place code here to interact with the ResultSet
}
catch ( SQLException e ){
System.err.println("SQL error." + e);
System.exit(3);
}
finally {
dataRequest.close();
dB.close();
}
4.2.2
executeUpdate()
示例
String url = "jdbc:odbc:Registration";
String userID = "jim";
String password = "keogh";
Statement dataRequest;
Connection dB;
int rowsUpdated;
try {
Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver");
dB = DriverManager.getConnection(url,userID,password);
}
catch (ClassNotFoundException e) {
System.err.println(
"Unable to load the JDBC/ODBC bridge." + e);
System.exit(1);
}
catch (SQLException e) {
System.err.println("Cannot connect to the database." + e);
System.exit(2);
}
try {
String query = "UPDATE Registration SET Enrolled='Y' WHERE StudentID = '123'";
dataRequest = dB.createStatement();
rowsUpdated = dataRequest.executeUpdate (query);
dataRequest.close();
}
catch ( SQLException e ){
System.err.println("SQL error." + e);
System.exit(3);
}
finally {
dataRequest.close();
dB.close();
}
4.3
PreparedStatement
对象的使用
PreparedStatement
对象适用于多次执行相似查询的场景。在编写 SQL 查询时,可以使用问号作为占位符,用于表示每次执行查询时可能会变化的数据。
4.3.1 执行
PreparedStatement
对象的步骤
-
声明
PreparedStatement对象并赋值:
PreparedStatement pstatement = dB.prepareStatement(query);
- 替换问号占位符的值:
pstatement.setString(1, "123");
- 执行查询:
ResultSet results = pstatement.executeQuery();
4.3.2 示例代码
String url = "jdbc:odbc:Registration";
String userID = "jim";
String password = "keogh";
ResultSet results;
Connection dB;
try {
Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver");
dB = DriverManager.getConnection(url,userID,password);
}
catch (ClassNotFoundException e) {
System.err.println(
"Unable to load the JDBC/ODBC bridge." + e);
System.exit(1);
}
catch (SQLException e) {
System.err.println(
"Cannot connect to the database." + e);
System.exit(2);
}
try {
String query = "SELECT * FROM Registration WHERE studentID = ?";
PreparedStatement pstatement = dB.prepareStatement(query);
pstatement.setString(1, "123");
results = pstatement.executeQuery();
//Place code here to interact with the ResultSet
}
catch ( SQLException e ){
System.err.println("SQL error." + e);
System.exit(3);
}
finally {
pstatement.close();
dB.close();
}
4.4
CallableStatement
对象的使用
CallableStatement
对象用于执行存储过程。存储过程是由程序员编写并存储在 DBMS 中的查询,执行存储过程时只需发送调用命令和存储过程的名称,比执行普通 SQL 查询更快。
4.4.1 调用存储过程的参数
调用存储过程时使用三个参数:
IN
、
OUT
和
INOUT
。
-
IN
参数:包含存储过程执行所需的数据,通过调用
setXXX()
方法设置其值。
-
OUT
参数:包含存储过程执行后返回的值,需要使用
registerOutParameter()
方法进行注册,然后使用
getXXX()
方法获取其值。
-
INOUT
参数:用于向存储过程传递信息并从存储过程中获取信息。
4.4.2 示例代码
String url = "jdbc:odbc:Registration";
String userID = "jim";
String password = "keogh";
String lastOrderNumber;
Connection dB;
try {
Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver");
dB = DriverManager.getConnection(url,userID,password);
}
catch (ClassNotFoundException e) {
System.err.println(
"Unable to load the JDBC/ODBC bridge." + e);
System.exit(1);
}
catch (SQLException e) {
System.err.println(
"Cannot connect to the database." + e);
System.exit(2);
}
try {
String query = "{ CALL LastOrderNumber}";
CallableStatement cstatement = dB.prepareCall(query);
cstatement.registerOutParameter(1, Types.VARCHAR);
cstatement.execute();
lastOrderNumber = cstatement.getString(1);
}
catch ( SQLException e ){
System.err.println("SQL error." + e);
System.exit(3);
}
finally {
cstatement.close();
dB.close();
}
4.5
ResultSet
对象的使用
executeQuery()
方法将 SQL 查询发送到 DBMS 进行处理,并返回一个
ResultSet
对象,该对象包含 DBMS 返回的数据。可以使用
ResultSet
对象的方法将数据复制到 Java 集合或变量中进行进一步处理。
4.5.1 结果集的结构
DBMS 返回的数据存储在结果集中,可以将结果集看作一个虚拟表,由行和列组成,类似于电子表格。结果集还包含元数据,如列名、列大小和数据类型等信息。
4.5.2 移动虚拟指针
可以使用虚拟指针来遍历结果集中的每一行,通过调用
ResultSet
对象的方法来移动指针。初始时,虚拟指针位于第一行上方,需要使用
next()
方法将其移动到第一行。如果存在下一行,
next()
方法返回
true
,否则返回
false
,表示已到达结果集的末尾。
4.5.3 复制数据
可以使用
getXXX()
方法将当前行的某一列的数据复制到 Java 集合或变量中,
XXX
表示列的数据类型。例如,
getString()
方法用于复制字符串类型的列数据。
4.5.4 示例代码
String url = "jdbc:odbc:Registration";
String userID = "jim";
String password = "keogh";
String printRow;
String firstName;
String lastName;
Statement dataRequest;
ResultSet results;
Connection dB;
try {
Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver");
dB = DriverManager.getConnection(url,userID,password);
}
catch (ClassNotFoundException e) {
System.err.println(
"Unable to load the JDBC/ODBC bridge." + e);
System.exit(1);
}
catch (SQLException e) {
System.err.println(
"Cannot connect to the database." + e);
System.exit(2);
}
try {
String query = "SELECT FirstName,LastName FROM Students";
dataRequest = dB.createStatement();
results = dataRequest.executeQuery (query);
}
catch ( SQLException e ){
System.err.println("SQL error." + e);
System.exit(3);
}
boolean records = results.next();
if (!records ) {
System.out.println("No data returned");
System.exit(4);
}
try {
do {
firstName = results.getString ( 1 );
lastName = results.getString ( 2 );
printRow = firstName + " " + lastName;
System.out.println(printRow);
} while (results.next() );
dataRequest.close();
}
4.6 整体流程图
graph TD;
A[开始] --> B[加载驱动];
B --> C{是否成功加载?};
C -- 是 --> D[连接数据库];
C -- 否 --> E[处理 ClassNotFoundException 异常并退出];
D --> F{是否成功连接?};
F -- 是 --> G[执行查询];
F -- 否 --> H[处理 SQLException 异常并退出];
G --> I[处理结果集];
I --> J[关闭连接];
J --> K[结束];
E --> K;
H --> K;
通过以上内容,我们详细介绍了 JDBC 与 Java 数据对象的相关知识,包括数据检索、异常处理、避免连接超时以及不同类型的
Statement
对象和
ResultSet
对象的使用方法。希望这些内容对大家在使用 Java 与数据库进行交互时有所帮助。
5. 实际应用案例分析
5.1 学生信息查询系统示例
假设我们要开发一个学生信息查询系统,根据学生 ID 查询学生的基本信息。我们可以使用
PreparedStatement
对象来实现这个功能。以下是具体的实现步骤:
1.
加载驱动并建立连接
:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class StudentQuerySystem {
public static void main(String[] args) {
String url = "jdbc:odbc:Registration";
String userID = "jim";
String password = "keogh";
Connection dB = null;
PreparedStatement pstatement = null;
ResultSet results = null;
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
dB = DriverManager.getConnection(url, userID, password);
} catch (ClassNotFoundException e) {
System.err.println("Unable to load the JDBC/ODBC bridge." + e);
System.exit(1);
} catch (SQLException e) {
System.err.println("Cannot connect to the database." + e);
System.exit(2);
}
- 准备 SQL 查询语句 :
try {
String query = "SELECT FirstName, LastName, Age FROM Students WHERE StudentID = ?";
pstatement = dB.prepareStatement(query);
- 设置查询参数 :
// 假设要查询学生 ID 为 123 的信息
pstatement.setString(1, "123");
- 执行查询并处理结果 :
results = pstatement.executeQuery();
if (results.next()) {
String firstName = results.getString("FirstName");
String lastName = results.getString("LastName");
int age = results.getInt("Age");
System.out.println("学生姓名: " + firstName + " " + lastName + ", 年龄: " + age);
} else {
System.out.println("未找到该学生信息。");
}
} catch (SQLException e) {
System.err.println("SQL error." + e);
System.exit(3);
} finally {
try {
if (results != null) results.close();
if (pstatement != null) pstatement.close();
if (dB != null) dB.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
5.2 存储过程调用示例
假设数据库中有一个存储过程
GetStudentCount
用于统计学生的数量,我们可以使用
CallableStatement
对象来调用这个存储过程。以下是具体的实现步骤:
1.
加载驱动并建立连接
:
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Types;
public class StudentCountProcedure {
public static void main(String[] args) {
String url = "jdbc:odbc:Registration";
String userID = "jim";
String password = "keogh";
Connection dB = null;
CallableStatement cstatement = null;
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
dB = DriverManager.getConnection(url, userID, password);
} catch (ClassNotFoundException e) {
System.err.println("Unable to load the JDBC/ODBC bridge." + e);
System.exit(1);
} catch (SQLException e) {
System.err.println("Cannot connect to the database." + e);
System.exit(2);
}
- 准备调用存储过程的 SQL 语句 :
try {
String query = "{CALL GetStudentCount(?)}";
cstatement = dB.prepareCall(query);
- 注册输出参数 :
cstatement.registerOutParameter(1, Types.INTEGER);
- 执行存储过程并获取结果 :
cstatement.execute();
int studentCount = cstatement.getInt(1);
System.out.println("学生总数: " + studentCount);
} catch (SQLException e) {
System.err.println("SQL error." + e);
System.exit(3);
} finally {
try {
if (cstatement != null) cstatement.close();
if (dB != null) dB.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
6. 性能优化建议
6.1 合理使用
PreparedStatement
如前文所述,
PreparedStatement
适用于多次执行相似查询的场景。通过预编译查询语句,可以减少每次查询时的编译开销,提高查询性能。例如,在一个学生信息管理系统中,经常需要根据不同的学生 ID 查询学生信息,使用
PreparedStatement
可以显著提高查询效率。
6.2 及时关闭资源
在使用完
ResultSet
、
Statement
和
Connection
对象后,要及时调用
close()
方法关闭这些资源。否则,可能会导致资源泄漏,影响系统性能。可以使用
try-with-resources
语句来确保资源的正确关闭,示例如下:
try (Connection dB = DriverManager.getConnection(url, userID, password);
PreparedStatement pstatement = dB.prepareStatement(query);
ResultSet results = pstatement.executeQuery()) {
// 处理结果集
while (results.next()) {
// 处理每一行数据
}
} catch (SQLException e) {
e.printStackTrace();
}
6.3 批量操作
如果需要插入、更新或删除大量数据,可以使用批量操作来提高性能。
Statement
和
PreparedStatement
都支持批量操作,通过调用
addBatch()
方法将多个 SQL 语句添加到批处理中,然后调用
executeBatch()
方法一次性执行这些语句。以下是一个批量插入数据的示例:
try (Connection dB = DriverManager.getConnection(url, userID, password);
PreparedStatement pstatement = dB.prepareStatement("INSERT INTO Students (FirstName, LastName) VALUES (?, ?)")) {
for (int i = 0; i < 100; i++) {
pstatement.setString(1, "FirstName" + i);
pstatement.setString(2, "LastName" + i);
pstatement.addBatch();
}
int[] results = pstatement.executeBatch();
System.out.println("插入的记录数: " + results.length);
} catch (SQLException e) {
e.printStackTrace();
}
6.4 性能优化流程图
graph TD;
A[开始] --> B[合理使用 PreparedStatement];
B --> C[及时关闭资源];
C --> D[使用批量操作];
D --> E[结束];
7. 总结
7.1 关键知识点回顾
-
数据检索与显示
:通过
ResultSet对象和getString()等方法从数据库中检索数据并显示。 -
异常处理
:使用
try-catch块捕获并处理ClassNotFoundException和SQLException等异常。 -
避免连接超时
:通过
DriverManager.setLoginTimeout()方法设置连接超时时间。 -
不同类型的
Statement对象 :Statement用于立即执行查询,PreparedStatement用于预编译查询,CallableStatement用于执行存储过程。 -
ResultSet对象 :用于处理数据库返回的结果集,通过虚拟指针和getXXX()方法复制数据。
7.2 应用场景总结
-
Statement对象 :适用于一次性执行的简单查询。 -
PreparedStatement对象 :适用于多次执行相似查询的场景,如根据不同条件查询学生信息。 -
CallableStatement对象 :适用于执行存储过程,如统计学生数量、计算订单总金额等。
通过掌握这些知识和技巧,我们可以更加高效地使用 Java 与数据库进行交互,开发出性能优良、稳定可靠的数据库应用程序。在实际开发中,要根据具体的业务需求选择合适的
Statement
对象和优化策略,以提高系统的性能和可维护性。
超级会员免费看
1158

被折叠的 条评论
为什么被折叠?



