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

JDBC核心技术与预编译SQL实战

JDBC

一、JDBC 介绍

(一)概念

JDBC(Java DataBase Connectivity),是使用 Java 语言操作关系型数据库的一套 API 。本质上,它是 Sun 公司官方定义的一套操作所有关系型数据库的规范(接口) 。各个数据库厂商会去实现这套接口,提供数据库驱动 jar 包,我们使用 JDBC 编程时,真正执行的代码是驱动 jar 包中的实现类,借此可通过 Java 程序操作 MySQL、Oracle、SQL Server 等不同关系型数据库 。

(二)依赖引入(以 Maven 项目为例,操作 MySQL 时)

在项目的 pom.xml 文件中添加如下依赖,引入 MySQL 的 JDBC 驱动:

<dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>8.0.33</version>
</dependency>

二、JDBC 执行DML语句(以insert为例)

(一)需求

基于 JDBC 程序,执行 update 语句(如 update user set name = 'xiaohua' where id = 1 ) 。

(二)代码实现(结合实际 Java 代码说明)

以下是使用 JDBC 操作数据库执行更新操作的完整 Java 代码及对应步骤解析,代码所在类为 jdbcTest ,位于 com.itxiaoli 包下:

package com.itxiaoli;import org.junit.Test;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;public class jdbcTest {/*** jdbc连接数据库入门程序*/@Testpublic void testUpdate() throws ClassNotFoundException, SQLException {// 1. 加载驱动(注册驱动)// 加载 MySQL 数据库的 JDBC 驱动类,让 Java 程序知道如何与 MySQL 数据库交互Class.forName("com.mysql.cj.jdbc.Driver");// 2. 获取数据库连接// 定义数据库连接的 URL,指定要连接的数据库为 *** ,运行在本地(localhost),端口 3306 String url = "***"; String username = "***"; // 数据库用户名,这里假设是 root String password = "***"; // 数据库密码 // 通过 DriverManager 的 getConnection 方法获取数据库连接对象Connection connection = DriverManager.getConnection(url, username, password);// 3. 获取 SQL 语句执行对象// 通过数据库连接对象创建 Statement 对象,用于执行 SQL 语句Statement statement = connection.createStatement();// 4. 执行 SQL 语句,并获取结果集// executeUpdate 方法返回值是 int 类型,表示受影响的记录行数int i = statement.executeUpdate("insert into *** values("**",**)"); System.out.println("sql语句执行完毕");// 5. 释放资源// 先关闭 Statement 对象,再关闭 Connection 对象,释放数据库连接相关资源statement.close(); connection.close(); }
}

步骤详细说明:

  1. 加载驱动(注册驱动):通过 Class.forName("com.mysql.cj.jdbc.Driver") 加载 MySQL 数据库的 JDBC 驱动类,使 Java 程序能够识别并使用对应的数据库驱动,建立与数据库的交互基础 。
  2. 获取数据库连接:使用 DriverManager.getConnection(url, username, password) 方法,传入数据库连接 URL(指定数据库位置、名称等)、用户名、密码,获取 Connection 对象,代表 Java 程序与数据库的实际连接通道 。
  3. 获取 SQL 语句执行对象:利用 Connection 对象的 createStatement() 方法创建 Statement 对象,该对象可用于发送 SQL 语句到数据库执行 。
  4. 执行 SQL 语句:调用 Statement 对象的 executeUpdate() 方法(针对增、删、改操作),传入要执行的 SQL 语句,执行后返回受影响的记录行数 。若执行查询操作则一般使用 executeQuery() 方法 。
  5. 释放资源:操作完成后,依次关闭 StatementConnection 对象,释放占用的数据库资源,避免资源泄漏,保证程序的稳定性和高效性 。

通过上述步骤,就能借助 JDBC 完成 Java 程序对关系型数据库(这里以 MySQL 为例)的操作,实现数据的增、删、改、查等功能 。

三、JDBC 执行DQL语句(以select为例)

(一)需求说明

基于 JDBC 执行 select 语句,把查询结果封装到 User 对象中,最终整理到 List<User> 集合,实现数据从数据库到 Java 实体的映射 。示例 SQL 为 select * from user where username = 'daqiao' and password = '123456' (实际应用中条件可动态处理 )。

(二)关键对象 - ResultSet(结果集对象)

通过 ResultSet rs = statement.executeQuery() 获取,用于承载查询返回的数据,核心方法:

  • next():将光标从当前位置前移一行,判断当前行是否有效行,返回 booleantrue 代表有效(有数据),false 代表无效(无数据),是遍历结果集的基础 。
  • getXxx(...):获取数据,支持按列编号(如 getInt(1) )或列名(如 getInt("id") ,推荐,可读性高 )获取,Xxx 随数据类型变化(getIntgetString 等 )。
 // 6. 处理结果集List<User> userList = new ArrayList<>();while (resultSet.next()) {// 创建User对象并设置属性User user = new User(resultSet.getInt("id"),resultSet.getString("username"),resultSet.getString("password"),resultSet.getString("name"),resultSet.getInt("age"));userList.add(user);}

JDBC程序执行DML语句? DQL语句?

•DML语句:int rowsAffected(受影响行数) = statement.executeUpdate();

•DQL语句:ResultSet(结果集) rs = statement.executeQuery();

DQL语句执行完毕结果集ResultSet解析?

•resultSet.next():光标往下移动一行

•resultSet.getXxx():获取字段数据

预编译SQL

一、预编译 SQL 概念与对比

(一)静态 SQL(参数硬编码)

在 JDBC 操作中,早期使用 Statement 执行 SQL 时,参数是直接硬编码在 SQL 语句里。例如:

Statement statement = connection.createStatement();
int i = statement.executeUpdate("update user set age = 25 where id = 1");
System.out.println("SQL执行完毕,影响的记录数为: " + i);

这种方式存在明显弊端,参数直接拼接,若输入内容不可控,易引发安全问题,且每次执行不同参数的同结构 SQL 都要重新解析、编译,性能欠佳 。

(二)预编译 SQL(参数动态传递)

通过 PreparedStatement 实现,先定义带有占位符(? )的 SQL 模板,再动态设置参数。比如查询操作:

// 3. 准备SQL语句,使用占位符?定义参数位置,形成预编译SQL模板 
String sql = "SELECT id, username, password, name, age FROM user WHERE username = ? AND password = ?"; 
// 4. 创建PreparedStatement对象并设置参数,同时完成预编译过程 
PreparedStatement preparedStatement = connection.prepareStatement(sql); 
preparedStatement.setString(1, "daqiao"); // 为第一个占位符设置值
preparedStatement.setString(2, "123456"); // 为第二个占位符设置值
// 5. 执行查询,由于预编译已做部分优化,执行效率更高 
ResultSet resultSet = preparedStatement.executeQuery(); 

二、预编译 SQL 优势

(一)防止 SQL 注入,更安全

SQL 注入是攻击者通过控制输入,修改预先定义好的 SQL 语句,达到非法执行代码、攻击服务器的目的。比如后台登录场景,若用静态 SQL 拼接用户输入的账号密码,攻击者输入特殊构造内容(如 ' OR '1'='1 ),可能绕过验证。而预编译 SQL 中,参数会被当作普通数据处理,不是 SQL 语句的一部分,有效抵御注入风险 。

(二)性能更高

当执行多条结构相同、仅参数不同的 SQL 时,预编译优势显著。以删除操作为例:

  • 静态 SQL 方式:每次执行不同 id 的删除,如 delete from user where id = 1;delete from user where id = 2; 等,MySQL 需对每条语句单独进行语法解析检查、优化、编译,多次重复流程 。
  • 预编译 SQL 方式:只需定义一次 delete from user where id = ?; ,后续仅需设置不同 id 参数。MySQL 对预编译后的 SQL 可缓存语法解析、优化结果,后续执行直接复用,减少重复开销,提升性能,尤其批量操作时效果明显 。

三、执行预编译 SQL 步骤(结合代码说明)

在 Java 中使用 JDBC 执行预编译 SQL ,通常包含以下流程(以查询用户信息为例,基于已获取 Connection 对象 connection ):

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class PrecompileSqlDemo {public void queryUser() {Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; try {// 假设已通过合适方式获取数据库连接 connection ,如前面提到的加载驱动、获取连接步骤// 3. 准备SQL语句,定义预编译的SQL模板,用?作为参数占位符String sql = "SELECT id, username, password, name, age FROM user WHERE username = ? AND password = ?"; // 4. 创建PreparedStatement对象,同时完成SQL预编译,后续设置参数即可preparedStatement = connection.prepareStatement(sql); preparedStatement.setString(1, "daqiao"); // 为第一个?占位符设置字符串参数,位置从1开始计数preparedStatement.setString(2, "123456"); // 为第二个?占位符设置字符串参数// 5. 执行查询,获取结果集。预编译后的执行,利用缓存等优化,性能更好resultSet = preparedStatement.executeQuery(); // 可遍历结果集处理数据,此处省略遍历逻辑...} catch (SQLException e) {e.printStackTrace();} finally {// 6. 释放资源,按照ResultSet、PreparedStatement、Connection的顺序关闭try {if (resultSet != null) resultSet.close();if (preparedStatement != null) preparedStatement.close();if (connection != null) connection.close();} catch (SQLException e) {e.printStackTrace();}}}
}

步骤解析:

  1. 准备 SQL 语句:编写包含占位符 ? 的 SQL 模板,明确参数位置,告知数据库后续要动态传入的数据位置 。
  2. 创建 PreparedStatement 对象:调用 connection.prepareStatement(sql) ,此时数据库会对 SQL 进行预编译处理,生成可复用的执行计划 。
  3. 设置参数:通过 preparedStatement 提供的 setXxx 方法(如 setStringsetInt 等,根据参数类型选择),为占位符按顺序设置实际值,保证参数类型匹配,防止错误 。
  4. 执行 SQL:执行 executeQuery(查询操作)或 executeUpdate(增删改操作),由于预编译已做优化,执行效率相对静态 SQL 更高,且更安全 。
  5. 释放资源:操作完毕后,按 ResultSetPreparedStatementConnection 的顺序关闭资源,避免数据库连接泄漏,影响程序稳定性和性能 。

综上,预编译 SQL 凭借防止注入的安全性和重复执行时的高性能优势,成为 JDBC 操作中处理动态参数 SQL 语句的优选方式 。`

http://www.dtcms.com/a/313149.html

相关文章:

  • 计算机网络:如何将一个C类网络划分成两个子网
  • 集成电路学习:什么是USB HID人机接口设备
  • Web前端文件上传安全与敏感数据安全处理
  • 时序论文44 | TwinsFormer:通过两个交互组件重构时间序列内在依赖关系
  • [spring-cloud: 服务发现]-源码解析
  • 医院课题管理全动态流程 (AI-Enhanced, Data-Driven Research Lifecycle)
  • 位运算在权限授权中的应用及Vue3实践
  • 第2章算法分析:其他渐进复杂度符号
  • 免费非常好用的录屏软件,体积小
  • 【Java EE】Spring AOP
  • Gumbel-Softmax函数
  • AI+预测3D新模型百十个定位预测+胆码预测+去和尾2025年8月3日第155弹
  • 数据与信息的边界:非法获取计算机信息系统数据罪的司法困境与出路
  • 【十九、Javaweb-day19-Linux概述】
  • python---可变类型、不可变类型
  • Pytorch 报错-probability tensor contains either ‘inf‘, ‘nan‘ or element < 0 解决方案
  • Arrays.asList() add方法报错java.lang.UnsupportedOperationException
  • 8月3日星期日今日早报简报微语报早读
  • 多线程(四) ~ wait,join,sleep及单例与工厂模式
  • 图像识别区分指定物品与其他物体
  • 【华为机试】815. 公交路线
  • NumPy库学习(三):numpy在人工智能数据处理的具体应用及方法
  • 机器学习sklearn:支持向量机svm
  • Vue3 其它Composition API
  • Linux网络编程 --- 多路转接select
  • 推送本地项目到Gitee远程仓库
  • Selenium Web 自动化
  • 优选算法 力扣 202.快乐数 快慢双指针 解决带环问题 C++解题思路 每日一题
  • ThinkPHP5x,struts2等框架靶场复现
  • Coin Combinations II(Dynamic Programming)