JDBC: Java数据库连接的桥梁

什么是JDBC?

Java数据库连接(Java Database Connectivity,简称JDBC)是Java提供的一种API,允许Java应用程序与各种数据库进行交互。JDBC提供了一组标准的接口,开发者可以利用这些接口执行SQL语句、处理结果集以及管理数据库连接。通过JDBC,Java应用程序能够轻松地进行增删改查操作(CRUD),使得数据库操作变得简单而高效。

下载JDBC驱动

MySQL :: Download Connector/J

以MySQL为例

下载对应压缩包

找到合适的路径进行解压,解压后找到如下的 jar 包

IDEA引入驱动

1.新建一个项目,在项目下新建一个 lib 文件夹,将找到的 jar 包 复制进去

2.放进去jar包之后,右键lib,选择 add as library

3.找到下面的文件打开

4.复制内容,用于进行注册

java 复制代码
Class.forName("com.mysql.cj.jdbc.Driver");

下面先看一个例子

java 复制代码
package com.ffyc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class jdbctest {
    public static void main(String[] args) {


        final String USERNAME="root";
        final String PASSWORD = "123456";
        final String URL =
                "jdbc:mysql://localhost:3306/kingdom_db?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai";
        Connection conn = null;
        Statement statement = null;


        try {
            //注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //获取连接
            conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
            //创建statement对象
            statement = conn.createStatement();
            String sql = "INSERT INTO dept_tab   VALUES (6, '教学部', '102');";
            //执行sql语句
            statement.executeUpdate(sql);

            System.out.println("数据插入成功!");

        } catch (Exception e) {
            throw new RuntimeException(e);
        }finally {
            //关闭资源
            try {
                if (statement != null) statement.close();
                if (conn != null) conn.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
s

URL的构成部分

  1. jdbc:mysql:

    • jdbc是Java数据库连接的协议前缀,指明这是一个JDBC类型的连接。
    • mysql表示使用MySQL数据库。
  2. localhost:

    • localhost指的是数据库服务器的地址。在这里,它表示数据库安装在本地计算机上。如果您要连接远程数据库,可以替换为相应的IP地址或主机名。
  3. :3306:

    • 3306是MySQL默认的端口号。它告诉JDBC在这个端口与MySQL数据库进行连接。如果您的MySQL数据库使用了不同的端口,请相应地更改此值。
  4. /kingdom_db:

    • /kingdom_db是您要连接的数据库的名称。在这个例子中,试图连接名为kingdom_db的数据库。
  5. ?useSSL=true:

    • ?用于开始查询参数。这部分包含了一些用于配置连接行为的选项。
    • useSSL=true指示JDBC驱动程序在连接时使用SSL加密。这对于保护数据传输是一个安全措施。
  6. &useUnicode=true:

    • &用于分隔多个查询参数。
    • useUnicode=true表示使用Unicode字符编码,确保对于包含多语言字符的数据能够正确地处理和存储。
  7. &characterEncoding=utf-8:

    • characterEncoding=utf-8指定了字符编码为UTF-8。UTF-8是一种广泛使用的字符编码方式,它支持多种语言字符的表示。这样可以避免字符乱码问题。
  8. &serverTimezone=Asia/Shanghai:

    • serverTimezone=Asia/Shanghai设置了数据库服务器时区。此参数对于处理日期和时间数据是很重要的,确保在进行时区转换时能够准确。

只需要修改一下 2 3 4的写法,其他基本都是固定写法,用的时候上网搜一下即可,不需要记住 。

这个URL提供了与MySQL数据库连接所需的详细信息,包括服务器位置、端口号、数据库名称以及一系列连接参数。正确地配置这些参数有助于确保您的应用程序能够稳定、高效地与数据库交互,同时提高安全性和数据的一致性。

JDBC中的常用方法及解释

  1. 注册驱动Class.forName("com.mysql.cj.jdbc.Driver"); 这行代码用于加载MySQL的JDBC驱动,在使用JDBC时必须先注册相应的数据库驱动。

  2. 获取连接Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD); 通过DriverManager获取到数据库的连接,这样才能进行后续的SQL操作。

  3. 创建预编译语句PreparedStatement pst = conn.prepareStatement(sql); 预编译语句主要用于执行SQL语句,其具有参数占位符,使得插入的值更安全, 可防止SQL注入攻击。

  4. 执行更新或查询pst.executeUpdate();ResultSet rs = pst.executeQuery(); 这两个方法用于执行SQL语句,前者用于执行更新(如插入、删除、更新),后者用于查询并返回结果集。

  5. 关闭连接: 在操作完成后应及时关闭连接,以释放资源。

PreparedStatement vs. Statement

Statement
  • 使用Statement时,SQL语句及参数是拼接在一起的,这意味着开发者需要手动构建整个SQL字符串。
  • Statement在执行前不会进行预编译,因此每次执行SQL时都会重新解析并编译SQL语句,这会影响性能。

示例代码:

java 复制代码
String username = "user";
String password = "pass123";
String sql = "SELECT * FROM user_tab WHERE username = '" + username + "' AND user_password = '" + password + "'";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
PreparedStatement
  • PreparedStatement使用占位符(?)来表示参数,SQL语句是通过预编译的,这可以有效提升性能,减少数据库的负担。
  • PreparedStatement可以防止SQL注入,因为参数是在执行时传递给SQL的,JDBC会自动进行转义处理。

示例代码:

java 复制代码
String sql = "SELECT * FROM user_tab WHERE username = ? AND user_password = ?";
PreparedStatement pst = conn.prepareStatement(sql);
pst.setString(1, username); // 设置第一个参数
pst.setString(2, password);  // 设置第二个参数
ResultSet rs = pst.executeQuery();

SQL注入漏洞

SQL注入是一种常见的安全攻击手段,攻击者可以通过在输入字段中插入恶意SQL代码来操纵数据库。例如,在使用Statement的情况下,以下拼接 SQL 的方式就容易受到SQL注入攻击:

java 复制代码
String unsafeUsername = "' OR '1'='1"; // 攻击者输入的用户名
String sql = "SELECT * FROM user_tab WHERE username = '" + unsafeUsername + "'";
ResultSet rs = stmt.executeQuery(sql);

在这个例子中,如果unsafeUsername被设置为' OR '1'='1,那么SQL语句实际上变成了:

java 复制代码
SELECT * FROM user_tab WHERE username = '' OR '1'='1'

这个查询会返回user_tab表中的所有用户,因为OR '1'='1'始终为真。

相比之下,使用PreparedStatement可以有效防止这样的攻击。例如:

java 复制代码
String sql = "SELECT * FROM user_tab WHERE username = ? AND user_password = ?";
PreparedStatement pst = conn.prepareStatement(sql);
pst.setString(1, unsafeUsername); // 输入的用户名
pst.setString(2, password);
ResultSet rs = pst.executeQuery();

在这种情况下,unsafeUsername的值不会被直接当作SQL代码执行,而是只作为参数处理。因此,即使攻击者输入了恶意的SQL片段,也不会改变原有SQL的结构,防止了SQL注入的发生。

这就是为什么要用PreparedStatement而不用Statement

简单封装

由于每次连接数据库都有一些重复的代码要写,所以我们对它进行简单的封装,下面的例子展示了如何封装JDBC操作,以便于日后的使用:

JdbcUtil 类

java 复制代码
package com.util;

import java.sql.*;

/**
 * static
 */
public class JdbcUtil {
    static final String USERNAME = "root";
    static final String PASSWORD = "123456";
    static final String URL =
            "jdbc:mysql://localhost:3306/kingdom_db?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai";
    static Connection conn;
    static PreparedStatement pst;
    static ResultSet rs;

    static{
       registry();
    }

    /**
     * 注册驱动
     */
    private static void registry(){
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public   static void connect(){
        try {
            conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    /**
    * 预编译sql语句
    */
    public static void prepareStatement(String sql,Object ... vals){
        try {
            pst = conn.prepareStatement(sql);
            for(int i=0;i<vals.length;i++){
                pst.setObject(i+1, vals[i]);
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 增删改sql语句
     */
    public static void executeUpdate(){
        try {
            pst.executeUpdate();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 查询sql语句
     */
    public static ResultSet executeQuery(){
        try {
            rs = pst.executeQuery();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return rs;
    }
    public static void close(){
        try {
            if(rs!=null) rs.close();
            if(pst!=null) pst.close();
            if(conn!=null) conn.close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

DeptDemo类

java 复制代码
package com.ffyc;

import com.util.JdbcUtil;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;

public class DeptDemo {
    public static void main(String[] args) throws SQLException {
        JdbcUtil.connect();
        String sql = null;
        ResultSet rs= null;
        Scanner sc = new Scanner(System.in);
        System.out.println("1. 添加部门信息\t2.查询所有部门信息");
        System.out.println("3. 根据部门名称查询");

        System.out.print("请选择: ");
        String choice = sc.nextLine();

        switch (choice) {
            case "1":
                System.out.print("请输入部门名称: ");
                String name = sc.nextLine();
                System.out.print("请输入部门位置: ");
                String loc = sc.nextLine();

                sql = "INSERT INTO dept_tab(dept_name, dept_loc) VALUES(?,?)";
                JdbcUtil.prepareStatement(sql, name,loc);
                JdbcUtil.executeUpdate();
                System.out.println("添加成功");

                break;
            case "2":
                sql = "SELECT * FROM dept_tab";
                JdbcUtil.prepareStatement(sql );
                 rs = JdbcUtil.executeQuery();
                while(rs.next()){
                    System.out.print(rs.getObject("dept_id"));
                    System.out.print("-"+rs.getObject("dept_name"));
                    System.out.print("-"+rs.getObject("dept_loc"));
                    System.out.println();
                }
                break;
            case "3":
                System.out.print("请输入部门的名称: ");
                String nName= sc.nextLine();
                sql = "SELECT * FROM dept_tab WHERE dept_name LIKE ?";
                JdbcUtil.prepareStatement(sql,"%"+nName+"%");
               rs = JdbcUtil.executeQuery();
                while(rs.next()){
                    System.out.print(rs.getObject("dept_id"));
                    System.out.print("-"+rs.getObject("dept_name"));
                    System.out.print("-"+rs.getObject("dept_loc"));
                    System.out.println();
                }
                break;
            default:
                System.out.println("输入不合法..");
        }

        JdbcUtil.close();

    }
}

代码解释

以上面这个例子。我对必要的地方做出解释说明

1.数据库连接

java 复制代码
String sql = "INSERT INTO dept_tab(dept_name, dept_loc) VALUES(?,?)";
JdbcUtil.prepareStatement(sql, name, loc);
JdbcUtil.executeUpdate();
java 复制代码
JdbcUtil.connect();

通过 JdbcUtil 类的 connect 方法连接到数据库。

2.用户交互

java 复制代码
Scanner sc = new Scanner(System.in);
System.out.println("1. 添加部门信息\t2.查询所有部门信息");
System.out.println("3. 根据部门名称查询");

使用 Scanner 类从控制台获取用户输入,提示用户选择要执行的操作。

3.添加部门信息

java 复制代码
String sql = "INSERT INTO dept_tab(dept_name, dept_loc) VALUES(?,?)";
JdbcUtil.prepareStatement(sql, name, loc);
JdbcUtil.executeUpdate();

重点是要对JdbcUtil这个封装类的方法理解,这是我们自定以的封装类

JDBC的优缺点

优点

  1. 平台独立性:作为 Java 的一部分,JDBC 具有平台无关性,可以在任何支持 Java 的环境中运行。
  2. 标准化接口:JDBC 提供了统一的 API,使得不同数据库之间的操作变得一致。
  3. 灵活性:支持多种数据库,如 MySQL、Oracle、PostgreSQL 等,只需更换驱动程序即可。

缺点

  1. 性能开销:传统的 JDBC 连接可能存在性能问题,尤其是在大量数据操作时。
  2. 代码复杂性:直接使用 JDBC 需要编写较多的样板代码,增加了开发的复杂性。
  3. 异常处理:JDBC 的异常处理相对复杂,开发者需要处理多种异常类型。

总结

JDBC 是 Java 开发中必不可少的组成部分,它为开发者提供了一种灵活、标准化的方法与数据库交互。尽管存在一些缺点,但通过合理的设计和封装,可以最大限度地发挥 JDBC 的优势。作为 Java 开发者,理解 JDBC 的工作原理及操作方式,将对提升数据库管理能力大有裨益。

相关推荐
loyd310 分钟前
【数据分析】5 设计不同业务分析框架
java·网络·数据分析
m0_7482451716 分钟前
Spring Boot项目开发常见问题及解决方案(上)
java·spring boot·后端
今天的接口写完了吗?17 分钟前
Spring Boot操作MaxComputer(保姆级教程)
java·spring boot·后端
鑫仔的记忆17 分钟前
【Oracle】视图用法和示例
数据库·oracle
金州小铁匠30 分钟前
基于EasyExcel封装的Excel工具类,支持高效导出和读取操作
java·spring·excel
IIIIIIlllii33 分钟前
java练习(43)
java·开发语言
xxxxxmy1 小时前
Spring MVC 程序开发(1)
java·spring·mvc
不平衡的叉叉树1 小时前
使用优化版的编辑距离算法替代ES默认的评分算法
java·算法
没什么技术1 小时前
Spock框架:让单元测试更优雅的高效武器
java·spock
码代码的小仙女1 小时前
学习笔记-07生产者-消费者模型4种实现方式
java·学习