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

JDBC 基础: API、SQL 注入问题,事务、连接池

一、JDBC

  1. JDBC 全称 Java DataBase Connectivity,是 Java 数据库连接规范,用于通过 Java 代码操作数据库
  2. JDBC 是一套接口规范,实现类由各数据库厂商提供
  3. 数据库驱动是厂商提供的实现类,使用 MySQL 需导入 mysql-connector-java 驱动 jar 包。
  4. JDBC 核心作用是建立 Java 程序与数据库的连接,实现数据增删改查操作

二、JDBC 快速入门开发步骤

  1. 创建数据库与数据表
    1. 创建数据库:create database jdbcdemo;
    2. 使用数据库:use jdbcdemo;
    3. 创建用户表:
create table t_user( id int primary key auto_increment, username varchar(30), password varchar(30), email varchar(30) );
  1. 插入测试数据:
insert into t_user values (null,'aaa','123','aaa@163.com'); insert into t_user values (null,'bbb','456','bb@163.com'); insert into t_user values (null,'ccc','789','ccc@163.com');
  1. 编写 Java 代码实现查询
    1. 加载驱动
    2. 获取数据库连接
    3. 编写 SQL 语句
    4. 获取执行 SQL 的对象
    5. 执行 SQL 并处理结果集
    6. 释放资源

查询代码:

import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class JdbcSelectDemo { public static void main(String[] args) throws Exception { // 1.加载驱动 Class.forName("com.mysql.jdbc.Driver"); // 2.获取连接 String url = "jdbc:mysql:///jdbcdemo"; Connection conn = DriverManager.getConnection(url, "root", "root"); // 3.获取执行SQL对象 Statement stmt = conn.createStatement(); // 4.编写并执行SQL String sql = "select * from t_user"; ResultSet rs = stmt.executeQuery(sql); // 5.遍历结果集 while (rs.next()) { int id = rs.getInt("id"); String username = rs.getString("username"); String password = rs.getString("password"); String email = rs.getString("email"); System.out.println(id + " " + username + " " + password + " " + email); } // 6.释放资源 rs.close(); stmt.close(); conn.close(); } }

三、API

(一)DriverManager 类

  1. 作用:管理 JDBC 驱动,获取数据库连接。
  2. 加载驱动
    1. Class.forName("com.mysql.jdbc.Driver");
    2. 避免直接使用 registerDriver 方法,防止驱动重复加载、降低耦合。
  3. 获取连接
    1. 方法:static Connection getConnection(String url, String user, String password)
    2. URL 格式:jdbc:mysql://localhost:3306/数据库名
    3. 本地简写:jdbc:mysql:///数据库名
    4. 参数:用户名、数据库密码

DriverManager 获取连接:

Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql:///jdbcdemo"; Connection conn = DriverManager.getConnection(url, "root", "root");

(二)Connection 接口

  1. 作用:代表数据库连接,资源稀有,使用后必须释放。
  2. 获取执行 SQL 对象
    1. Statement createStatement():普通执行对象
    2. PreparedStatement prepareStatement(String sql):预编译执行对象,防 SQL 注入
  3. 事务管理
    1. setAutoCommit(boolean autoCommit):设置事务自动提交
    2. commit():提交事务
    3. rollback():回滚事务

Connection 获取执行对象:

// 获取普通Statement Statement stmt = conn.createStatement(); // 获取预编译PreparedStatement String sql = "select * from t_user where username=?"; PreparedStatement pstmt = conn.prepareStatement(sql);

(三)Statement 接口

  1. 作用:执行静态 SQL 语句。
  2. 核心方法
    1. executeQuery(String sql):执行查询语句,返回 ResultSet 结果集
    2. executeUpdate(String sql):执行增删改语句,返回受影响行数
  3. 支持批处理操作:addBatch、clearBatch、executeBatch

Statement 增删改代码

// 添加 String sqlInsert = "insert into t_user values(null,'test','123','test@qq.com')"; int rowsInsert = stmt.executeUpdate(sqlInsert); // 修改 String sqlUpdate = "update t_user set password='888' where username='aaa'"; int rowsUpdate = stmt.executeUpdate(sqlUpdate); // 删除 String sqlDelete = "delete from t_user where id=3"; int rowsDelete = stmt.executeUpdate(sqlDelete);

(四)PreparedStatement 接口

  1. 是 Statement 子接口,支持预编译 SQL,解决 SQL 注入漏洞。
  2. 使用占位符?替代参数,SQL 先编译后传参。
  3. 常用方法
    1. setXxx(参数位置, 参数值):为占位符赋值
    2. executeQuery():执行查询
    3. executeUpdate():执行增删改

PreparedStatement 完整代码:

String sql = "insert into t_user values(null,?,?,?)"; PreparedStatement pstmt = conn.prepareStatement(sql); // 设置参数 pstmt.setString(1, "preUser"); pstmt.setString(2, "prePwd"); pstmt.setString(3, "pre@qq.com"); // 执行 int rows = pstmt.executeUpdate();

(五)ResultSet 接口

  1. 作用:封装查询结果集,以表格形式存储数据。
  2. 核心方法
    1. next():向下移动游标,判断是否有下一行数据
    2. getXxx(字段名/下标):获取指定字段值,下标从 1 开始
    3. getObject():获取任意类型数据,需自行强转

ResultSet 遍历:

ResultSet rs = stmt.executeQuery("select * from t_user"); while (rs.next()) { int id = rs.getInt(1); String name = rs.getString("username"); System.out.println(id + "---" + name); }

四、资源释放

  1. 连接、执行对象、结果集使用后必须释放。
  2. 释放代码放在 finally 代码块中,保证一定执行。
  3. 释放顺序:ResultSet → Statement → Connection。
  4. 释放前判断对象非空,避免空指针异常。
ResultSet rs = null; Statement stmt = null; Connection conn = null; try { // 数据库操作 } catch (Exception e) { e.printStackTrace(); } finally { // 释放 if (rs != null) { try { rs.close(); } catch (Exception e) { e.printStackTrace(); } } if (stmt != null) { try { stmt.close(); } catch (Exception e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (Exception e) { e.printStackTrace(); } } }

五、SQL 注入问题

  1. 漏洞原理:拼接 SQL 语句时,用户输入特殊字符改变 SQL 逻辑。
  2. 典型注入语句:aaa' or '1=1aaa' -- '
  3. 危害:已知用户名可任意登录,绕过密码验证。
  4. 解决方案:使用 PreparedStatement 预编译对象。

SQL 注入演示:

// 危险:字符串拼接SQL String username = "aaa' or '1=1"; String password = "任意密码"; String sql = "select * from t_user where username='" + username + "' and password='" + password + "'";

解决方法(PreparedStatement):

String sql = "select * from t_user where username=? and password=?"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, username); pstmt.setString(2, password); ResultSet rs = pstmt.executeQuery();

六、数据库事务

(一)事务

  1. 事务是数据库操作的最小单元,要么全部成功,要么全部失败。
  2. 典型场景:银行转账,扣款与加款必须同时成功或失败。

事务测试表 SQL:

create table t_account( id int primary key auto_increment, username varchar(20), money double ); insert into t_account values (null,'美美',10000); insert into t_account values (null,'冠希',10000);

(二)MySQL 事务操作

  1. 命令行方式
    1. 开启事务:start transaction;
    2. 执行 SQL 语句
    3. 提交事务:commit;
    4. 回滚事务:rollback;
  2. 设置非自动提交
    1. 关闭自动提交:set autocommit = off;
    2. 手动执行 commit 或 rollback

(三)JDBC 事务操作

  1. 核心依赖 Connection 接口。
  2. 步骤
    1. 关闭自动提交:conn.setAutoCommit(false);
    2. 执行多个 SQL 操作
    3. 正常执行:conn.commit();
    4. 出现异常:conn.rollback();

JDBC 转账事务:

public void transfer() { Connection conn = null; PreparedStatement p1 = null; PreparedStatement p2 = null; try { Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mysql:///jdbcdemo", "root", "root"); // 开启事务 conn.setAutoCommit(false); // 冠希 -1000 String sql1 = "update t_account set money=money-1000 where username='冠希'"; p1 = conn.prepareStatement(sql1); p1.executeUpdate(); // 美美 +1000 String sql2 = "update t_account set money=money+1000 where username='美美'"; p2 = conn.prepareStatement(sql2); p2.executeUpdate(); // 提交 conn.commit(); System.out.println("转账成功"); } catch (Exception e) { e.printStackTrace(); // 回滚 try { if (conn != null) conn.rollback(); } catch (Exception ex) { ex.printStackTrace(); } System.out.println("转账失败"); } finally { // 释放资源 try { if (p1 != null) p1.close(); if (p2 != null) p2.close(); if (conn != null) conn.close(); } catch (Exception e) { e.printStackTrace(); } } }

(四)事务四大特性(ACID)

  1. 原子性:事务不可分割,全部执行或全部不执行。
  2. 一致性:事务执行前后数据总量保持一致。
  3. 隔离性:并发事务之间相互隔离,不干扰。
  4. 持久性:事务提交后数据永久保存到数据库。

(五)事务隔离性问题

  1. 脏读:读取到其他事务未提交的数据。
  2. 不可重复读:同一事务多次查询结果不一致,针对 update 操作。
  3. 幻读:同一事务多次查询结果不一致,针对 insert 操作。

(六)四种隔离级别

  1. Read uncommitted:最低级别,无法解决任何问题。
  2. Read committed:避免脏读,允许不可重复读、幻读。
  3. Repeatable read:MySQL 默认级别,避免脏读、不可重复读,允许幻读。
  4. Serializable:最高级别,避免所有问题,性能最低。
  5. 安全性:Serializable > Repeatable read > Read committed > Read uncommitted。
  6. 效率:Serializable < Repeatable read < Read committed < Read uncommitted。

七、数据库连接池

(一)连接池概述

  1. 解决频繁创建、销毁连接的性能损耗问题。
  2. 连接可复用,提升程序执行效率。
  3. 核心参数:初始连接数、最大连接数、最小空闲连接、最大等待时间。

(二)DataSource 接口

  1. SUN 公司定义标准接口,所有连接池必须实现。
  2. 核心方法:Connection getConnection()获取连接。

(三)常用连接池

  1. DBCP:Apache 开源组织提供。
  2. C3P0:传统开源连接池。
  3. Druid:阿里巴巴开发,性能、功能最优,支持监控、加密等。

(四)Druid 连接池使用步骤

  1. 导入 druid 对应的 jar 包。
  2. 配置参数
    1. 驱动类:driverClassName=com.mysql.jdbc.Driver
    2. 连接地址:url=jdbc:mysql:///数据库名
    3. 用户名、密码
    4. 初始连接数、最大连接数、最大等待时间

druid.properties 配置文件:

driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql:///jdbcdemo username=root password=root initialSize=5 maxActive=10 maxWait=3000
  1. 编写工具类
    1. 静态代码块加载配置文件,创建连接池对象。
    2. 提供获取连接、释放资源的静态方法。
  2. 连接释放:调用 close () 方法并非销毁连接,而是归还到连接池。

Druid 工具类:

import com.alibaba.druid.pool.DruidDataSourceFactory; import javax.sql.DataSource; import java.io.InputStream; import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement; import java.util.Properties; public class JdbcUtils { private static DataSource dataSource; static { try { Properties prop = new Properties(); InputStream is = JdbcUtils.class.getResourceAsStream("/druid.properties"); prop.load(is); dataSource = DruidDataSourceFactory.createDataSource(prop); } catch (Exception e) { e.printStackTrace(); } } // 获取连接 public static Connection getConnection() throws Exception { return dataSource.getConnection(); } // 释放资源 public static void close(ResultSet rs, Statement stmt, Connection conn) { try { if (rs != null) rs.close(); if (stmt != null) stmt.close(); if (conn != null) conn.close(); } catch (Exception e) { e.printStackTrace(); } } }

Druid 使用测试:

public class DruidTest { public static void main(String[] args) throws Exception { Connection conn = JdbcUtils.getConnection(); String sql = "insert into t_user values(null,'druid','123','druid@qq.com')"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.executeUpdate(); JdbcUtils.close(null, pstmt, conn); } }

八、JDBC 工具类封装

  1. 作用:简化连接获取、资源释放操作。
  2. 实现方式
    1. 配置文件存储数据库参数,解耦代码。
    2. 静态代码块初始化连接池。
    3. 提供统一的 getConnection 方法。
    4. 重载 close 方法,支持不同场景资源释放。

工具类重载 close 方法:

// 无结果集 public static void close(Statement stmt, Connection conn) { close(null, stmt, conn); }
http://www.jsqmd.com/news/711447/

相关文章:

  • Mamba-2状态空间模型的编译器优化与实现
  • 反向海淘独立站搭建与SaaS工具选型:技术轻量化落地路径解析
  • AMO-Bench:高中数学竞赛大语言模型评估体系构建
  • Meshroom:基于节点的可视化编程工具箱如何重新定义3D重建工作流
  • 2026年北京同仁堂虫草回收靠谱机构top5排行参考:北京名酒回收,北京洋酒回收,北京清酒回收,实力盘点! - 优质品牌商家
  • 基于模型预测控制的两轮差速移动机器人轨迹跟踪研究(Matlab代码、Simulink仿真实现)
  • AI代码沙箱安全实践白皮书(Docker+Seccomp+gVisor三重防护实测报告)
  • 2026 最新版:凌风工具箱 TEMU 采集上架|凌风工具箱一键铺货更高效
  • 用 OpenCV 实现云顶之弈英雄识别:从截图到英雄 ID 的完整拆解
  • 05.实战 YOLOv8:零错误端到端目标检测教程
  • C#开发的网络版通用进销存系统源码V15(含完整功能模块)
  • 基于模型预测控制MPC的轮式移动机器人/两轮差速移动机器人轨迹跟踪研究(Matlab代码、Simulink仿真实现)
  • 高质量LLM数据集精选与实战:从数据构建到模型微调全流程解析
  • 从暗通道先验到引导滤波:一个图像去雾算法的十年演进与工程优化
  • RWKV Runner:零门槛部署本地大模型,图形化工具与OpenAI API兼容
  • 5分钟跑通 Claude API(国内版教程)
  • 主动推理LLM系统架构设计与应用实践
  • 北京清酒回收技术解析与合规操作推荐2026 - 优质品牌商家
  • 【Eclipse】运行easyx
  • 超越G代码:深入LinuxCNC的HAL层,像搭积木一样自定义你的数控逻辑(附Python联动案例)
  • 【图像传输】OFDM图像加密传输(含QAM QPSK)【含GUI Matlab源码 15384期】
  • 少儿艺术机构,守护成长每一程
  • API中转站靠谱吗?我踩过的3个坑
  • 金融 AI 必看:OWASP 十大风险警示 —— 大模型安全不是选择题,是必答题(THS)
  • 硅基流动平台认证专享礼,免费领取16元全平台通用代金卷!硅基流动代金卷使用方法,可调用Deepseek-v4!
  • 固件防篡改不是选择题,而是生死线:某航电系统因未启用CRC32+SM3双模校验导致整机拒飞的真实事件全复盘
  • 酷特AGI:从“自家试验田”到“全球输出”
  • 基于矢量水听器的潜标探测系统——信号处理部分
  • Go语言的上下文管理详解
  • DeepSeek V4大模型算法解析