【MySQL】JDBC 编程详解

JDBC 编程详解

  • 一. 概念
  • 二. JDBC 工作原理
  • 三. JDBC 使用
    • 1. 创建项目
    • 2. 引入依赖
    • 3. 编写代码
      • (1). 创建数据源
      • (2). 建立数据库连接
      • (3). 创建 SQL
      • (4). 执行 SQL
      • (5). 遍历结果集
      • (6). 释放连接
    • 4. 完整的代码
    • 5. 如何不把 sql 写死 ?
    • 6. 获取连接失败的情况
  • 四. JDBC常用接口和类
    • 1. 数据库连接 Connection
    • 2. Statement 对象
    • 3. PreparedStatement 的预编译

一. 概念

JDBC: 即Java Database Connectivity,java数据库连接。是一种用于执行SQL语句的Java API,
它是Java中的数据库连接规范。这个API由 java.sql.*,javax.sql.* 包中的一些类和接口组成,
它为Java开发人员操作数据库提供了一个标准的API,可以为多种关系数据库提供统一访问。

产生的原因:
MySQL、Oracle、SQL server 这些数据库都提供自己的 API 来支持程序员实现自己的客户端来完成一些增删改查功能, 没有业界统一的标准,Java 当然不乐意了, 因为 Java 诞生就是为了跨平台的。
所以 Java 就搞出了 JDBC,约定一组 API 为 JDBC,里面包含一些类和方法, 通过这些类和方法实现数据库的基本操作,由各厂商提供各自的 “数据库驱动包” 来和 JDBC 的 API 对接。
所以,只要掌握这一套 JDBC API 就可以操作各种数据库了。

二. JDBC 工作原理

JDBC 为多种关系数据库提供了统一访问方式,作为特定厂商数据库访问API的一种高级抽象,它主要包含一些通用的接口类。

JDBC 访问数据库层次结构:
在这里插入图片描述

JDBC 优势:

  • Java 语言访问数据库操作完全面向抽象接口编程
  • 开发数据库应用不用限定在特定数据库厂商的 API
  • 程序的可移植性大大增强

三. JDBC 使用

注意:
JDBC 只支持关系型数据库, 不支持非关系型数据库。

1. 创建项目

创建一个项目即可。

2. 引入依赖

  • 准备数据库驱动包,并添加到项目的依赖中:
    在项目中创建文件夹 lib,并将依赖包(MySQL 使用的是哪个系列就用哪个系列的驱动)如 mysql-connector-java-5.1.47.jar (下载地址:Maven 中央仓库) 复制到 lib 中。
    右键上面的目录,选择 add as library 选项,这样才能把 jar 包导入到项目中,项目才能读取到里面的 .class 文件。

3. 编写代码

(1). 创建数据源

// 创建数据源
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("你的用户名");
((MysqlDataSource)dataSource).setPassword("你的数据库密码");

注意:

  1. DataSource 对象描述了数据库对象在哪。

  2. MySQL 数据连接的 URL 参数格式如下:
    jdbc:mysql://服务器地址:端口/数据库名?参数名=参数值&参数名=参数值&…
    服务器地址:我们写 的 127.0.0.1 是因为我们连接的是 本机的数据库, 所以用的是环回 IP 127.0.0.1,如果连接的是服务器上的数据库就得写对应的 IP 地址。
    端口:MySQL 的默认端口号为 3306
    数据库名:代码中的 URL 中的 test 要换为自己的数据库的名字。

  3. setUser、setPassword 都是自己的用户名(MySQL 默认用户为 root )和密码。

  4. 为什么 使用向上转型,DataSource 引用 MysqlDataSource 对象,然后设置参数时 先强转(向下转型)回来,为什么不直接使用 MysqlDataSource 对象,这样不就不用来回转了嘛 ?
    为了使代码低耦合:
    后面代码中若需要用到 DataSource 类型,使用的相关参数也是 dataSource , 未来如果 不适用 MySQL 做数据库了, 使用其他数据库了 如 PostgreSQL 了,代码几乎不用怎么改动。
    但是如果直接写成 :

MysqlDataSource mysqlDataSource = new MysqlDataSource();

这样不需要来回转换, 但是代码中充斥着 MysqlDataSource,到时候一旦更换数据库,代码要改动的地方就非常多了, 基本凉凉。

(2). 建立数据库连接

// 建立连接
Connection connection = dataSource.getConnection(); // 注意处理异常

(3). 创建 SQL

JDBC 中构造的 sql 不需要带上 ; 符号

// 创建 sql// 更新的 sql 
String sql = "insert into student values ('wangwu', 90)";
PreparedStatement statement = connection.prepareStatement(sql);// 查询的 sql
// String sql2 = "select * from student"; // 不用加上 ;
// PreparedStatement statement2 = connection.prepareStatement(sql2);

只一个 String 类型的 sql 还不行,需要把这个 String 包装成一个语句对象 PreparedStatement 。

(4). 执行 SQL

// 执行 sql
int ret = statement.executeUpdate();// 执行查询的 sql 
// ResultSet resultSet = statement2.executeQuery();

执行 增删改 的 sql 使用 executeUpdate 方法, 返回值是受影响的行数。
执行 查询 的 sql 使用 executeQuery 方法,并使用 ResultSet 接收结果。

(5). 遍历结果集

      // 执行 查询的 sql 时需要遍历结果集while (resultSet.next()) {int age = resultSet.getInt("age");String name = resultSet.getString("name");System.out.println(" 姓名: " + name + " 年龄: " + age);}

可以根据 列名 获取对应的值, 也可以根据列的下标(从 1 开始)获取,但是不推荐。

(6). 释放连接

        // resultSet.close(); // 如果查询的话需要释放statement.close(); connection.close();// 也要注意处理异常

先释放 statement 再 释放 connection
类似于关冰箱,先把抽屉关了, 再把冰箱门关了。

4. 完整的代码

以查询为例:

    public static void main(String[] args) throws SQLException {// 1. 创建数据源DataSource dataSource = new MysqlDataSource();((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false");((MysqlDataSource)dataSource).setUser("root");((MysqlDataSource)dataSource).setPassword("123456");// 2. 建立数据库连接Connection connection = dataSource.getConnection(); // 注意处理异常// 3. 创建 sqlString sql = "select * from student"; // 不用加上 ;PreparedStatement statement = connection.prepareStatement(sql);// 4. 执行查询的 sqlResultSet resultSet = statement.executeQuery();// 5. 遍历结果集 (查询的话需要)while (resultSet.next()) {int age = resultSet.getInt("age");String name = resultSet.getString("name");System.out.println(" 姓名: " + name + " 年龄: " + age);}// 6. 释放连接resultSet.close(); // 如果查询的话需要释放statement.close();connection.close();}

在这里插入图片描述

使用步骤总结:

六个步骤:

  1. 创建数据源: DataSourse
  2. 建立数据库连接: Connection
  3. 创建 sql: PreparedStatement
  4. 执行 sql: executeUpdate/executeQuery
  5. 遍历结果集(如果是 查询的话): ResultSet
  6. 释放连接 ResultSet / PreparedStatement / Connection close()

注意:

整个写代码的时候注意处理异常,要么抛给上层调用者,要么自己处理掉。

5. 如何不把 sql 写死 ?

使用 PreparedStatement 并使用占位符

String name = "zhouba";
int age = 88;
String sql = "insert into student values(?,?)"; // 不用加上 ;PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1, name);
statement.setInt(2, age);
statement.executeUpdate();

使用 ? 先占一个位置,再使用 PreparedStatement 的 setXXX 方法进行替换,注意类型要一致。
注意该方法的第一个参数 是 ? 的位置, 下标从 1 开始,第二个参数是要填上去的值。

如果想一次插入多条数据, 就使用多个 ?, 对应替换上去就行了。

String sql = "insert into student values(?,?),(?,?),(?,?),(?,?)"; // 不用加上 ;

不要使用字符串拼接实现动态 sql, 因为会引入 sql 注入问题
比如: 可能我们如果使用 字符串拼接的话, 会像下面这么写

Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
String password = scanner.nextLine();
String sql = "select * from user where name=" + name + " and password=" + password;
PreparedStatement statement = connection.prepareStatement(sql);

正常情况下没有什么问题, 但是, 有一个巨大的漏洞,
当用户输入:

'zhangsan'
'' or 1=1

(或者输入一些其他的恶意代码)
拼接成的 sql 为

select * from user where name='zhangsan' and password='' or 1=1

最后出现了一个 or 1=1
这在什么条件下都会成立的,所以说这个 sql 完全能执行成功,
在恶意用户不用知道 正确的用户名和密码的情况下,能查询数据库中的所有内容, 这是相当可怕的,尤其在一些银行等数据库内容非常机密的情况下。
所以, 我们不能使用 字符串拼接来实现动态的 sql ,
而 使用 PreparedStatement 的占位符则不会出现这种情况。

6. 获取连接失败的情况

  • 数据库地址不对
  • 端口号不对
  • 数据库名不对
  • 用户名不对
  • 密码不对
  • 其他情况

四. JDBC常用接口和类

1. 数据库连接 Connection

Connection 接口实现类由数据库提供,获取 Connection 对象通常有两种方式:

  • 一种是通过 DriverManager(驱动管理类)的静态方法获取:
// 加载JDBC驱动程序:反射,这样调用初始化com.mysql.jdbc.Driver类,即将该类加载到JVM方法区,并执行该类的静态方法块、静态属性。
Class.forName("com.mysql.jdbc.Driver");// 创建数据库连接
Connection connection = DriverManager.getConnection(url,user,password);
  • 一种是通过 DataSource(数据源)对象获取。实际应用中会使用 DataSource 对象。
DataSource ds = new MysqlDataSource();
((MysqlDataSource) ds).setUrl("jdbc:mysql://localhost:3306/test");
((MysqlDataSource) ds).setUser("root");
((MysqlDataSource) ds).setPassword("123456");
Connection connection = ds.getConnection();

以上两种方式的区别是:

  1. DriverManager 类来获取的 Connection 连接,是无法重复利用的,每次使用完以后释放资源时,通过 connection.close() 都是关闭物理连接。
  2. DataSource 提供连接池的支持。连接池在初始化时将创建一定数量的数据库连接,这些连接是可以复用的,每次使用完数据库连接,释放资源调用 connection.close() 都是将 Conncetion 连接对象重新初始化然后回收,不用关闭物理连接。

非常不建议使用 DriverManager :

  1. 使用了反射,非常影响代码的可读性,也不利于 IDEA 对代码解析校验。
  2. DataSourse 内置连接池,在频繁创建/断开连接时,DataSourse 比 DriverManager 的方式更高效。

2. Statement 对象

Statement 对象主要是将SQL语句发送到数据库中。JDBC API 中主要提供了三种 Statement 对象。

在这里插入图片描述

实际开发中最常用的是 PreparedStatement 对象:

  1. 可以参数化 SQL 查询。
  2. 占位符为 ?,下标从 1 开始,占位符不能使用多值。
  3. 使用 SQL 预编译。
  4. 可以阻止常见的 SQL 注入攻击。
  5. 性能比 Statement 高。

PreparedStatement 与 Statement 的区别:

  1. Statement 是 PreparedStatement 的父接口。
  2. 语法不同:PreparedStatement 使用预编译,使用动态 sql 时,相同的 sql 语句,除了参数不同,只需发送一次 sql,后面的只发送了参数,共用一个 sql 语句。(同构)
    而 Statement 只能使用静态 sql。(异构)
  3. 效率不同:PreparedStatement 使用了缓冲区,效率比 Statement 高。
  4. 安全性不同: PreparedStatement 可有效防止 sql 注入,Statement 不能。

3. PreparedStatement 的预编译

  1. 只有数据库服务器支持预编译,JDBC 驱动才能使用数据库预编译功能,预编译在比较新的 JDBC 驱动中默认是关闭的,需要配置才能打开。
  2. PreparedStatement 预编译是数据库进行的,编译后 函数的 key 缓存在 PreparedStatement 中,函数本身 缓存在 数据库服务器中。
  3. 预编译前检查 sql 语法是否正确。
  4. PreparedStatement 需要使用带 占位符的 sql, 如果使用静态 sql, 也还是会编译多次。Statement 本身就只支持静态的 sql。
  5. 数据库服务器对 sql 模板进行编译,且 PreparedStatement 存储了函数 的 key, 所以 PreparedStatement 做的就是把参数转义后直接传参数到数据库服务器中,然后让函数执行,所以 PreparedStatement 能防止 sql 注入。
  6. PreparedStatement 存储的 key 和 数据库存储的函数都建立在数据库连接的基础上,连接断开,key 和函数都清空。
  7. 各个连接之间的预编译都是相互独立的。
  8. Statement 不缓存函数的key, 数据库也不缓存函数, 所以多次执行相同一条 sql 时,还是会先检查 sql 的语法,再编译执行。

好啦,以上就是对 JDBC 编程的讲解,希望能帮到你 !
评论区欢迎指正 !

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

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

相关文章

MT36291 2.5A,高效型1.2MHz电流模式升压转换器芯片

MT36291 2.5A,高效型1.2MHz电流模式升压转换器芯片 特征 ●集成了80ms功率的MOSFET ●2.2V到16V的输入电压 ●1.2MHz固定开关频率 ●可调过电流保护: 0.5A ~2.5A ●内部2.5开关限流(OC引脚浮动) ●可调输出电压 ●内部补偿 ●过电…

vue插槽slot

插槽有三种&#xff1a; 目录 1.普通插槽 2.具名插槽 3.作用域插槽 1.普通插槽 sub.vue 子组件 --- 子组件写slot标签&#xff0c;父组件的Sub标签内填写的内容会显示在slot的位置&#xff0c;父组件如果不写内容就会展示默认内容。 <template><div class"…

极坐标转化

在数学中&#xff0c;极坐标系是一个二维坐标系统。该坐标系统中任意位置可由一个夹角和一段相对原点—极点的距离来表示。极坐标系的应用领域十分广泛&#xff0c;包括数学、物理、工程、航海、航空以及机器人领域。两点间的关系用夹角和距离很容易表示时&#xff0c;极坐标系…

Redis-Cluster集群的部署(详细步骤)

一、环境准备 本次实操为三台机器&#xff0c;关闭防火墙和selinux 注:规划架构两种方案&#xff0c;一种是单机多实例&#xff0c;这里我们采用多机器部署 三台机器&#xff0c;每台机器上面两个redis实例&#xff0c;一个master一个slave&#xff0c;第一列做主库&#xff…

基于matlab的扩频解扩误码率完整程序分享

clc; clear; close all; warning off; addpath(genpath(pwd)); r5; N2^r-1;%周期31 aones(1,r); mzeros(1,N); for i1:(2^r-1) temp mod((a(5)a(2)),2); for jr:-1:2 a(j)a(j-1); end a(1)temp; m(i)a(r); end mm*2-1;%双极性码 %产生随…

学妹学Java(一)

⭐简单说两句⭐ 作者&#xff1a;后端小知识 CSDN个人主页&#xff1a;后端小知识 &#x1f50e;GZH&#xff1a;后端小知识 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; Hello&#xff0c;亲爱的各位友友们&#xff0c;好久不见&#xff0…

K8s 多集群实践思考和探索

作者&#xff1a;vivo 互联网容器团队 - Zhang Rong 本文主要讲述了一些对于K8s多集群管理的思考&#xff0c;包括为什么需要多集群、多集群的优势以及现有的一些基于Kubernetes衍生出的多集群管理架构实践。 一、为什么需要多集群 随着K8s和云原生技术的快速发展&#xff0c…

echarts条形图实现颜色渐变

eCharts——柱状图中的柱体颜色渐变_echarts 柱状图渐变_小美同学的博客-CSDN博客 【Echarts】柱状图渐变两种实现方式_echarts柱状图渐变_芳草萋萋鹦鹉洲哦的博客-CSDN博客

将 Spring Boot 应用程序与 Amazon DocumentDB 集成

Amazon DocumentDB&#xff08;与 MongoDB 兼容&#xff09;是一种可扩展、高度持久和完全托管的数据库服务&#xff0c;用于操作任务关键型 MongoDB 工作负载。在 Amazon DocumentDB 上&#xff0c;您可以使用相同的 MongoDB 应用程序代码、驱动程序和工具来运行、管理和扩展工…

学习笔记|回顾(1-12节课)|应用模块化的编程|添加函数头|静态变量static|STC32G单片机视频开发教程(冲哥)|阶段小结:应用模块化的编程(上)

文章目录 1.回顾(1-12节课)2.应用模块化的编程(.c .h)Tips:添加函数头创建程序文件三步引脚定义都在.h文件函数定义三步bdata位寻址变量的使用 3.工程文件编写静态变量static的使用完整程序为&#xff1a;demo.c&#xff1a;seg_led.c:seg_led.h: 1.回顾(1-12节课) 一、认识单…

文件上传漏洞-upload靶场13-16关 (图片木马-文件包含与文件上次漏洞)

文件上传漏洞-upload靶场13-16关 &#xff08;图片木马-文件包含与文件上次漏洞&#xff09; 简介 upload靶场到了第十三关&#xff0c;难度就直线上升了&#xff0c;在最后这7关中&#xff0c;包含了图片木马、竞争条件等上传技巧&#xff0c;这些漏洞的本质&#xff0c;都是…

重复的DNA序列(力扣)JAVA

DNA序列 由一系列核苷酸组成&#xff0c;缩写为 ‘A’, ‘C’, ‘G’ 和 ‘T’.。 例如&#xff0c;“ACGAATTCCG” 是一个 DNA序列 。 在研究 DNA 时&#xff0c;识别 DNA 中的重复序列非常有用。 给定一个表示 DNA序列 的字符串 s &#xff0c;返回所有在 DNA 分子中出现不止…

Vite,Vue3项目引入dataV报错的解决方法

背景:开发一个大屏项目中,需要是要DataV的那边边框,装饰等,只是DataV是基于vue2的,vue3版的作者还在开发中,于是翻了DataV的源码,发现使用esm方式时是直接引入源码而不经过打包,其源码中使用的vue语法vue3也支持,所以可以直接在vue3中引入使用. vite,vue3项目直接引入DataV 安…

Upload-labs 1~15 通关详细教程

文章目录 Upload-labs 1~15 通关详细教程Pass-01-前端js验证Pass-02-后端MIME验证Pass-03-黑名单验证Pass-04-黑名单验证.htaccessPass-05-文件后缀名大小写绕过Pass-06-文件后缀名空格绕过Pass-07-文件后缀名点绕过Pass-08-文件后缀名::$DATA绕过Pass-09-点空格点空格绕过Pass…

《Market Insight:中国低代码/零代码市场发展洞察 ( 2023 )》报告正式发布 | LowCode低码时代

数字化浪潮下&#xff0c;低代码/零代码通过提升“开发生产力”将极大促进技术应用效率和产业数字化进程。目前中国的低代码/零代码在制造业、政务与公共事业、金融、电商等领域取得了一定的应用成效。而伴随着生成式AI技术的应用突破&#xff0c;低代码/零代码市场又将迎来新的…

【前端】React项目初体验

React介绍 React 是一个非常流行的 JavaScript 前端框架&#xff0c;它为开发人员提供了一种快速构建高质量用户界面的方式。以下是使用 React 构建项目的初体验&#xff1a; 安装 React 和相关依赖项 使用 React 开发项目需要先安装一些必需的依赖项&#xff0c;包括 Node.…

快速掌握STM32工程创建

STM32 工程创建-- 使用Keil uVision5 软件 晓理紫 1 准备库函数库 STM32F10x_StdPeriph_Lib_V3.5.0 VX 搜索“晓丽紫”关注回复STM32F10x即可下载 2、创建一个目录用来存放工程 STM32Study STM32Study/study1 存放本次工程目录 3、打开Keil uVision5 创建工程 4、选择型号(根据…

【用unity实现100个游戏之9】使用Unity制作类八方旅人、饥荒风格的俯视角2.5D游戏

前言 2.5D游戏 是一种介于二维和三维之间的游戏形式。它通常在二维平面上展示游戏内容&#xff0c;但利用三维技术来实现更加逼真的图像效果。 在2.5D游戏中&#xff0c;角色和环境通常是以平面的形式呈现&#xff0c;但可以在垂直方向上移动。这意味着玩家可以在一个相对较薄…

对话永洪科技CEO何春涛:专注BI,决胜AI时代丨数据猿专访

大数据产业创新服务媒体 ——聚焦数据 改变商业 大数据、云计算、人工智能为代表的新一代信息技术走向普及&#xff0c;数据驱动业务&#xff0c;逐渐成为现代化企业管理、运作的日常。对于年均复合增长率超过20%的国内商业智能&#xff08;BI&#xff09;市场而言&#xff0c…

编译KArchive在windows10下

使用QT6和VS2019编译KArchive的简要步骤&#xff1a; 安装 Qt &#xff0c;我是用源码自己编译的 "F:\qtbuild"安装CMakefile并配置环境变量安装Git下载ECM源码 https://github.com/KDE/extra-cmake-modules.git-------------------------------------------------…