Java数据库连接——JDBC

news2024/9/23 5:55:52

目录

1、JDBC简介

2、JDBC应用

2.1 建立数据库连接

2.1.1 DriverManager静态方法获取连接

2.1.2 DataSource对象获取

2.2 获取SQL执行对象

2.2.1 SQL注入

2.2.2 Statement(执行静态SQL)

2.2.3 PreparedStatement(预处理的SQL执行对象)

2.3 执行SQL并返回结果

2.4 关闭连接,释放资源

3、示例


1、JDBC简介

JDBC(Java Data Base Connectivity,Java数据库连接)是Java程序和数据库之间的桥梁,包含 了⼀套Java定义的用于执行SQL语句的接口,使开发者能够编写数据库的程序。JDBC 的主要作用是: 与数据库建立连接、发送SQL语句和处理数据库执行结果。

正常来说,访问数据库需要经过以下几个重要步骤:

  1. 确定数据库服务器的地址,端口号(数据源)
  2. 建立连接,用户名、密码(不同的数据库以哪种协议建立连接)
  3. 发生要执行的SQL(以什么样的形式发送——需要考虑编码的格式(协议))
  4. 接收返回的结果(结果集(select)、受影响的行数(insert、...))(需要考虑一哪种协议解析结果)
  5. 关闭连接(释放资源,关闭连接)

JDBC是Java平台提供的接口,其中具体的实现是由不同的数据库厂商来完成的,数据库厂商实现完后将其封装在不同的方法中,Java开发者可以使用这些封装好的方法,操作数据库。

JDBC工作原理简洁地概括为:

  1. 加载驱动
  2. 建立连接
  3. 创建Statement(获取SQL执行对象)
  4. 执行SQL并返回结果
  5. 处理结果,关闭资源

2、JDBC应用

2.1 建立数据库连接

2.1.1 DriverManager静态方法获取连接

获取数据库连接的第一种方式:以驱动管理类DriverManager获取连接。

注意:该方式获取的是物理连接,即每次运行时都会重新打开一个客户端工具(随用随开)。

举个例子:比如公司中有了一个新业务,老板为完成这个业务招了十个员工,业务完成后立刻把他们炒了。过了一段时间,公司又有了一个新业务,老板又重新招人,完成业务又把他们开了。(随用随招)

因此,该方法效率低下,不推荐。

 //1. 加载数据库厂商提供的驱动
 //通过完全限定名记载指定的类到JVM
 Class.forName("com.mysql.cj.jdbc.Driver");
 //2. 获取数据库连接(物理连接)
 connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test2?characterEncoding=utf8&" +
                    "allowPublicKeyRetrieval=true&useSSL=false", "root", "111111");

2.1.2 DataSource对象获取

通过数据源DataSource对象获取,一个连接可以执行很多SQL,直到关闭数据源。

这种方式是通过一个连接池去管理很多个连接,当需要SQL执行时,就从连接池里拿出一个连接,用完后返还给连接池。

推荐在实际开发中使用这种方式。

        //1. 定义MySQL数据源对象(连接池)
        MysqlDataSource mysqlDataSource = new MysqlDataSource();
        //2. 设置数据库连接串
        mysqlDataSource.setURL("jdbc:mysql://127.0.0.1:3306/test2?characterEncoding=utf8" +
                "&allowPublicKeyRetrieval=true&useSSL=false");
        //用户
        mysqlDataSource.setUser("root");
        //密码
        mysqlDataSource.setPassword("111111");

        //定义JDBC的数据源对象
        DataSource dataSource = mysqlDataSource;

        //1. 通过数据源获得数据库连接对象
        connection = dataSource.getConnection();

2.2 获取SQL执行对象

2.2.1 SQL注入

SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应 用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。

2.2.2 Statement(执行静态SQL)

Statement是用于执行静态SQL语句并返回执行结果的对象

注意:该方式存在SQL注入的安全问题!!!

如下图:该方式是通过字符串拼接的方式组装完成的SQL语句,字符串拼接形式构造SQL语句时,如果不处理参数中的特殊字符就会造成SQL注入,这是⼀个非常严重的安全性问题。

//定义Statement 
Statement statement = null;
//3. 创建Statement对象
statement = connection.createStatement();
//4. 定义SQL并执行SQL语句
Scanner scanner = new Scanner(System.in);
System.out.println("请输入要查询的学生的姓名:");
//接收用户输入
String name = scanner.next();
String sql = "select student_id, sn, name, mail, class_id from student where name = '" + name + "'";
//5. 执行SQL并获取查询结果
resultSet = statement.executeQuery(sql);

2.2.3 PreparedStatement(预处理的SQL执行对象)

预编译SQL语句对象,SQL语句被预编译并存储在PreparedStatement对象中,可以使用该对象多次执行SQL语句,同时可以解决SQL注入问题。

动态参数用占位符 ? 表示。

简单以上文SQL注入的输入为例,该方式直接将用户输入的内容全部当做name的值(利用占位符),直接在数据表中通过输入值来查找相应记录。

注意:使用真实值替换占位符时,使用setString/setLong/....方法,编号从1开始,有多少个参数就设置多少个值。

            //定义要执行的SQL
            String sql = "select student_id, sn, name, mail, class_id from student where name = ?";
            Scanner scanner = new Scanner(System.in);
            //2. 获取预处理SQL执行对象
            statement = connection.prepareStatement(sql);
            //接收用户输入
            System.out.println("请输入要查询的学生的姓名:");
            String name = scanner.next();
            //3. 用真实值替换占位符
            statement.setString(1, name);

2.3 执行SQL并返回结果

执行select语句,返回结果集(ResultSet结果集接收):

//定义结果集对象
ResultSet resultSet = null; 
//4. 执行SQL,获取结果集对象
resultSet = statement.executeQuery();
//迭代打印结果集
//最初游标位于第⼀⾏之前,调⽤next⽅法将游标移动到下⼀⾏,
//当ResultSet中没有更多的数据⾏时返回false
while (resultSet.next()) {
    long stuId = resultSet.getLong(1);
    String stuSn = resultSet.getString(2);
    String stuName = resultSet.getString(3);
    String stuMail = resultSet.getString(4);
    long stuClassId = resultSet.getLong(5);
    System.out.println(MessageFormat.format("学生编号={0}, 学号={1}, 姓名={2}, 邮箱={3}, 班级编号={4}",
            stuId, stuSn, stuName, stuMail, stuClassId));
}

执行update、delete、insert操作,返回所影响的行数:

int row = statement.executeUpdate();

2.4 关闭连接,释放资源

自下而上,依次关闭。

// 依次释放资源,关闭连接
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }

3、示例

封装数据库连接、资源关闭方法:

package org.example.utils;

import com.mysql.cj.jdbc.MysqlDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * Created with IntelliJ IDEA.
 * Description:封装方法
 * User: dings
 * Date: 2024-09-21
 * Time: 14:53
 */
public class DBUtils {
    private static DataSource dataSource = null;
    private static MysqlDataSource mysqlDataSource = new MysqlDataSource();
    private static String URL = "jdbc:mysql://127.0.0.1:3306/test2?characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false";
    private static String USER = "root";
    private static String PASSWORD = "111111";


    private DBUtils() {}//构造方法私有化

    static {
        mysqlDataSource.setURL(URL);
        mysqlDataSource.setUser(USER);
        mysqlDataSource.setPassword(PASSWORD);
        dataSource = mysqlDataSource;
    }
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }
    public static void close(ResultSet resultSet, Statement statement, Connection connection) {
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

实现记录的插入:

package org.example;

import org.example.utils.DBUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner;

/**
 * Created with IntelliJ IDEA.
 * Description:向表中插入记录
 * User: dings
 * Date: 2024-09-21
 * Time: 15:06
 */
public class Demo03_insert {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            connection = DBUtils.getConnection();
            String sql = "insert into student (sn, name, mail, class_id) values (?,?,?,?)";
            statement = connection.prepareStatement(sql);
            Scanner scanner = new Scanner(System.in);

            System.out.println("请输入学号:");
            String sn = scanner.next();

            System.out.println("请输入姓名:");
            String name = scanner.next();

            System.out.println("请输入邮箱:");
            String mail = scanner.next();

            System.out.println("请输入班级编号:");
            Long classId = Long.valueOf(scanner.next());

            //编号从1开始
            statement.setString(1, sn);
            statement.setString(2, name);
            statement.setString(3, mail);
            statement.setLong(4, classId);

            int row = statement.executeUpdate();
            if(row == 1) {
                System.out.println("插入成功!");
            }else {
                System.out.println("插入失败!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            // 释放资源,关闭连接
            DBUtils.close(null, statement, connection);
        }
    }
}

END

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Error when custom data is added to Azure OpenAI Service Deployment

题意:在向 Azure OpenAI 服务部署添加自定义数据时出现错误。 问题背景: I receive the following error when adding my custom data which is a .txt file (it doesnt matter whether I add it via Azure Cognitive Search, Azure Blob Storage, or F…

证书学习(五)Java实现RSA、SM2证书颁发

目录 一、知识回顾1.1 X.509 证书1.2 X509Certificate 类二、代码实现2.1 Maven 依赖2.2 RSA 证书颁发1)PfxGenerateUtil 证书文件生成工具类2)CertDTO 证书中间类3)RSACertGenerateTest RSA证书生成测试类4)执行结果2.3 SM2 证书颁发1)SM2Utils 国密SM2算法工具类2)SM2C…

查询一条 SQL 语句的流程

查询一条sql语句的流程 连接器:建立连接,管理连接、校验用户身份查询缓存:查询语句如果命中查询缓存则直接返回,否则继续往下执行(MSQL8.0 已删除)解析 SQL:通过解析器对 SQL 查询语句进行词法分析、语法分析&#xf…

【RH124】解释Linux文件系统权限

RH124教材中控制对文件的访问一章中有一道解释Linux文件系统权限的测验题,可以一起来看看: 一、权限解释 这是通过 ls -l 命令查看的结果。它显示了文件或目录的权限、拥有者、所属组等信息。 1、长列表的第一个字符表示文件类型: -是常…

(done) 声音信号处理基础知识(6) (How to Extract Audio Features)

参考:https://www.youtube.com/watch?v8A-W1xk7qs8&t2s 先复习之前分类的声学特征 时域特征流水线 如下是 441Khz 下一个采样点播放的时间。这比人类耳朵分辨率(10ms)还低。 所以,把多个采样点组合成一个 frame 的原因有,这是一个人…

计算机的错误计算(一百零一)

摘要 展示 在0附近数的函数值的计算精度问题。 计算机的错误计算(一百)探讨了 在一般情形下的计算精度问题。本节讨论其在0附近的数的函数值的计算精度问题。 例1. 已知 计算 不妨在Python 3.12.5下计算,则有 若在线运行R代码&#x…

阿⾥编码规范⾥⾯Manager分层介绍-专⽤名词和POJO实体类约定

开发⼈员:张三、李四、王五 ⼀定要避免单点故障 ⼀个微服务起码两个⼈熟悉:⼀个是主程⼀个是技术leader 推荐是团队⾥⾯两个开发⼈员 N⽅库说明 ⼀⽅库: 本⼯程内部⼦项⽬模块依赖的库(jar 包)⼆⽅库: 公司内部发布到中央仓库,可供公司…

车辆重识别(CVPR2016图像识别的深度残差学习ResNet)论文阅读2024/9/21

[2] Deep Residual Learning for Image Recognition ( CVPR 2016) 作者:Kaiming He Xiangyu Zhang Shaoqing Ren Jian Sun 单位:微软研究院 摘要: 更深层的神经网络更难训练。我们提出了一个残差学习框架,以减轻对比先前使用的深…

鸿蒙OpenHarmony【轻量系统内核扩展组件(动态加载)】子系统开发

基本概念 在硬件资源有限的小设备中,需要通过算法的动态部署能力来解决无法同时部署多种算法的问题。以开发者易用为主要考虑因素,同时考虑到多平台的通用性,LiteOS-M选择业界标准的ELF加载方案,方便拓展算法生态。LiteOS-M提供类…

【Linux 21】线程安全

文章目录 🌈 一、线程互斥⭐ 1. 线程间互斥的相关概念🌙 1.1 临界资源和临界区🌙 1.2 互斥和原子性 ⭐ 2. 互斥量 mutex⭐ 3. 互斥量接口🌙 3.1 初始化互斥量🌙 3.2 销毁互斥量🌙 3.3 互斥量上锁&#x1f3…

原子结构与电荷

1.原子结构与电荷 1.1 物质到底是由什么构成的 阴极射线 电磁波 电磁波 我们生活中的物质。究竟是由什么构成的呢?这个问题其实困扰了人们很久。 1.提出“原子”的概念 早在2400年前,古希腊哲学家德莫克里特就提出了原子的概念。当时他就认为&…

H264-NAL

目录 错误日志NAL简介参考资料 错误日志 拉流时存在如下日志,会因为拉流失败导致之后的任务也停止 missing picture in access unit with size 16384 Invalid NAL unit size Error splitting the input into NAL units. 之后只要设置抓取异常后,重新拉流&#xff…

Python--TCP/UDP通信

文章目录 前言一、pandas是什么?二、使用步骤 1.引入库2.读入数据总结 一.客户端与服务端通信原理 1. 服务器端 服务器端的主要任务是监听来自客户端的连接请求,并与之建立连接,然后接收和发送数据。 创建套接字:首先&#xff0…

【Fastapi】参数获取,json和query

【Fastapi】参数获取,json和query 前言giteegithub query形式json传递同步方法使用json 前言 花了半个月的时间看了一本小说,懈怠了…今天更新下fastapi框架的参数获取 gitee https://gitee.com/zz1521145346/fastapi_frame.git github https://git…

一些迷你型信息系统 - 2

1 Linux内核数据结构信息查询 Linux内核的数据结构众多,成千上万,做一个程序来存储查询信息;自己录入数据; 代码字段最长可录入65535个字符;每个字段录入时长度超限会有红色告警; 其他的以后想到再做&#…

git-repo系列教程(4) windows平台下安装git-repo客户端

文章目录 简介操作步骤1.设置/root目录和/home目录2.打开本地终端3.安装python34.安装git5.安装git -repo6.查看版本 需要注意点 简介 git-repo天生是在Linux和MacOS下使用,在windows下直接安装运行会出错. 经过不断尝试,终于找到了一种简单的安装方法,在网上现在是独一份. …

Golang | Leetcode Golang题解之第424题替换后的最长重复字符

题目: 题解: func characterReplacement(s string, k int) int {cnt : [26]int{}maxCnt, left : 0, 0for right, ch : range s {cnt[ch-A]maxCnt max(maxCnt, cnt[ch-A])if right-left1-maxCnt > k {cnt[s[left]-A]--left}}return len(s) - left }f…

Maven-六、私服仓库

Maven 文章目录 Maven前言下载到本地解压启动并访问资源管理maven配置创建仓库选择使用仓库配置私服地址 资源上传配置资源上传操作私服连接中央仓库总结 前言 模块在引用依赖时一般先看本地仓库再看中央仓库,但是在团队开发中,不同人员要引用一些项目通…

某省公共资源交易电子平台爬虫逆向

目标网站 aHR0cHM6Ly9nZ3p5ZncuZnVqaWFuLmdvdi5jbi9pbmRleC9uZXc 一、抓包分析 1、请求参数加密 二、逆向分析 搜索定位加密参数位置 这里生成,扣取响应代码到本地即可 2、响应数据加密解密 xhr断点 向下跟栈,直到出现加密数据 解密函数 本地获取数据…

C语言中数组和字符串的联系

一、C语言中,数组和字符串 1、C语言中,定义一个数组后,数组名保存的是这个数组的首地址。类似一个指向数组第一个元素的指针,但是这个指针不能重新指向。2、字符串在C语言中是通过字符数组来实现的,也就是说字符串还是…