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

JDBC 入门详解(附工具类与防 SQL 注入)

一、JDBC 核心概念深度解析

       JDBC(Java DataBase Connectivity)并非具体实现,而是 Java 官方定义的数据库操作标准接口规范。其设计目标是解决 “不同数据库厂商接口不统一” 的问题 ——Java 通过统一接口定义操作逻辑,MySQL、Oracle 等厂商则提供符合接口的实现类(即 “驱动”),开发者只需掌握接口用法,即可用相同的 Java 代码操作任意数据库,无需关注底层厂商差异。

1. 核心组成:接口与驱动的协作

  • 接口层:由 JDK 提供,核心接口包括Connection(数据库连接)、Statement(SQL 执行器)、ResultSet(结果集)等,定义了 “连接数据库、执行 SQL、处理结果” 的标准方法。
  • 驱动层:由数据库厂商提供,是接口的具体实现。例如 MySQL 的驱动是mysql-connector-java系列 Jar 包,Oracle 的驱动是ojdbc系列 Jar 包,开发者必须导入对应驱动才能建立连接。

2. 版本差异:MySQL 5 与 MySQL 8 驱动区别

       MySQL 5 和 MySQL 8 的驱动在类路径、URL 参数、依赖版本上存在关键差异,直接影响 JDBC 代码的正确性,具体对比如下:

对比项MySQL 5 版本(以 5.1.13 为例)MySQL 8 版本(以 8.0.30 为例)
驱动 Jar 包名称mysql-connector-java-5.1.13-bin.jarmysql-connector-java-8.0.30.jar
驱动类全路径com.mysql.jdbc.Drivercom.mysql.cj.jdbc.Driver(需加cj
URL 必填参数无需额外参数(示例:jdbc:mysql:///jdbcdemo必须加serverTimezone(示例:jdbc:mysql:///jdbcdemo?serverTimezone=UTC
自动加载驱动需手动执行Class.forName()加载支持 SPI 自动加载(可省略Class.forName(),但建议显式加载以兼容低版本 JDK)
依赖兼容性支持 JDK 5 及以上推荐 JDK 8 及以上(低版本 JDK 可能存在兼容性问题)

二、JDBC 入门核心步骤(MySQL 5/8 双版本适配)

       JDBC 操作的本质是 “按固定流程调用接口方法”,无论 MySQL 5 还是 8,核心流程均为 “加载驱动→获取连接→执行 SQL→处理结果→释放资源”,但需根据版本调整细节。

1. 环境准备:创建数据库与表(通用)

       首先在 MySQL 中创建测试数据库和表,执行以下 SQL 脚本(5/8 版本通用):

-- 1.创建数据库jdbcdemo
create database if not exists jdbcdemo character set utf8mb4 collate utf8mb4_general_ci;
-- 2.使用数据库
use jdbcdemo;
-- 3.创建用户表t_user(包含主键自增、用户名、密码、邮箱字段)
create table if not exists t_user(id int primary key auto_increment comment '用户ID(自增主键)',username varchar(30) not null comment '用户名',password varchar(30) not null comment '密码',email varchar(50) comment '邮箱'
) comment '用户表';
-- 4.插入测试数据
insert into t_user values 
(null,'aaa','123','aaa@163.com'),
(null,'bbb','456','bbb@163.com'),
(null,'ccc','789','ccc@163.com');

2. 开发五步走(双版本代码对比)

步骤 1:导入驱动 Jar 包
  • MySQL 5:下载mysql-connector-java-5.1.13-bin.jar,放入项目lib目录(或通过 Maven 依赖:<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.13</version></dependency>)。
  • MySQL 8:下载mysql-connector-java-8.0.30.jar,放入项目lib目录(或通过 Maven 依赖:<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.30</version></dependency>)。
步骤 2:加载驱动(版本差异核心点)
  • MySQL 5:必须通过Class.forName()加载驱动类,否则无法初始化驱动。
    // MySQL 5加载驱动
    Class.forName("com.mysql.jdbc.Driver");
    
  • MySQL 8:驱动类路径变为com.mysql.cj.jdbc.Driver,且支持 SPI 自动加载(JDK 6 + 可省略此步骤),但显式加载更稳妥。
    // MySQL 8加载驱动(必须加cj)
    Class.forName("com.mysql.cj.jdbc.Driver");
    
步骤 3:获取数据库连接(URL 参数差异)

       通过DriverManager.getConnection(url, username, password)获取Connection对象,url是版本差异的关键:

  • MySQL 5 URL 格式jdbc:mysql://[主机IP]:[端口号]/[数据库名],本地数据库可省略主机IP:端口号(默认localhost:3306)。
    // MySQL 5获取连接(本地数据库简写)
    String url = "jdbc:mysql:///jdbcdemo"; // 完整写法:jdbc:mysql://localhost:3306/jdbcdemo
    String username = "root"; // 你的MySQL用户名
    String password = "root"; // 你的MySQL密码
    Connection conn = DriverManager.getConnection(url, username, password);
    
  • MySQL 8 URL 格式:必须添加serverTimezone参数(解决时区错误),可选添加useSSL=false(开发环境禁用 SSL 加密,避免证书问题)。
    // MySQL 8获取连接(带时区参数)
    String url = "jdbc:mysql:///jdbcdemo?serverTimezone=UTC&useSSL=false"; // 完整写法:jdbc:mysql://localhost:3306/jdbcdemo?serverTimezone=UTC&useSSL=false
    String username = "root";
    String password = "root";
    Connection conn = DriverManager.getConnection(url, username, password);
    
步骤 4:执行 SQL 语句(分查询 / 增删改)

       根据 SQL 类型,使用StatementPreparedStatement执行(推荐后者,防 SQL 注入):

  • 查询操作:执行select语句,返回ResultSet结果集,需遍历获取数据。
    // 1.编写SQL(查询t_user所有数据)
    String sql = "select id, username, password, email from t_user";
    // 2.创建PreparedStatement对象(预编译SQL,防注入)
    PreparedStatement pstmt = conn.prepareStatement(sql);
    // 3.执行查询,获取结果集
    ResultSet rs = pstmt.executeQuery();
    // 4.遍历结果集(游标默认指向第一行前,next()移动游标并判断是否有数据)
    while (rs.next()) {// 按字段名获取数据(推荐,不受字段顺序影响)int id = rs.getInt("id"); String uname = rs.getString("username");String pwd = rs.getString("password");String email = rs.getString("email");// 按索引获取数据(索引从1开始,需与SQL字段顺序一致)// int id = rs.getInt(1);// String uname = rs.getString(2);System.out.printf("ID:%d,用户名:%s,密码:%s,邮箱:%s%n", id, uname, pwd, email);
    }
    
  • 增删改操作:执行insert/update/delete语句,返回受影响的行数(int 类型)。
    // 示例:新增用户(MySQL 5/8通用)
    String sql = "insert into t_user(username, password, email) values(?, ?, ?)";
    PreparedStatement pstmt = conn.prepareStatement(sql);
    // 给占位符赋值(?的索引从1开始,类型需与字段匹配)
    pstmt.setString(1, "ddd"); // 第一个?:username
    pstmt.setString(2, "101112"); // 第二个?:password
    pstmt.setString(3, "ddd@163.com"); // 第三个?:email
    // 执行增删改,获取受影响行数
    int rows = pstmt.executeUpdate();
    System.out.println("新增成功,受影响行数:" + rows); // 输出1表示新增1条数据
    
步骤 5:释放资源(必须执行,避免内存泄漏)

       Connection(连接)、PreparedStatement(执行器)、ResultSet(结果集)都是 “稀缺资源”,使用后必须关闭,且关闭顺序为 “ResultSet → PreparedStatement → Connection”(后创建的先关闭)。建议在finally块中处理(确保无论是否报错都会执行):

// 释放资源(通用代码)
finally {// 关闭ResultSetif (rs != null) {try {rs.close();} catch (SQLException e) {e.printStackTrace();}}// 关闭PreparedStatementif (pstmt != null) {try {pstmt.close();} catch (SQLException e) {e.printStackTrace();}}// 关闭Connection(最重要,不关闭会导致数据库连接耗尽)if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}
}

三、核心 API 详解(掌握这些,JDBC 就会了)

1. DriverManager 类:驱动管理与连接获取

       DriverManager是 JDBC 的 “入口类”,主要负责加载驱动创建数据库连接

  • 加载驱动:通过Class.forName(驱动类全路径)触发驱动类的静态代码块,自动向DriverManager注册驱动(MySQL 5 必须显式执行,MySQL 8 可省略但建议保留)。
  • 获取连接static Connection getConnection(String url, String user, String password)是核心方法,3 个参数的含义:
    • url:数据库连接地址,格式随 MySQL 版本变化(见步骤 3)。
    • user:MySQL 用户名(如root)。
    • password:MySQL 密码(如root)。

2. Connection 接口:数据库连接的 “总开关”

       Connection代表与数据库的 “一次连接会话”,是 JDBC 中最重要的接口之一,核心功能包括:

  • 创建 SQL 执行器
    • createStatement():创建Statement对象(不推荐,有 SQL 注入风险)。
    • prepareStatement(String sql):创建PreparedStatement对象(推荐,支持预编译,防注入)。
  • 事务管理
    • setAutoCommit(boolean autoCommit):设置是否自动提交事务(默认true,即执行 SQL 后自动提交;手动事务需设为false)。
    • commit():提交事务(手动事务中,所有 SQL 执行成功后调用)。
    • rollback():回滚事务(手动事务中,SQL 执行失败时调用,恢复到事务开始前状态)。

3. PreparedStatement 接口:防注入的 “安全执行器”

       PreparedStatementStatement的子接口,核心优势是预编译 SQL,彻底解决 SQL 注入漏洞:

  • 预编译原理:创建PreparedStatement时,会将 SQL 语句(含?占位符)发送到 MySQL 服务器,服务器先对 SQL 进行 “语法解析和编译”,生成固定的执行计划;后续传入的参数(给?赋值)仅作为 “纯数据” 处理,不会被当作 SQL 语法解析,因此无法篡改 SQL 逻辑。
  • 核心方法
    • setXxx(int parameterIndex, Xxx value):给?赋值(Xxx是数据类型,如setStringsetIntparameterIndex?的索引,从 1 开始)。
    • executeQuery():执行查询 SQL,返回ResultSet(无参数,因 SQL 已预编译)。
    • executeUpdate():执行增删改 SQL,返回受影响行数(无参数)。

4. ResultSet 接口:查询结果的 “容器”

       ResultSet用于封装查询结果(类似 “内存中的表格”),核心特性和方法:

  • 游标机制:内部维护一个 “游标”,默认指向 “第一行数据之前”;调用next()方法可将游标向下移动一行,返回true表示游标指向有效数据,false表示已到结果集末尾。
  • 获取数据
    • 按字段名:getString(String columnLabel)getInt(String columnLabel)(如rs.getString("username")),优点是 “与 SQL 字段顺序无关”,代码更健壮。
    • 按索引:getString(int columnIndex)getInt(int columnIndex)(如rs.getInt(1)),优点是效率略高,但需与 SQL 字段顺序严格一致,维护成本高。
    • 通用方法:getObject(String columnLabel)getObject(int columnIndex),返回Object类型,需手动强转(适用于不确定字段类型的场景)。

四、实战优化:JDBC 工具类封装(双版本适配)

       实际开发中,“加载驱动、获取连接、释放资源” 是重复代码,封装成工具类可大幅减少冗余。以下是支持 MySQL 5/8 的通用工具类,通过配置文件实现 “参数可配置”。

1. 编写配置文件(db.properties)

       在项目src目录下创建db.properties文件,存储驱动类、URL、用户名、密码(根据 MySQL 版本修改对应值):

# MySQL 5配置(注释掉MySQL 8配置即可使用)
# driver=com.mysql.jdbc.Driver
# url=jdbc:mysql:///jdbcdemo# MySQL 8配置(注释掉MySQL 5配置即可使用)
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql:///jdbcdemo?serverTimezone=UTC&useSSL=false# 数据库账号密码(根据自己的MySQL修改)
username=root
password=root

2. 封装工具类(JDBCUtils.java)

       工具类采用 “静态代码块加载配置文件 + 静态方法提供连接 / 释放资源” 的设计,确保配置只加载一次,连接获取更高效:

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;public class JDBCUtils {// 静态变量存储配置信息(类加载时初始化,全局共享)private static String driver;private static String url;private static String username;private static String password;// 静态代码块:加载配置文件(类加载时执行一次,避免重复加载)static {try {// 1.创建Properties对象(用于读取key-value格式的配置文件)Properties props = new Properties();// 2.通过类加载器获取配置文件的输入流(src目录下的文件可直接通过类加载器读取)InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("db.properties");// 3.加载配置文件到Propertiesprops.load(is);// 4.读取配置信息并赋值给静态变量driver = props.getProperty("driver");url = props.getProperty("url");username = props.getProperty("username");password = props.getProperty("password");// 5.加载驱动(MySQL 5必须,MySQL 8可选但建议显式加载)Class.forName(driver);} catch (IOException | ClassNotFoundException e) {// 抛出运行时异常,终止程序(配置加载或驱动加载失败,程序无法继续)throw new RuntimeException("JDBC工具类初始化失败:" + e.getMessage(), e);}}/*** 获取数据库连接* @return Connection对象* @throws SQLException 连接获取失败时抛出*/public static Connection getConnection() throws SQLException {return DriverManager.getConnection(url, username, password);}/*** 释放资源(适用于查询操作:需关闭ResultSet、PreparedStatement、Connection)*/public static void close(ResultSet rs, PreparedStatement pstmt, Connection conn) {// 关闭ResultSetif (rs != null) {try {rs.close();} catch (SQLException e) {e.printStackTrace();}}// 关闭PreparedStatementif (pstmt != null) {try {pstmt.close();} catch (SQLException e) {e.printStackTrace();}}// 关闭Connectionif (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}/*** 释放资源(适用于增删改操作:无需关闭ResultSet)*/public static void close(PreparedStatement pstmt, Connection conn) {// 调用重载方法,减少代码冗余close(null, pstmt, conn);}
}

3. 工具类使用示例(查询 t_user 表)

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class JDBCUtilsDemo {public static void main(String[] args) {// 声明资源变量(作用域扩大到finally)Connection conn = null;PreparedStatement pstmt = null;ResultSet rs = null;try {// 1.通过工具类获取连接(无需关心驱动和URL细节)conn = JDBCUtils.getConnection();// 2.编写SQLString sql = "select id, username, email from t_user where password = ?";// 3.创建PreparedStatementpstmt = conn.prepareStatement(sql);// 4.给占位符赋值pstmt.setString(1, "123");// 5.执行查询rs = pstmt.executeQuery();// 6.处理结果System.out.println("密码为123的用户:");while (rs.next()) {System.out.printf("ID:%d,用户名:%s,邮箱:%s%n", rs.getInt("id"), rs.getString("username"), rs.getString("email"));}} catch (SQLException e) {e.printStackTrace();} finally {// 7.通过工具类释放资源(无需写重复的关闭逻辑)JDBCUtils.close(rs, pstmt, conn);}}
}

五、常见问题与解决方案(MySQL 8 重点)

1. MySQL 8 时区错误(最常见)

  • 错误信息The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone
  • 原因:MySQL 8 默认时区与 Java 虚拟机(JVM)时区不一致,且必须显式指定时区。
  • 解决方案:在 URL 中添加serverTimezone参数,可选值:
    • UTC:世界协调时间(通用,推荐)。
    • Asia/Shanghai:中国标准时间(与 UTC+8 一致,更符合国内场景)。
    • 示例:jdbc:mysql:///jdbcdemo?serverTimezone=Asia/Shanghai&useSSL=false

2. MySQL 8 SSL 连接警告

  • 警告信息Establishing SSL connection without server's identity verification is not recommended
  • 原因:MySQL 8 默认开启 SSL 加密连接,开发环境中若未配置 SSL 证书,会触发安全警告。
  • 解决方案:在 URL 中添加useSSL=false,禁用 SSL 连接(生产环境需配置 SSL 证书,开启useSSL=true)。

3. 驱动类路径错误(MySQL 5→8 迁移时)

  • 错误信息ClassNotFoundException: com.mysql.jdbc.Driver(使用 MySQL 8 时)。
  • 原因:MySQL 8 的驱动类路径已改为com.mysql.cj.jdbc.Driver,仍使用旧路径会导致类找不到。
  • 解决方案:修改配置文件中的driver值为com.mysql.cj.jdbc.Driver,并确保导入的是 MySQL 8 版本的驱动 Jar 包。

六、总结

       JDBC 是 Java 操作数据库的 “基础核心技术”,掌握它不仅能完成简单的数据库交互,更是学习 MyBatis、Spring JDBC 等框架的前提。核心要点总结:

  1. 版本适配:MySQL 5 与 8 的驱动类、URL 参数差异是关键,需重点区分。
  2. 核心流程:“加载驱动→获取连接→执行 SQL→处理结果→释放资源” 五步是不变的核心,其中 “释放资源” 和 “用 PreparedStatement 防注入” 是必须遵守的规范。
  3. 工具类封装:通过配置文件 + 工具类减少重复代码,是实际开发的必备技巧。
http://www.dtcms.com/a/614166.html

相关文章:

  • 公司网站改版设计汽车之家这样的网站怎么做
  • 【网络编程】TCP/IP网络概述
  • 网页和站点的区别上海网站高端
  • 【C++开发面经】全过程面试问题详解
  • 【前端学习】前端高频面试场景题
  • 解决在虚拟机的ensp中启动路由器,卡0%且出现虚拟机卡死的方法
  • 网站开发项目策划书手机前端开发软件工具
  • 宁波教师巧用3D技术,打造互动几何课堂:动态观察正方体组合,让空间想象触手可及
  • Amazon VPC中Web应用无法连接数据库的安全组配置问题分析与修复
  • C++ 模板进阶:解锁泛型编程的高级玩法
  • STM32F407 GPIO深度解析:从底层架构到实战应用
  • 网站开发读什么专业做百度推广一定要有自已网站
  • 家政服务网站建设方案电商网站开发需求文档
  • SVN服务器修改ip后无法连接
  • 如何申请一个免费的网站空间建网站的意义
  • 【LeetCode刷题】和为K的子数组
  • 网站建设教程免费下载电脑平面设计软件
  • BuildingAI 二开 平台配置菜单和页面功能PRD
  • OFDM、IQ调制与AxC技术介绍
  • Linux快速安装java运行环境
  • div嵌套影响网站收录wordpress后台模版
  • 【工具】BatteryInfoView
  • RGB 颜色值与十六进制颜色码相互转换工具
  • 芜湖市网站开发直播app开发一个需要多少钱
  • 数据类型与变量
  • 如何利用LangChain1.0快速进行天气查询
  • 百度网站公司信息推广怎么做做网站很累
  • 51的DSP来了, 100MHz, STC32G144K246
  • SQL索引失效场景全汇总
  • 启闭机闸门的网站建设上海网站建设 劲晟