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.复制内容,用于进行注册

Class.forName("com.mysql.cj.jdbc.Driver");

下面先看一个例子 

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语句,这会影响性能。

示例代码:

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会自动进行转义处理。

 示例代码:

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注入攻击:

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

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

SELECT * FROM user_tab WHERE username = '' OR '1'='1'

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

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

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 类

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类 

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.数据库连接

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

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

2.用户交互

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

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

3.添加部门信息

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 的工作原理及操作方式,将对提升数据库管理能力大有裨益。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/902238.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

「C/C++」C++ STL容器库 之 std::multiset 键的集合容器

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「C/C」C/C程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasoli…

腾讯云跨AZ部署FortigateHA备忘录

随时保存配置 config system globalset admintimeout 480set alias "FortiGate-VM64-KVM"set gui-auto-upgrade-setup-warning disableset hostname "FG-Slave"set revision-backup-on-logout enableset revision-image-auto-backup enableset timezone &…

【 thinkphp8 】00006 启动 内、外置服务器

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【 t…

Java学习Day53:铲除紫云山金丹原料厂厂长(手机快速登录、权限控制)

1.手机快速登录 手机快速登录功能&#xff0c;就是通过短信验证码的方式进行登录。这种方式相对于用户名密码登录方式&#xff0c;用户不需要记忆自己的密码&#xff0c;只需要通过输入手机号并获取验证码就可以完成登录&#xff0c;是目前比较流行的登录方式。 前端页面&…

centos7.x安装openCV 4.6.0版本

## 从源代码编译安装 1.更新系统 sudo yum update -y 2.安装依赖项 sudo yum groupinstall "Development Tools" sudo yum install cmake gcc-c git libjpeg-turbo-devel libpng-devel libtiff-devel libwebp-devel openexr-devel gstreamer1-plugins-base-devel…

iTerm2 保持SSH远程连接

1、保持SSH远程连接的稳定&#xff0c;防止因闲置时间过长而断开连接 When idle, send ASCII code 35 every 60 seconds每60秒 输入# 2、客户端设置保持活动 设置客户端每隔60秒发送一次保活信号&#xff0c;总共尝试3次。 vim ~/.ssh/configHost *ServerAliveInterval 60…

uniapp 底部导航栏tabBar设置后不显示的问题——已解决

uniapp 底部导航栏tabBar设置后不显示的问题——已解决 网上找了一堆解决办法&#xff0c;挨个对着试吧 解决办法一&#xff1a;tabBar里的list第一项和page中的第一项要相同&#xff0c;确实就能显示了。但是问题来了&#xff0c;page中的第一项是入口页&#xff0c;那就意味…

鲸鱼优化算法(Whale Optimization Algorithm, WOA)原理与MATLAB例程

鲸鱼优化算法&#xff08;Whale Optimization Algorithm, WOA&#xff09;是一种基于鲸鱼捕食行为的智能优化算法。它模拟了座头鲸在狩猎时的“气泡网”捕食策略。 文章目录 1.适应度函数2. 更新公式2.1 突袭行为2.2 螺旋更新3.线性递减参数4. 边界处理 MATLAB 实现示例代码说明…

HarmonyOS 5.0应用开发——Navigation实现页面路由

【高心星出品】 文章目录 Navigation实现页面路由完整的Navigation入口页面子页面 页面跳转路由拦截其他的 Navigation实现页面路由 Navigation&#xff1a;路由导航的根视图容器&#xff0c;一般作为页面&#xff08;Entry&#xff09;的根容器去使用&#xff0c;包括单页面&…

前端构建工具vite的优势

1. 极速冷启动 Vite 使用原生 ES 模块 (ESM) 在开发环境下进行工作。相比于传统构建工具需要打包所有的文件&#xff0c;Vite 只在浏览器请求模块时动态加载所需的文件。无打包冷启动&#xff1a;无需预先打包&#xff0c;项目启动非常快&#xff0c;尤其对于大型项目效果更明…

Arduino Uno 同时控制多路舵机

Arduino Uno同时控制4个舵机 舵机可以在0~180度内指定角度的控制。常用于航模、机器人、遥控玩具等物品,然而,很多时候要一次性控制多个舵机,今天以控制4个舵机为例进行说明 接线方式如下图: 舵机的信号线分别接A0,A1,A2,A3。控制舵机从0旋转到180度,再由180度旋转到0度,…

基于NERF技术重建学习笔记

NeRF&#xff08;Neural Radiance Fields&#xff09;是一种用于3D场景重建的神经网络模型&#xff0c;能够从2D图像生成逼真的3D渲染效果。它将场景表征为一个连续的5D函数&#xff0c;利用了体积渲染和神经网络的结合&#xff0c;通过学习光线穿过空间时的颜色和密度来重建场…

机器视觉-相机、镜头、光源(总结)

目录 1、机器视觉光源概述 2、光源的作用 3、光谱 4、工业场景常见光源 4.1、白炽灯 4.2、卤素灯 4.3、 荧光灯 4.4、LED灯 4.5、激光灯 5、光源的基本性能 5.1、光通量 5.2、光效率 5.3、发光强度 5.4、光照度 5.5、均匀性 5.6、色温 5.7、显色性 6、基本光学…

openpnp - 解决“底部相机高级校正成功后, 开机归零时,吸嘴自动校验失败的问题“

文章目录 openpnp - 解决"底部相机高级校正成功后, 开机归零时&#xff0c;吸嘴自动校验失败的问题"概述笔记问题现象1问题现象2原因分析现在底部相机和吸嘴的位置偏差记录修正底部相机位置现在再看看NT1在底部相机中的位置开机归零&#xff0c;看看是否能通过所有校…

python csv库

python csv库 水一水又是一篇&#xff0c;乐 读取 import csv # 打开 CSV 文件 with open(example.csv, moder, newline) as file: csv_reader csv.reader(file) # 读取文件头&#xff08;可选&#xff09; headers next(csv_reader) print(f"Headers: {heade…

golang将指针传给cgo后还能被回收吗?

问题&#xff1a; 如果把golang分配的变量&#xff0c;其指针通过cgo传给c&#xff0c;并被c存储&#xff0c;那这个变量还能被gc回收吗&#xff1f; 实验代码&#xff1a; test_memory_leak.go package main/* #include <stdlib.h> #include <string.h> #incl…

基于docker-compose编排部署微服务快速开发框架

1. 规划节点 节点规划&#xff0c;见表1。 表1 节点规划 IP主机名节点10.24.2.10masterdocker-compose节点 2. 基础准备 Docker和Docker Compose已安装完成&#xff0c;将提供的软件包Pig.tar.gz上传至master节点/root目录下并解压。 案例实施 1. 基础环境准备 &#x…

渗透测试-百日筑基—SQL注入篇时间注入绕过HTTP数据编码绕过—下

day8-渗透测试sql注入篇&时间注入&绕过&HTTP数据编码绕过 一、时间注入 SQL注入时间注入&#xff08;也称为延时注入&#xff09;是SQL注入攻击的一种特殊形式&#xff0c;它属于盲注&#xff08;Blind SQL Injection&#xff09;的一种。在盲注中&#xff0c;攻击…

模型评估:Accuracy、Precision、Recall、F1、ROC曲线、AUC、PR曲线

Accuracy & Precision & Recall & F1 准确率 Accuracy A c c u r a c y T T T F A L L Accuracy \frac{TT TF}{ALL} AccuracyALLTTTF​ 1.分类器到底分对了多少&#xff1f; 精确率 Precision 2.返回的图片中正确的有多少&#xff1f; 召回率 / 查全率 …

了解光耦合器输入输出关系---腾恩科技

光耦合器&#xff0c;也称为光隔离器&#xff0c;是电子电路中必不可少的元件&#xff0c;主要用于在隔离部分之间传输信号&#xff0c;同时防止电噪声或高压影响敏感元件。其独特的设计使它们能够在没有直接电接触的情况下&#xff0c;弥合不同电压域之间的差距。在本文中&…