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

JDBC 入门:从基础到实战

一、JDBC 概述

JDBC,即 Java DataBase Connectivity,是 Java 用于连接数据库的技术,旨在通过 Java 代码操作数据库。它是一套接口规范,其实现类由各数据库生产商提供。掌握 JDBC 接口和方法,就能操作不同数据库。而驱动则是数据传输的桥梁,使用 MySQL 数据库需导入 mysql - connector - java - 5.1.13 - bin.jar 等相应驱动 jar 包。

二、JDBC 快速入门步骤

  1. 创建数据库和表结构:以创建 jdbcdemo 数据库及 t_user 表为例,插入一些测试数据。
CREATE DATABASE jdbcdemo;
USE jdbcdemo;
CREATE TABLE t_user (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(30),
    password VARCHAR(30),
    email VARCHAR(30)
);
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. 加载驱动:使用 DriverManager 类加载驱动,推荐 Class.forName("com.mysql.jdbc.Driver"); 方式,相比 DriverManager.registerDriver(new Driver()),此方式避免过度依赖特定实现类,也不会使驱动 jar 包加载两次。

  1. 获取连接:通过 DriverManager.getConnection(String url, String user, String password) 方法获取连接。url 格式如 jdbc:mysql://localhost:3306/day07,其中 jdbc 是主协议,mysql 是子协议,localhost 是主机,3306 是默认端口号,day07 是数据库名。若访问本地数据库,localhost:3306 可省略,即 jdbc:mysql:///day07。另外两个参数分别是用户名和密码。
 Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
 // 获取到连接,localhost:3306可以省略不写的,访问本地mysql服务器

  1. 执行 SQL 语句
    • 编写 SQL 语句:根据需求编写查询、插入、更新或删除等 SQL 语句。
    • 获取执行 SQL 语句的对象:通过 Connection 对象获取 Statement 接口对象,如 Statement createStatement()。若要防止 SQL 注入漏洞,可使用 PreparedStatement prepareStatement(String sql) 获取 PreparedStatement 对象。
    • 执行查询语句:若执行查询,使用 Statement 的 executeQuery(String sql) 方法,结果封装在 ResultSet 接口中。
    • 执行增删改语句:使用 Statement 的 executeUpdate(String sql) 方法执行增删改操作。
// 执行SQL语句
            // 编写SQL语句
            String sql = "select * from t_user";
            // 有能执行SQL语句的对象 Statement对象
            stmt = conn.createStatement();//不能防止sql注入
            //conn.prepareStatement()//可以防止sql注入问题
  1. 处理结果集(针对查询)ResultSet 代表结果集,以表格形式封装数据,内部有游标,默认指向第一行数据之前。通过调用 next() 方法向下移动游标,根据字段类型调用不同方法获取值,如 getInt()getString() 等,也可使用 getObject() 并自行强转。获取数据方法可通过下标(从 1 开始)或字段名称取值,后者更常用。
 rs = stmt.executeQuery(sql);
            // 遍历rs结果集
            while(rs.next()){
                // 获取到数据就OK
                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);
  1. 释放资源:连接等对象使用完后必须释放,通常在 finally 代码块中进行,确保一定会执行。以释放 Connection 为例:
if (conn!= null) {
    try {
        conn.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    conn = null;
}

三、JDBC 相关接口和 API

  1. DriverManager 类:管理 JDBC 驱动的实现类,作用是加载驱动和获取连接。
  2. Connection 接口:代表数据库连接,很重要且资源稀有,用完需释放。可获取执行 SQL 语句的对象(Statement 或 PreparedStatement),还能管理事务(如 setAutoCommit(boolean autoCommit) 开启事务、commit() 提交事务、rollback() 回滚事务)。
  3. Statement 接口:能执行 SQL 语句,包括查询(executeQuery(String sql))和增删改(executeUpdate(String sql)),还支持批处理(addBatch(String sql) 添加 SQL 语句到批处理、clearBatch() 清除批处理、executeBatch() 执行批处理)。
  4. PreparedStatement 接口Statement 的子接口,能执行 SQL 语句,有预编译功能,可解决 SQL 注入漏洞。通过 Connection 的 prepareStatement(String sql) 方法获取,使用 setXxxx() 系列方法向占位符 ? 传入值,再执行相应的 executeQuery() 或 executeUpdate() 方法。

四、SQL 注入漏洞及解决

  1. 漏洞产生:在拼接 SQL 语句时,若用户输入特殊字符,可能改变 SQL 语句逻辑。例如,当用户名输入 aaa'or'1=1,密码任意时,原本的查询语句 select * from t_user where username = '"+username+"' and password = '"+password+"' 会变为 select * from t_user where username = 'aaa'or'1=1' and password ='sfsdfsds,使查询条件恒成立,导致非法登录。
  2. 解决方法:使用 PreparedStatement 接口,将 SQL 语句中的参数部分用 ? 占位符代替,先将 SQL 语句发送到 MySQL 服务器编译,之后传入的值都作为 ? 的参数处理,从而避免 SQL 注入。

五、JDBC 工具类编写及控制台登陆案例

  1. 编写配置文件:在 src 目录创建 db.properties 文件,以 key = value 形式配置数据库相关信息。
driverclass=com.mysql.jdbc.Driver
url=jdbc:mysql:///jdbcdemo
username=root
password=root
  1. 封装工具类:将 JDBC 常用操作封装成工具类,方便复用。在控制台登陆案例中,结合工具类和 PreparedStatement 可有效防止 SQL 注入,实现安全的用户登陆验证。
package cn.qcby.utils;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

/**
 * JDBC的工具类 1.0版本
 * JDBC的工具类 2.0版本(智能一些),编写properties属性文件,程序就可以读取属性文件
 *      1. 驱动类
 *      2. 数据库地址
 *      3. 用户名
 *      4. 密码
 */
public class JdbcUtils {

    private static final String driverclass;
    private static final String url;
    private static final String username;
    private static final String password;

    static{
        // 加载属性文件
        Properties pro = new Properties(); //创建Properties对象
        //通过反射获取文件里的数据并转成流的方式输出
        InputStream inputStream = JdbcUtils.class.getResourceAsStream("/db.properties");
        //调用Properties中的load方法进行加载
        try {
            // 加载属性文件
            pro.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 给常量赋值
        driverclass = pro.getProperty("driverclass");
        url = pro.getProperty("url");
        username = pro.getProperty("username");
        password = pro.getProperty("password");
    }

    /**
     * 加载驱动
     */
    public static void loadDriver(){
        try {
            // 通过反射加载驱动类
            Class.forName(driverclass);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 加载完驱动,获取到连接,返回连接对象
     * @return
     */
    public static Connection getConnection(){
        // 加载驱动
        loadDriver();
        // 获取到连接对象,返回
        Connection conn = null;
        try {
            // 获取到连接
            conn = DriverManager.getConnection(url,username,password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

    /**
     * 关闭资源
     * @param conn
     * @param stmt
     * @param rs
     */
//两种对close方法的重载,一种是有结果集的,也就是查询走的关闭资源路径,一种是没有结果集走的关闭资源
    public static void close(Connection conn, Statement stmt, ResultSet rs){
        if(rs != null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(stmt != null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 关闭资源
     * @param conn
     * @param stmt
     */
    public static void close(Connection conn, Statement stmt){
        if(stmt != null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }



}


http://www.kler.cn/a/552522.html

相关文章:

  • 大数据SQL调优专题——Flink执行原理
  • 安装海康威视相机SDK后,catkin_make其他项目时,出现“libusb_set_option”错误的解决方法
  • DeepSeek R1生成图片总结2(虽然本身是不能直接生成图片,但是可以想办法利用别的工具一起实现)
  • word$deepseep
  • 用deepseek学大模型03-数学基础 概率论 最大似然估计(MLE)最大后验估计(MAP)
  • DeepSeek告别服务器繁忙
  • 应急响应(linux 篇,以centos 7为例)
  • Linux、Docker、Redis常见面试题
  • MybatisMybatisPllus公共字段填充与配置逻辑删除
  • LLaMa-Factory部署及llamafactory-cli webui命令无法打开ui界面问题解决记录
  • 【触想智能】工业显示器和普通显示器的区别以及工业显示器的主要应用领域分析
  • Leetcode2080:区间内查询数字的频率
  • SpringCloud面试题----为什么会产生Eureka的自我保护, 如何关闭自我保护机制
  • docker 安装的open-webui链接ollama出现网络错误
  • 阿里云大文件ossutil工具进行上传下载,该工具支持断点续传
  • mysql开启gtid并配置主从
  • eNSP防火墙综合实验
  • AI与大数据:双剑合璧的智能革命
  • 什么是UV环形光源
  • Flutter 状态管理:详细分析与实战