DBC 是一套用于Java程序访问数据库的API,它提供了连接数据库、执行SQL查询和处理结果的标准方法。通过JDBC,Java程序可以连接到多种数据库,包括MySQL、PostgreSQL、Oracle、SQL Server等。JDBC的主要组成部分包括:
- JDBC Driver:驱动程序,用于与特定的数据库进行通信。每个数据库都有自己的JDBC驱动程序。
- Connection:连接对象,用于连接数据库。
- Statement:用于执行SQL查询的对象。
- ResultSet:结果集对象,用于存储查询结果。
- PreparedStatement:预编译的SQL语句对象,防止SQL注入攻击,提高查询效率。
- CallableStatement:用于执行存储过程的对象。
java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class JDBCDemo {
public static void main(String[] args) {
try {
// 加载驱动程序
Class.forName("com.mysql.cj.jdbc.Driver");
// 建立连接
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase", "username", "password");
// 创建Statement对象
Statement statement = connection.createStatement();
// 执行查询
ResultSet resultSet = statement.executeQuery("SELECT * FROM mytable");
// 处理结果
while (resultSet.next()) {
System.out.println("Column1: " + resultSet.getString("column1"));
System.out.println("Column2: " + resultSet.getString("column2"));
}
// 关闭资源
resultSet.close();
statement.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Connection
在JDBC中,Connection 对象是一个非常重要的接口,它代表了Java应用程序和数据库之间的一个连接会话。通过 Connection 对象,可以执行SQL语句、管理事务和处理数据库的连接和释放。以下是 Connection 接口的一些关键功能:
- 创建 Statement 对象 :
- createStatement():创建一个 Statement 对象来执行静态SQL语句。
- prepareStatement(String sql):创建一个 PreparedStatement 对象来执行预编译的SQL语句。这种方式可以提高性能并防止SQL注入。
- prepareCall(String sql):创建一个 CallableStatement 对象来调用数据库中的存储过程。
- 事务管理 :
- setAutoCommit(boolean autoCommit):设置此连接的事务是否自动提交。设置为 false 时,可以手动控制事务的提交或回滚。
- commit():在事务中执行了多个操作后,使用此方法提交事务,确保所有操作都被保存到数据库中。
- rollback():如果事务中的某个操作失败,可以调用此方法回滚事务,取消所有未提交的操作。
- 连接管理 :
- close():关闭此 Connection 对象和其所有相关的资源。一旦连接被关闭,就不能再使用它来执行任何操作。
- isClosed():检查此连接是否已被关闭。
- 元数据获取 :
- getMetaData():获取与此数据库连接相关的元数据。这可以提供关于数据库的结构信息,如表、列、索引等。
- 配置连接属性 :
- setReadOnly(boolean readOnly):设置此连接的只读状态。只读连接意味着通过这个连接只能查询数据,不能执行插入、更新或删除操作。
- setTransactionIsolation(int level):设置此连接的事务隔离级别,这影响了不同事务间的可见性和互相干扰的程度。
在实际开发中,建立 Connection 通常需要通过 DriverManager 类来完成,如下例所示:
java
Connection conn = DriverManager.getConnection(url, username, password);
这里,url 是数据库的URL,username 是数据库用户名称,password 是对应的密码。正确管理 Connection 对象对于维护数据库性能和数据一致性至关重要。
Statement
在JDBC中,Statement 接口是用于执行静态SQL语句并返回它所生成结果的一种机制。通过 Connection 对象创建 Statement 对象,可以用来执行基本的SQL命令。
主要方法
- 执行SQL语句
- executeQuery(String sql): 执行给定的SQL语句,该语句返回一个单一的 ResultSet 对象(通常用于查询)。
- executeUpdate(String sql): 执行给定的SQL语句(如INSERT、UPDATE、DELETE、DDL等),返回一个整数,表示受影响的行数。
- execute(String sql): 可用于执行返回多个结果集、多个更新计数或二者组合的语句。
- 资源管理 :
- close(): 释放 Statement 对象的数据库和JDBC资源。注意,与之关联的任何 ResultSet 对象也将被关闭。
- 批处理执行 :
- addBatch(String sql): 将多个SQL语句添加到批处理中,这些语句一起执行可以减少通信开销,提高性能。
- executeBatch(): 执行批量更新。
- 设置查询超时 :
- setQueryTimeout(int seconds): 设置在抛出异常前 Statement 等待数据库回应的秒数。
java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class StatementExample {
public static void main(String[] args) {
try {
// 建立连接
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase", "username", "password");
// 创建Statement对象
Statement statement = connection.createStatement();
// 执行查询
ResultSet resultSet = statement.executeQuery("SELECT * FROM employees");
while (resultSet.next()) {
System.out.println(resultSet.getString("name") + ", " + resultSet.getInt("age"));
}
// 执行更新
int rowsAffected = statement.executeUpdate("UPDATE employees SET age = age + 1 WHERE id = 1");
System.out.println("Updated rows: " + rowsAffected);
// 关闭资源
resultSet.close();
statement.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
注意事项
- SQL注入:直接使用 Statement 执行SQL语句容易受到SQL注入的攻击,特别是当SQL语句包含来自不可靠源的数据时。在这种情况下,更推荐使用 PreparedStatement,因为它支持参数化查询,可以有效防止SQL注入。
- 性能:频繁地创建和销毁 Statement 对象可能导致性能问题,特别是在大量操作数据库的应用中。预编译的 PreparedStatement 对象通常提供更好的性能,因为它们可以重复使用。
通过适当使用 Statement 和管理其生命周期,可以有效地在Java应用程序中管理数据库操作。
ResultSet
在JDBC中,ResultSet 接口代表从数据库查询返回的数据集。当执行查询数据库的SQL语句(通常是SELECT语句)时,Statement 或 PreparedStatement 对象的 executeQuery 方法会返回一个 ResultSet 对象。这个对象可以用来逐行访问查询结果。
主要方法和功能
- 数据访问 :
- next(): 将光标从当前位置向前移动一行。初次调用 next 方法将光标置于第一行。如果行存在,则返回 true;如果没有更多行,则返回 false。
- getString(int columnIndex) 或 getString(String columnLabel): 获取当前行中指定列的值作为字符串。
- 类似地,getInt, getDouble, getDate 等方法可用于获取其它数据类型的列值。
- 遍历
- ResultSet 对象最初位于第一行之前。next() 方法用于逐行遍历数据,通常在循环中使用。
- 更新数据 :
- 如果 ResultSet 是可更新的(依赖于如何创建 Statement 对象),可以修改其数据并反映回数据库。
- updateString, updateInt 等方法修改列值,updateRow 提交修改。
- 关闭 ResultSet :
- close(): 关闭 ResultSet 对象并释放相关资源。注意,一旦 Statement 对象被关闭,其生成的所有 ResultSet 对象也将自动关闭。
java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class ResultSetExample {
public static void main(String[] args) {
try {
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase", "username", "password");
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT id, name, age FROM employees");
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
int age = resultSet.getInt("age");
System.out.println("ID: " + id + ", Name: " + name + ", Age: " + age);
}
resultSet.close();
statement.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
JDBC工具类编写
首先,我们需要创建一个工具类,提供数据库连接和资源关闭的方法。这个类通常会包含获取连接、关闭 ResultSet、关闭 Statement 和 PreparedStatement、以及关闭 Connection 的静态方法。
java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCUtils {
private static final String JDBC_URL = "jdbc:mysql://localhost:3306/mydatabase";
private static final String JDBC_USER = "username";
private static final String JDBC_PASSWORD = "password";
static {
try {
// 加载数据库驱动
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
// 获取数据库连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);
}
// 关闭连接和语句
public static void close(Statement stmt, Connection conn) {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// 关闭所有资源
public static void close(ResultSet rs, Statement stmt, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
close(stmt, conn);
}
}
使用 JDBC 工具类
java
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class UseJDBCUtils {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = JDBCUtils.getConnection(); // 使用工具类获取数据库连接
String sql = "SELECT * FROM employees WHERE department_id = ?";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, 10); // 设置参数
rs = pstmt.executeQuery();
while (rs.next()) {
System.out.println("Employee Name: " + rs.getString("name"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.close(rs, pstmt, conn); // 使用工具类关闭资源
}
}
}
- 集中管理:JDBC 工具类有助于集中管理数据库连接和关闭操作,避免代码冗余。
- 异常处理:通过在工具类中统一处理异常,可以简化错误处理。
- 改进安全性:确保所有数据库连接和相关资源在使用后都被正确关闭,避免资源泄露。