引言

一直希望深入学习一下数据库持久化技术,接触过Hibernate、Mybatis,也使用过Spring事务管理来控制回滚操作,但是越发觉得底层知识有一定的知识盲区和空洞。

很多ORM框架都是基于JDBC规范来进行构建的,因此,学习JDBC的基础知识势在必行。虽然不建议在实际开发中使用 JDBC API,但了解其技术背景和使用过程无疑会更好的理解构建于其上的高级框架。

本篇博客总结自尚硅谷宋红康老师的视频教程,旨在记录和总结JDBC API的使用步骤和常见问题,方便未来面试和深入理解其他框架。

一、JDBC概述

1.1 JDBC 介绍

JDBC,Java Database Connectivity,Java数据库连接技术。这是JDK原生的独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(一组API)。

这套API包含在 java.sql. 和 javax.sql 包下。使用这套API 可以以一种标准的方法访问数据库资源。

JDBC产生的原因是由于各个数据库厂商,如MySQL、Oracle、SQL Server、DB2(IBM)等,都有属于自己数据库特有的连接和访问方式,从连接驱动到增删改查,都存在各种差异。

JDBC的目标是使Java程序员无需对特定的数据库系统的特点有过多了解,也能够快速完成数据库访问等开发工作。

1.2 JDBC体系结构

JDBC接口包括两个层次:

  • 面向应用的API:Java API,抽象接口,供应用开发者使用,包括连接数据库、执行SQL语句、获得结果等。
  • 面向数据库的API:Java Driver API,供数据库服务商实现特定于自家数据库的驱动程序。MySQL的驱动就是我们经常需要引入的mysql-connector-java.jar 。

1.3 JDBC的编程步骤

jdbc编程步骤有以下几步固定操作:

1、添加数据库驱动依赖,例如:MySQL的 mysql-connector-java.jar,这是一种纯Java实现的驱动程序,除此之外,微软的SQL Server,需要JDBC-ODBC桥方式。

2、加载并注册驱动程序

3、创建 Connection 对象

4、创建 Statement 对象

5、执行 SQL 语句

6、若为查询操作,需要额外处理 ResultSet 结果集

7、关闭 Statement 对象

8、关闭 Connection 对象

补充:ODBC(Open Database Connectivity 开放式数据库连接),是微软在 Windows 平台下推出的。

二、JDBC编程实践

在使用 JDBC 进行编程前,有一些不可或缺的要素:

1、Driver 接口实现:是JDBC API中对数据库驱动程序的接口定义,不同的数据库厂商会自定义实现,但都需要符合Driver接口标准。一般使用MySQL,就需要引入mysql-connector-java驱动包。

包中提供的 com.mysql.jdbc.Driver(高版本已经废弃,改为com.mysql.cj.jdbc.Driver) 就是java.sql.Driver接口的实现类。

2、数据库连接信息:URL、用户名、密码等。

JDBC URL的标准由三部分组成,各部分用冒号分隔,例如:

jdbc:mysql://localhost:3306/test?serverTimezone=UTC

jdbc是主协议名,mysql是子协议,JDBC URL的主协议始终是 jdbc。

以下代码为 jdbc 实现入库操作的最终版本,后面的章节将会进一步探讨可以优化或需要注意的点,但是以下代码作为学习范例,已经足够展现JDBC 编程的绝大部分内容。

import java.sql.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;public class PreparedStatementUpdTest {public static void main(String[] args) {jdbcTest();}public static void jdbcTest() {// 创建驱动Connection connection = null;PreparedStatement ps = null;try {Class.forName("com.mysql.cj.jdbc.Driver");// 声明连接信息String url = "jdbc:mysql://localhost:3306/learn_mysql?serverTimezone=UTC";String username = "root";String password = "123456";// 创建连接connection = DriverManager.getConnection(url, username, password);String sql = "INSERT INTO user(name, birth_day) VALUES(?, ?)";// SQL预编译ps = connection.prepareStatement(sql);ps.setObject(1, "Lisa");DateFormat format = new SimpleDateFormat("yyyy-MM-dd");java.util.Date birthday = format.parse("2021-02-12");// util.Date和sql.Date的共同点是毫秒数一样ps.setObject(2, new Date(birthday.getTime()));// 执行SQL语句,executeUpdate()方法可以返回 int 受影响行数ps.execute();} catch (Exception e) {e.printStackTrace();} finally {// 关闭资源try {if (ps != null)ps.close();} catch (SQLException e) {e.printStackTrace();}try {if (connection != null)connection.close();} catch (SQLException e) {e.printStackTrace();}}}
}

三、JDBC编程实践的优化与思考

3.1 创建驱动实例

在程序编写之初,我们已经通过依赖管理,将mysql-connector-java.jar 包引入类路径下,那么 JDBC 的 Driver 接口就有了针对于MySQL的驱动器实现——com.mysql.cj.jdbc.Driver。

实际上,我们可以通过最原始的方式 new 一个出来

// 直接 new 创建驱动实例,不要这么做!
Driver driver = new com.mysql.cj.jdbc.Driver();
// 声明连接信息(略)
// 从 Driver 中获取 Connection
Connection connection = driver.connect(连接信息);

但是通过 Class.forName(..) 获得驱动对象的好处就是可以将类名作为配置放到程序外,方便替换其他的数据库驱动,有更好的移植性:

// 通过反射获取驱动,有更强的可移植性
Class<?> clazz = Class.forName("com.mysql.cj.jdbc.Driver");
Driver driver = (Driver) clazz.newInstance();
// 声明连接信息(略)
// 从 Driver 中获取 Connection
Connection connection = driver.connect(连接信息);

3.2 DriverManager与Connection获取方式的

Driver 接口有获取Connection的方法,这是最初获取Connection的方式。

Connection connection = driver.connect(连接信息);

JDBC API提供了一个名为 DriverManager 的基础服务类,可以管理 Driver 驱动程序,并创建 Connection 对象,于是有了通过 DriverManager 获取 Connection的方式,但前提是需要将驱动对象注册到 DriverManager 中

// 创建驱动
Class<?> clazz = Class.forName("com.mysql.cj.jdbc.Driver");
Driver driver = (Driver) clazz.newInstance();
// 注册驱动
DriverManager.registerDriver(driver);
// 连接信息(略)
// 从驱动管理器中获取连接
Connection connection = DriverManager.getConnection(url, username, password);

其实,“注册驱动”的操作并不需要应用开发者来完成,在 Driver 类加载时,就会自动注册,原因就是以下静态代码块:

public class Driver extends NonRegisteringDriver implements java.sql.Driver {public Driver() throws SQLException {}static {try {DriverManager.registerDriver(new Driver());} catch (SQLException var1) {throw new RuntimeException("Can't register driver!");}}
}

因此,在 Class.forName(..) 完成后,mysql Driver 类已经成功加载,即已经完成了驱动注册步骤,因此我们可以更加简化我们获取Connection的代码:

Class.forName("com.mysql.cj.jdbc.Driver");
// 声明数据库连接信息(略)
Connection connection = DriverManager.getConnection(url, user, password);

另外,值得一提的是,Class.forName("com.mysql.cj.jdbc.Driver") 加载驱动这一步也可以省略,

这是因为当 mysql-connector-java.jar 引入类路径后,会默认自动加载 META-INF/services/java.sql.Driver中配置的驱动实现类,但是建议不要省略,因为如果迁移了其他数据库驱动,可能不会有这样的默认操作。

3.3 配置化数据库连接信息

在前面的例子中,其实已经可以轻松的获取到数据库连接:

Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/learn_mysql?serverTimezone=UTC";
String user = "root";
String password = "123456";
Connection connection = DriverManager.getConnection(url, user, password);

我们可以进一步将驱动类信息、连接信息转移到程序之外,以配置的形式存在:

然后通过 Properties 获取配置数据:

InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
Properties props = new Properties();
props.load(is);
String url = props.getProperty("url");
String username = props.getProperty("username");
String password = props.getProperty("password");
String driverName = props.getProperty("driverName");
// 加载驱动类
Class.forName(driverName);
// 获取连接
Connection connection = DriverManager.getConnection(url, username, password);

通过系统类加载器获取配置文件数据,默认读取 src 目录下的文件,以 properties 结尾的文件可以直接被 load 进 Properties 对象中。

3.4 Statement与PreparedStatement

数据库连接被用于向数据库服务器发送命令和SQL语句,并接收数据库返回的结果。其实,一个数据库连接就是一个Socket连接。

在java.sql包中有 3 个接口分别定义了对数据库的调用方式:

  • Statement:用于执行静态SQL语句并返回它所生成结果的对象。
  • PreparedStatement:SQL语句被预编译并存储在此对象中,可以使用此对象多次高效地执行SQL语句。
  • CallableStatement:用于执行SQL存储过程。

原始的Statement存在一定的弊端,由于只能处理静态SQL语句,因此只能将变量直接拼接到SQL中才可以使用,除此之外,更严重的问题还是SQL注入

例如下面这条拼接的SQL语句:

String sql = "SELECT user, password FROM user_table WHERE user='" + username + "' AND password='" + password + "'";

如果username和password分别是:

String username = "1' OR ";
String password = " = 1 OR '1' = '1";

那么sql 的WHERE条件就是一个恒成立的情况,这就是SQL注入:

SELECT user, password FROM user_table WHERE user='1' OR ' AND password=' = 1 OR '1' = '1'

PreparedStatement表示一个可以预编译SQL语句的对象,使用“?”占位符来明确区分 SQL语法与参数,可以有效防止SQL注入问题。

因此,Statement 已不再使用了,取而代之的是可以进行预编译SQL的PreparedStatement。

总结

JDBC是数据库访问的公共规范,它的编程步骤主要分为几点:

1、引入对应数据库厂商的驱动包

2、加载、注册驱动(类加载的同时即完成注册)

3、从驱动管理器 DriverManager 中直接通过连接信息创建一个 Connection 对象

4、使用 Connection 对象以预编译方式创建 PreparedStatement 对象

5、填充 PreparedStatement 属性值

6、使用PreparedStatement 执行SQL 操作(查询操作需要处理结果集)

7、以资源创建的先后顺序,逆向关闭资源

JDBC——概述与JDBC的使用相关推荐

  1. JDBC概述(JDBC是什么,主要作用,驱动类型等)

    1. 概述: JDBC是一种可用于执行SQL语句的JAVA API,是链接数据库和JAVA应用程序的纽带 2. 主要任务: JDBC技术主要是完成以下几个任务: 与数据库建立一个链接 向数据库发送SQ ...

  2. 01-JDBC学习手册:JDBC概述之JDBC发展、API、驱动

    1  概述 JDBC  从物理结构上说就是 Java 语言访问数据库的一套接口集合.从本质上来说就是调用者(程序员)和实现者(数据库厂商)之间的协议.JDBC 的实现由数据库厂商以驱动程序的形式提供. ...

  3. 小汤学编程之JDBC(一)——JDBC概述和快速入门

    一.JDBC概述 1.概念     2.作用 二.JDBC快速入门 1.实现步骤     2.查询数据和操作数据     3.SQL注入     4.事务管理     5.Statement与Prep ...

  4. 【JDBC】——JDBC概述

    JDBC概述 JDBC(Java Data Base Connectivity) 数据库连接 是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口(API),提供了诸如查询和更新数据库中数 ...

  5. 【JDBC - 核心技术】01 JDBC概述

    第01章 JDBC概述 创作日期:2021-12-05 1.1 数据的持久化 持久化(persistence):把数据保存到可掉电式存储设备中以供之后使用.大多数情况下,特别是企业级应用,数据持久化意 ...

  6. 【JDBC技术】终于知道Java底层是如何连接数据库了!——(1)JDBC概述

    JDBC 核心技术解析 JDBC 指 Java 数据库连接,是一种标准Java应用编程接口( JAVA API),用来连接 Java 编程语言和广泛的数据库. 文章目录 JDBC 核心技术解析 JDB ...

  7. dorado java_概述-Dorado JDBC Addon

    最新动态 JDBC Addon 1.0.2已经正式发布.参考:发布日志 文档正在编写中,目前发布在WIKI中 为什么我们开发了Dorado7 JDBC Addon Dorado7 JDBC Addon ...

  8. JDBC 第一章 JDBC概述

    文章目录 1.JDBC的本质 2.模拟JDBC 传送门 1.JDBC的本质 JDBC(Java DateBase Connectivity Java语言连接数据库)本质上是SUN公司制定的一套接口 面 ...

  9. jmeter jdbc mysql_jmeter获取JDBC响应做接口关联(三)

    概述: jmeter中,常常需要连接数据库去断言业务是否正确.因此jdbc数据库关联是必须掌握的核心知识. 基础操作 JDBC请求,最核心的是两个jar包: mysql驱动-mysql-connect ...

最新文章

  1. [WARNING] unable to add QUERY_STRING=XXXX to uwsgi packet, consider increasing buffer size
  2. 《初级前端开发人员经常容易忽视几个细节问题汇总》
  3. pyqt5讲解12:自定义参数 (给信号传入参数)
  4. Scala-列表操作
  5. Mysql学习总结(64)——Mysql配置文件my.cnf各项参数解读
  6. 开课吧:OOM常见的解决方案有哪些?
  7. 语言环境及apt工具使用方法
  8. iview在项目中遇到的坑
  9. RK3328 中文介绍
  10. 支付交易相关接口文档对接
  11. scrapy爬取阳光政务投诉
  12. 2015年电商行业十大发展趋势分析预测
  13. 博士申请 | 阿尔伯塔大学招收人工智能方向全奖博士生、硕士生
  14. win10重装系统自动修复失败,用U盘做了启动器也进不去PE界面的解决办法
  15. JSONObject 转对象
  16. 裴建瑞2021011195
  17. ORACLE数据库23道练习题
  18. centos7 oracle11g创建表空间和用户
  19. 第1部分 基础算法(提高篇)--第1章 贪心算法1425:【例题4】加工生产调度
  20. strncasecmp() 函数

热门文章

  1. c++重载++运算符_C ++运算符重载| 查找输出程序| 套装3
  2. 实战:隐藏SpringBoot中的私密数据!
  3. js时间格式化通用方法
  4. linux——回射服务器
  5. nifi 实现数据库到数据库之间数据同步
  6. RequestDispatcher提供两个方法:forward,include有什么区别
  7. uniapp+typeScript+vue3.0+vite
  8. mysql基础测试_MySQL基础知识测试
  9. linux临时挂载别的文件目录_linux基础05:linux系统目录有哪些?命令行界面如何切换目录?...
  10. @data注解不生效_你说啥什么?注解你还不会?