当前位置: 首页 > news >正文

JDBC基本操作

在 Java 应用程序中与数据库交互,执行 SQL 语句是核心操作之一。本文将详细介绍如何通过 JDBC 执行 SELECT、INSERT、UPDATE、DELETE 等常见 SQL 语句,并提供优化建议和最佳实践。

一、执行 SQL 语句的基本流程

通过 JDBC 执行 SQL 语句的基本步骤:

  1. 建立数据库连接:获取 Connection 对象
  2. 创建 Statement 对象:使用 Connection 创建 Statement 或 PreparedStatement
  3. 执行 SQL 语句:根据语句类型选择合适的执行方法
  4. 处理结果:对于查询语句,处理 ResultSet;对于更新语句,获取受影响行数
  5. 关闭资源:按顺序关闭 ResultSet、Statement 和 Connection

下面是一个完整的示例,展示了执行不同类型 SQL 语句的基本结构:

import java.sql.*;public class JdbcSqlExample {private static final String URL = "jdbc:mysql://localhost:3306/mydatabase";private static final String USERNAME = "root";private static final String PASSWORD = "password";public static void main(String[] args) {try (Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD)) {// 设置自动提交为 false,开启事务控制conn.setAutoCommit(false);try {// 1. 执行 INSERT 语句insertData(conn);// 2. 执行 UPDATE 语句updateData(conn);// 3. 执行 DELETE 语句deleteData(conn);// 4. 执行 SELECT 语句selectData(conn);// 提交事务conn.commit();} catch (SQLException e) {// 发生异常时回滚事务conn.rollback();e.printStackTrace();}} catch (SQLException e) {e.printStackTrace();}}// 插入数据示例private static void insertData(Connection conn) throws SQLException {String sql = "INSERT INTO users (name, age, email) VALUES (?, ?, ?)";try (PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setString(1, "李四");pstmt.setInt(2, 30);pstmt.setString(3, "lisi@example.com");int rows = pstmt.executeUpdate();System.out.println("插入 " + rows + " 行数据");}}// 更新数据示例private static void updateData(Connection conn) throws SQLException {String sql = "UPDATE users SET age = ? WHERE name = ?";try (PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setInt(1, 31);pstmt.setString(2, "李四");int rows = pstmt.executeUpdate();System.out.println("更新 " + rows + " 行数据");}}// 删除数据示例private static void deleteData(Connection conn) throws SQLException {String sql = "DELETE FROM users WHERE age > ?";try (PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setInt(1, 40);int rows = pstmt.executeUpdate();System.out.println("删除 " + rows + " 行数据");}}// 查询数据示例private static void selectData(Connection conn) throws SQLException {String sql = "SELECT id, name, age, email FROM users WHERE age < ?";try (PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setInt(1, 40);try (ResultSet rs = pstmt.executeQuery()) {while (rs.next()) {int id = rs.getInt("id");String name = rs.getString("name");int age = rs.getInt("age");String email = rs.getString("email");System.out.printf("ID: %d, 姓名: %s, 年龄: %d, 邮箱: %s%n", id, name, age, email);}}}}
}

二、执行不同类型 SQL 语句的详细说明

1. SELECT 查询语句

查询语句用于从数据库中检索数据,返回一个 ResultSet 对象。

String sql = "SELECT * FROM products WHERE price > ? AND category = ?";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setDouble(1, 100.0);pstmt.setString(2, "电子产品");try (ResultSet rs = pstmt.executeQuery()) {// 处理结果集while (rs.next()) {int id = rs.getInt("id");String name = rs.getString("name");double price = rs.getDouble("price");// 处理其他字段...}}
}

关键方法

  • executeQuery():执行查询语句,返回 ResultSet
  • ResultSet.next():移动游标到下一行
  • ResultSet.getXXX():获取不同类型的字段值

2. INSERT 插入语句

插入语句用于向数据库表中添加新记录。

String sql = "INSERT INTO orders (order_number, customer_id, order_date) VALUES (?, ?, ?)";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setString(1, "ORD-2023001");pstmt.setInt(2, 1001);pstmt.setDate(3, new java.sql.Date(System.currentTimeMillis()));int rows = pstmt.executeUpdate();System.out.println("插入 " + rows + " 行数据");
}

关键方法

  • executeUpdate():执行插入、更新或删除语句,返回受影响的行数

3. UPDATE 更新语句

更新语句用于修改数据库表中的现有记录。

String sql = "UPDATE products SET price = price * ? WHERE category = ?";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setDouble(1, 1.1); // 价格上涨10%pstmt.setString(2, "书籍");int rows = pstmt.executeUpdate();System.out.println("更新 " + rows + " 行数据");
}

4. DELETE 删除语句

删除语句用于从数据库表中删除记录。

String sql = "DELETE FROM customers WHERE last_login < ?";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {// 删除一年前登录的客户Calendar cal = Calendar.getInstance();cal.add(Calendar.YEAR, -1);pstmt.setDate(1, new java.sql.Date(cal.getTimeInMillis()));int rows = pstmt.executeUpdate();System.out.println("删除 " + rows + " 行数据");
}

三、高级 SQL 执行技术

1. 批量操作

对于大量数据的插入或更新,使用批量操作可以显著提高性能。

String sql = "INSERT INTO logs (log_time, message, level) VALUES (?, ?, ?)";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {// 禁用自动提交,开启事务conn.setAutoCommit(false);// 添加多个批处理命令for (LogEntry entry : logEntries) {pstmt.setTimestamp(1, new Timestamp(entry.getTime()));pstmt.setString(2, entry.getMessage());pstmt.setString(3, entry.getLevel());pstmt.addBatch();}// 执行批量操作int[] results = pstmt.executeBatch();// 提交事务conn.commit();
}

2. 获取自动生成的键

当插入记录时,如果表使用自增主键,可以获取生成的主键值。

String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
try (PreparedStatement pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {pstmt.setString(1, "王五");pstmt.setString(2, "wangwu@example.com");int rows = pstmt.executeUpdate();if (rows > 0) {// 获取自动生成的键try (ResultSet generatedKeys = pstmt.getGeneratedKeys()) {if (generatedKeys.next()) {long userId = generatedKeys.getLong(1);System.out.println("插入用户的ID是: " + userId);}}}
}

3. 执行存储过程

使用 CallableStatement 执行数据库存储过程。

// 调用带输入输出参数的存储过程
String sql = "{call calculate_discount(?, ?, ?)}";
try (CallableStatement cstmt = conn.prepareCall(sql)) {// 设置输入参数cstmt.setDouble(1, 1000.0);  // 订单金额cstmt.setString(2, "VIP");   // 会员等级// 注册输出参数cstmt.registerOutParameter(3, Types.DOUBLE);// 执行存储过程cstmt.execute();// 获取输出参数double discount = cstmt.getDouble(3);System.out.println("折扣金额: " + discount);
}

四、SQL 语句优化建议

1. 使用 PreparedStatement 而非 Statement

PreparedStatement 的优势:

  • 防止 SQL 注入攻击
  • 预编译 SQL 语句,提高执行效率
  • 更好地处理参数类型

2. 优化查询语句

  • **避免使用 SELECT ***:只选择需要的字段
  • 添加适当的索引:对经常用于 WHERE 子句和 JOIN 的字段添加索引
  • 优化 JOIN 语句:确保 JOIN 字段上有索引,使用合适的 JOIN 类型
  • 分页查询:使用 LIMIT 和 OFFSET 限制返回的记录数
// 分页查询示例
int pageSize = 20;
int pageNumber = 1;
String sql = "SELECT id, name, price FROM products ORDER BY price DESC LIMIT ? OFFSET ?";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {pstmt.setInt(1, pageSize);pstmt.setInt(2, (pageNumber - 1) * pageSize);// 执行查询...
}

3. 批量处理数据

对于大量数据操作,使用批量处理代替循环单条操作:

// 批量插入示例 - 每500条记录提交一次
int batchSize = 500;
int count = 0;for (DataRecord record : dataRecords) {pstmt.setString(1, record.getName());pstmt.setInt(2, record.getValue());pstmt.addBatch();if (++count % batchSize == 0) {pstmt.executeBatch();}
}// 处理剩余记录
pstmt.executeBatch();

4. 事务管理

  • 将相关操作放在一个事务中
  • 根据业务需求设置合适的事务隔离级别
  • 确保事务尽快提交,减少锁持有时间
try {conn.setAutoCommit(false);// 执行多个SQL操作updateInventory(conn, productId, quantity);createOrder(conn, orderData);updateCustomerPoints(conn, customerId, points);conn.commit();
} catch (SQLException e) {conn.rollback();throw e;
} finally {conn.setAutoCommit(true);
}

五、常见问题与解决方案

1. SQL 注入问题

错误做法:直接拼接 SQL 语句

// 存在SQL注入风险
String sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";

正确做法:使用 PreparedStatement

String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
pstmt.setString(1, username);
pstmt.setString(2, password);

2. 资源泄漏问题

错误做法:不关闭资源

Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
// 使用结果集,但没有关闭rs和stmt

正确做法:使用 try-with-resources 语句

try (Statement stmt = conn.createStatement();ResultSet rs = stmt.executeQuery(sql)) {// 使用结果集
} // 自动关闭rs和stmt

3. 性能问题

  • 问题表现:大量数据查询缓慢、频繁创建连接
  • 解决方案:使用连接池、批量操作、优化查询语句、添加适当索引

六、总结

通过 JDBC 执行 SQL 语句是 Java 数据库编程的基础,掌握以下关键点:

  1. 基本流程:建立连接 → 创建 Statement → 执行 SQL → 处理结果 → 关闭资源
  2. 不同类型 SQL 的执行:SELECT 使用 executeQuery(),INSERT/UPDATE/DELETE 使用 executeUpdate()
  3. 高级技术:批量操作、获取自动生成键、执行存储过程
  4. 优化策略:使用 PreparedStatement、优化查询、批量处理、合理使用事务
  5. 最佳实践:防止 SQL 注入、正确管理资源、处理异常

合理使用这些技术和策略,可以构建高效、安全、稳定的数据库应用程序。在实际开发中,还可以考虑使用 ORM 框架(如 Hibernate、MyBatis)来进一步简化数据库操作。

相关文章:

  • 基于大语言模型的浏览器翻译插件
  • 一键下载智享 AI 直播(三代)!打造直播生态闭环,解锁流量增长新密码
  • JavaScript- 4.1 DOM-document对象
  • 如何设计高效的索引策略?
  • IoT/HCIP实验-1/物联网开发平台实验Part2(HCIP-IoT实验手册版)
  • Java 继承(下)
  • [java八股文][JavaSpring面试篇]SpringBoot
  • vue+threeJs 设置模型默认的旋转角度
  • some面试题2
  • 树莓派超全系列教程文档--(49)远程访问树莓派
  • 2.2.1 05年T3
  • 网络常识:网线和光纤的区别
  • 微信小程序的软件测试用例编写指南及示例
  • Java 继承(上)
  • JavaScript性能优化全景指南
  • STM32的DMA入门指南:让单片机学会“自动搬运“数据
  • 自动驾驶决策规划框架详解:从理论到实践
  • Asp.Net Core 通过JWT版本号实现JWT无法提前撤回的问题
  • GitHub push失败解决办法-fatal: unable to access ‘https://github.com/xxx
  • 封装文档核心知识点总结(通俗版)
  • 企业建站公司服务/环球贸易网
  • 排名前十的招聘app/seo综合查询怎么用的
  • 网站后台更新 前台看不到/百度指数专业版价格
  • 做网站优化如何遍文章/广东省新闻
  • 深圳网站设计公司排名前十强/友情链接网站源码
  • 城阳网站制作/软文推广网站