Java数据库连接

应用程序接口

Java数据库连接

Java数据库连接(英文:Java Database Connectivity,简称 JDBC)是一种Java应用程序编程接口(Java API),用于管理与数据库的连接并执行查询。[1]JDBC面向关系型数据库,为Java应用程序提供数据库连接标准。[1][2]JDBC API起源于Microsoft公司的开放数据库连接(Open DataBase Connectivity,简称ODBC),是Sun Microsystems公司专门为Java语言设计的处理SQL(结构化查询语言)的接口,于1997年作为JDK 1.1的一部分发布,是最早为Java语言开发的库之一。[3]JDBC自发布以来,经历了多个版本的更新和改进,以支持Java平台和数据库技术的发展。JDBC 4.3是现在的最新版本,于2017年9月作为Java SE 9的一部分发布。[4]目前,JDBC API已经成为Java应用程序连接和访问数据库的主流技术之一,并被应用到各种框架和工具中。[5][6][7][8]

Java数据库连接(英文:Java Database Connectivity,简称 JDBC)是一种Java应用程序编程接口(Java API),用于管理与数据库的连接并执行查询。[2]JDBC面向关系型数据库,为Java应用程序提供数据库连接标准。[2][3]

JDBC API起源于Microsoft公司的开放数据库连接(Open DataBase Connectivity,简称ODBC),是Sun Microsystems公司专门为Java语言设计的处理SQL(结构化查询语言)的接口,于1997年作为JDK 1.1的一部分发布,是最早为Java语言开发的库之一。[4]JDBC自发布以来,经历了多个版本的更新和改进,以支持Java平台和数据库技术的发展。JDBC 4.3是现在的最新版本,于2017年9月作为Java SE 9的一部分发布。[5]目前,JDBC API已经成为Java应用程序连接和访问数据库的主流技术之一,并被应用到各种框架和工具中。[6][7][8][9]

JDBC API由一组用Java编程语言编写的接口和类组成,主要接口和类有:DriverManager类、Connection接口、Statement接口等。使用这些标准接口和类,程序员可以编写连接到数据库的应用程序、发送用SQL编写的查询并处理结果。[10]而JDBC驱动程序为特定的DBMS厂商实现了这些接口和类,可以认为,JDBC驱动程序在Java应用程序和所需数据库之间架起一座桥梁。使用JDBC API的Java应用程序在实际连接到数据库之前会加载特定DBMS的指定驱动程序,然后,JDBC DriverManager类将所有JDBC API调用发送到加载的驱动程序来实现数据库的连接和访问。[11]

起源

20世纪80年代,SQL成为关系数据库管理广泛采用的语言。到了20世纪90年代,数据库技术发展迅速,出现了多种类型和厂商的数据库管理系统(DBMS),如OracleSybaseInformixDB2等,这些数据库管理系统都有自己的特定的接口和协议,导致了数据库编程的碎片化和不兼容性[12]为了统一对SQL数据库的访问,Microsoft公司于 1992年推出了开放数据库连接(Open Database Connectivity,简称ODBC),一种用于连接和操作数据库的通用 API。ODBC API是一个ODBC函数库,独立于编程语言和数据库系统,它可以让支持ODBC的应用程序连接到任何有ODBC驱动程序的数据库,执行SQL语句,并获取结果。[13]

然而,ODBC API不适合直接用于Java编程语言,因为它使用了C语言的接口,从Java调用本地C代码会带来一些安全性、实现、稳健性和应用程序的自动可移植性方面的缺点。且ODBC性能较低,依赖于操作系统,不支持对象和异常,而Java是一种流行的、跨平台的、面向对象的编程语言,它需要一种更适合自己的数据库访问方式。[1]

为了解决这些问题,Sun Microsystems公司于1997年专门为Java语言设计了JDBC API,它是一个基于Java的数据库访问接口,可以让Java应用程序连接到任何支持SQL的数据库。JDBC API借鉴了ODBC的一些设计思想,它也是基于Open Group SQL CLI (Call Level Interface) 的,但是JDBC API更适合Java的特点和优势,它使用了Java的对象和异常机制,而且不依赖于操作系统或数据库厂商的 API,从而提高了安全性、稳健性和可移植性。JDBC API由此成为了Java语言访问关系数据库的标准方式。[1]

发展

1997年 Sun Microsystems公司发布的JDBC 1.0只支持基本的SQL语句,没有提供高级功能,如事务控制、结果集处理等。1999年,为了解决效率和稳定性问题,JDBC 2.0发布,增加了高级功能,如批处理更新、事务控制、数据源、行集等。JDBC API从JDBC 2.0开始分为JDBC 2.0 Core API(java.sql)和JDBC 2.0 Standard Extension API(javax.sql)。[14]

2003年,JDBC 3.0发布,引入了保存点、返回自动生成的键、参数元数据等特性,以适应更复杂、更大规模的数据处理需求。这些特性使得Java程序能够更好地处理分布式和并发的环境,提高了容错和恢复能力。[15]

2006年,JDBC 4.0发布,支持了Java SE 6的新特性,如注解、泛型、自动加载驱动等。JDBC 4.0进一步简化了开发过程,通过引入自动加载驱动程序和增强型连接功能来提高开发人员的生产力和应用程序的可靠性,这些特性使得Java程序能够更容易地与新的数据库技术和标准进行集成,如SQL XML、Blob和 Clob的流式处理等。[16]

2011年,JDBC 4.1发布,主要是为了支持Java SE 7的新特性,如try-with-resources 语句、JDBC-ODBC桥的移除、RowId生命周期提示等,使得Java程序能够更简洁地管理资源、更方便地访问本地数据库、更准确地处理RowId类型等。[17]

2014年,JDBC 4.2发布,提供了对Java SE 8的新特性的支持,如日期和时间类型、大对象的流式处理、REF CURSOR类型等,这些特性使得Java程序能够更好地处理新的数据类型和格式。[18]

2017年,JDBC 4.3发布,支持了Java SE 9的新特性,如模块化系统、Sharding API以及更多的SQL类型,这些特性使得Java程序能够更好地适应模块化的开发模式、更好地支持分布式和水平扩展的数据库、更好地兼容不同的数据库标准等。[19]

现状

目前,JDBC在Java平台和数据库技术的发展中扮演了重要的角色,为Java程序提供了一种简单、统一、跨平台的数据库访问机制,让Java程序可以与任何支持SQL的数据库进行通信。JDBC被广泛应用于各种Java应用程序和框架中,例如Spring、Hibernate、JPA等,在Web开发、数据分析、企业应用、云计算等领域都有重要的作用。[6][7][8][9]

JDBC应用程序模型

JDBC API支持数据库访问的两层和三层客户端-服务器模型。[20][21]

两层客户端-服务器模型

所谓的两层模型是指Java应用程序和目标数据库分别安装在两个层次的组件上。[21]这两个组件分别是:

应用层:安装在客户端机器上,包括:JDBC驱动程序:用于连接数据库和执行SQL语句;用户界面:用于与用户交互和显示数据;Java应用程序:用于实现业务逻辑和数据处理。[21]数据库层:安装在数据库服务器上,包括:RDBMS:用于管理和存储数据;数据库:用于存放具体的数据表和记录。[21]

两层模型的典型配置(图片来源:)
两层模型的典型配置(图片来源:)

在两层客户端-服务器模型中,Java应用程序直接与数据库通信,这需要一个JDBC驱动程序,它可以与被访问的特定数据库进行交互,用户的命令被JDBC驱动程序传送到数据库或其他数据源,而这些语句的结果被发送回用户。数据库可以位于另一台机器上,用户通过网络与之连接,这被称为客户端-服务器配置,用户的机器是客户端,数据库所在的机器是服务器。用户连接数据库的网络可以是一个内部网,例如一个公司的内部网络,也可以是互联网。[20]

三层客户端-服务器模型

三层客户端-服务器模型是一种常用的Java数据库应用程序的架构方式,它分为三个层次的组件,分别是客户端层、应用程序服务器层和数据库层。这三个层次的组件可以分别安装在不同的机器上,通过网络进行通信和数据交换[21]

客户端层:用户与应用程序交互的界面,它可以是一个Web浏览器,也可以是一个桌面应用程序或移动应用程序。客户端层通常包括一些语言指定的虚拟机,如Java虚拟机或.NET虚拟机,用于运行应用程序的代码。客户端层向应用程序服务器层发送数据操作请求,如查询、插入、更新或删除数据,然后接收应用程序服务器层返回的数据或结果,并显示给用户。[21]应用程序服务器层:负责处理业务逻辑或应用程序逻辑,如验证用户身份、计算数据、生成报表等。应用程序服务器层可以使用Java Web应用程序或Java Web服务来实现,这些应用程序或服务可以运行在一个Web服务器上,如TomcatJetty。应用程序服务器层包含JDBC API,用于连接数据库和执行SQL语句。应用程序服务器层接收客户端层的数据操作请求,然后根据请求的内容,向数据库层发送相应的SQL语句,并将数据库层返回的数据或结果,转换为客户端层可以识别的格式,如XML或JSON,并发送回客户端层。[21]数据库层:负责数据存储,它包括一个关系数据库管理系统(RDBMS)和一个数据库。数据库层可以安装在一个数据库服务器上,如MySQLOracle或SQL Server。数据库层接收应用程序服务器层的SQL语句,然后根据SQL语句的内容,对数据库进行相应的操作,如查询、插入、更新或删除数据,并将操作的结果或数据,返回给应用程序服务器层。[21]

三层模型的典型配置(图片来源:)
三层模型的典型配置(图片来源:)

使用三层模型相比两层模型的优点包括:

通过分离应用程序服务器层和数据库层,应用程序服务器层可以并发地处理多个客户端层的请求,而数据库层可以专注于数据的管理和存储,可以大大提高应用程序的性能;业务逻辑与数据库明确分离,应用程序服务器层可以根据需求进行修改或更新,而不影响数据库层的结构和数据,使得应用程序更容易维护和扩展;客户端层可以使用一个简单的协议来访问应用程序服务器层,如HTTP或SOAP,而不需要知道数据库层的具体细节,如数据库的类型、地址、用户名、密码等,这样可以提高客户端层的安全性和可移植性。[21]

JDBC API

JDBC API由一组类和接口组成,用于管理与数据库的连接、发出查询和命令以及处理从数据库获取的结果集。JDBC API提供了通过Java编程语言进行的通用数据访问,允许用户以相同的编码方式访问任何类型的关系数据库,这意味着用户可以使用相同的编码开发一个程序来访问SQL Server数据库或Oracle数据库,或者不修改编码的MySQL数据库[22]

JDBC API中定义的类及其功能:

类功能DriverManager处理驱动程序的加载和卸载并建立与数据库的连接DriverPropertyInfo该类中定义的所有方法都用于设置或检索驱动程序的属性,连接对象可以使用这些属性来连接到数据库Type类型类仅用于定义用于标识SQL类型的常量Date该类包含执行SQL日期格式和Java日期对象转换的方法Time该类与Date类类似,包含SQL时间和Java时间对象之间转换的方法TimeStamp该类通过添加纳秒字段为Java日期对象提供额外的精度

参考来源:[23]

其中,DriverManager、DriverPropertyInfo和Type类在Java数据库编程应用中广泛实现。DriverManager类方法用于访问和调用JDBC驱动程序。[23]

JDBC API中定义的接口:

接口功能Drive驱动程序接口的主要用途是创建连接对象,还可用于JDBC驱动程序元数据的收集和JDBC驱动程序状态检查Connection用于数据库会话的维护和状态监控,还通过使用事务锁定来提供数据访问控制Statement用于执行SQL语句并从ResultSet对象中检索数据PreparedStatement该接口用于执行预编译SQL语句。预编译语句允许更快、更高效的语句执行,更重要的是,它允许运行具有查询参数变化的动态查询。这个接口可以被认为是声明的子类CallableStatement该接口主要用于执行SQL存储过程,支持IN和OUT参数。这个接口可以被认为是声明的子类ResultSetResultSet对象包含行和列格式的查询结果,该接口提供了检索SQL语句执行返回的数据的方法,它还包含SQL数据类型和JDBC数据类型转换的方法ResultSetMetaData该接口包含与最后一个ResultSet对象关联的元数据信息或物理描述的集合DatabaseMetaData该接口包含有关所使用数据库的元数据集合,包括数据库版本、表名、列和支持的函数

参考来源:[23]

这些接口在Java应用程序与数据库的交互中都很流行并广泛实现。[23]

驱动程序

JDBC API定义了Java接口和类,程序员用它们来连接数据库和发送查询。JDBC驱动程序为特定的DBMS厂商实现了这些接口和类。可以认为,JDBC驱动程序在Java应用程序和所需数据库之间架起一座桥梁。使用JDBC API的Java应用程序在实际连接到数据库之前会加载特定DBMS的指定驱动程序。然后,JDBC DriverManager类将所有JDBC API调用发送到加载的驱动程序。[11]

根据配置的不同,JDBC驱动程序可以分为以下四种类型。[24]

JDBC-ODBC Bridge 驱动程序

JDBC-ODBC Bridge驱动程序使用Java的本地方法调用ODBC驱动程序,将JDBC方法调用转换为ODBC函数调用,从而实现与数据库的连接。[24][25][26]

JDBC-ODBC Bridge 驱动程序
JDBC-ODBC Bridge 驱动程序

优点:便于使用;可以轻松连接到任何数据库。[24][26]缺点:由于JDBC方法调用转换为ODBC函数调用,因此性能下降;客户端计算机上需要安装ODBC驱动程序。[24][26]

注意:在 JDBC 4.2中,JDBC-ODBC Bridge已被移除。[27]

网络协议全 Java 驱动程序

网络协议全Java驱动程序使用中间件(应用程序服务器),将JDBC调用直接或间接转换为特定供应商的数据库协议,该驱动程序完全用Java编写。[24][26]

网络协议全 Java 驱动程序
网络协议全 Java 驱动程序

优点基于服务器,客户端计算机上不需要JDBC驱动程序代码;跨平台,完全是Java实现,适合网络应用[24][26]缺点需要在服务器端安装数据库中间层,增加了网络开销和维护成本。[24][26]

本地 API 部分 Java 驱动程序

本地API部分Java驱动程序使用数据库厂商提供的客户端库,将JDBC方法调用转换为数据库API的本机调用,该驱动程序不完全用Java编写。[24][26]

本地 API 部分 Java 驱动程序
本地 API 部分 Java 驱动程序

优点性能较 JDBC-ODBC Bridge驱动程序有所提升。[24][26]缺点需要在客户端安装数据库特定的 API;不跨平台,不完全是Java实现。[24][26]

本地协议全 Java 驱动程序

本地协议全Java驱动程序将JDBC调用直接转换为供应商特定的数据库协议,该驱动程序完全用Java编写。[24][26]

本地协议全 Java 驱动程序
本地协议全 Java 驱动程序

优点比所有其他驱动程序都有更好的性能;客户端或服务器端不需要任何软件。[24][26]缺点驱动程序依赖于数据库,需要针对每种数据库开发不同的驱动程序,不通用。[24][26]

步骤

使用JDBC将Java应用程序与数据库连接需要5个步骤。这些步骤如下:

注册驱动程序

在连接数据库之前,需要为每个数据库加载或注册一次驱动程序,创建与数据库的通信通道。[24]加载驱动程序可以通过两种方式完成:[23]

静态注册:使用Class.forName(driverName)方法,其中 driverName 是驱动程序的全限定类名,如com.mysql.cj.jdbc.Driver;[23]动态注册:使用DriverManager.registerDriver(driver)方法,其中 driver 是驱动程序的实例,如new com.mysql.jdbc.Driver()。[23]

建立连接

getConnection() 方法用于创建一个连接对象,该对象将对应于与数据库的物理连接。可以使用两种方式来实现:[28]

getConnection(URL, username, password):使用三个参数,URL、用户名和密码,如Connection conn = DriverManager.getConnection(url, user, password);[28]getConnection(URL):只有一个参数 URL,该 URL 包含用户名和密码。对于不同的关系数据库,有不同的 JDBC 连接字符串,比如 Oracle 数据库:jdbc:oracle:thin:@HOST_NAME:PORT:SERVICE_NAME。[28]

执行查询

连接建立后,可以使用Connection类的createStatement方法创建Statement对象来执行SQL查询,Statement对象表示SQL语句的接口。例如:Statement stmt = conn.createStatement()。[29]

创建Statement对象后,使用Statement对象的查询方法传入SQL查询语句。Statement对象的查询方法有以下3种:execute()、executeQuery()和executeUpdate(),其中executeQuery()方法用于执行查询语句,返回一个ResultSet对象,表示结果集,如ResultSet rs = stmt.executeQuery(sql)。[29]

处理结果集

当使用 executeQuery() 方法执行查询时,它会返回一个 ResultSet 对象,表示结果集。然后可以使用 ResultSet 对象的方法访问从数据库检索的数据。如使用 ResultSet 对象的 next 方法,遍历结果集:while (rs.next()) { }。[29]

关闭连接

当使用完 Connection 、 Statement 或 ResultSet 对象时,调用其 close 方法以立即释放其正在使用的资源。如依次关闭结果集、语句对象、数据库连接对象:rs.close(); stmt.close(); conn.close()。[29]

这 5 个步骤只是 Java 应用程序连接数据库的一般步骤,如有需要,可以根据实际开发情况进行数据库连接。比如,如果在注册驱动程序前没有导入包,可以使用import java.sql.*导入 java.sql。再比如,使用 try-with-resources 语句自动关闭 Connection、ResultSet 和 Statement 类型的资源,可以避免显式的连接关闭步骤,简化代码。[30]

示例

下面是一个使用JDBC连接MySQL数据库的示例:

// 导入 JDBC 驱动程序包 import java.sql.*; public class JDBCExample { public static void main(String[] args) { // 定义数据库连接的参数 String url = "jdbc:mysql://localhost:3306/school"; // 数据库 URL String user = "user"; // 数据库用户名 String password = "password"; // 数据库密码 // 定义 SQL 查询语句 String sql = "SELECT * FROM student"; // 定义连接、语句和结果集对象 Connection conn = null; Statement stmt = null; ResultSet rs = null; try { // 注册驱动程序 Class.forName("com.mysql.cj.jdbc.Driver"); // 建立连接 conn = DriverManager.getConnection(url, user, password); // 创建语句对象 stmt = conn.createStatement(); // 执行查询 rs = stmt.executeQuery(sql); // 处理结果集 while (rs.next()) { // 从结果集中获取每一列的数据 int id = rs.getInt("id"); // 学生编号 String name = rs.getString("name"); // 学生姓名 int age = rs.getInt("age"); // 学生年龄 String gender = rs.getString("gender"); // 学生性别 // 打印每一条记录 System.out.println("id: " + id + ", name: " + name + ", age: " + age + ", gender: " + gender); } } catch (Exception e) { // 处理异常 e.printStackTrace(); } finally { // 关闭连接 try { if (rs != null) { rs.close(); } if (stmt != null) { stmt.close(); } if (conn != null) { conn.close(); } } catch (SQLException e) { // 处理关闭连接时的异常 e.printStackTrace(); } } } }

执行结果

使用 JDBC API 执行 SQL 语句,返回的可能是结果集、更新计数或输出参数。[23]

SQL 查询结果集

SQL 查询结果集对应于接口 java.sql.ResultSet 的实例对象。ResultSet 对象一般由 Statement、PreparedStatement 或 CallableStatement 对象的 executeQuery() 或 execute() 方法返回。ResultSet 对象不仅记录了查询集结果中的每行数据,同时也记录了各列的类型信息。ResultSet 对象的主要方法有以下几类:[31]

移动光标的方法,用于移动ResultSet对象的光标,指向不同的行,比如 next()、previous()、first()、last() 方法等。获取列值的方法,用于获取当前行的某一列的值,这些值会被转换为指定的 Java 类型,比如getString()、getInt()、getBoolean()、getDouble() 等。更新列值的方法,用于更新当前行的某一列的值,并把这些值设置为指定的 Java 类型,比如updateString()、updateInt()、updateBoolean()、updateDouble() 等。获取元数据的方法,用于获取结果集的元数据,比如列的数量、名称、类型、长度等,比如getMetaData()、getRow()、getType() 等。关闭结果集的方法,close() 方法用于关闭结果集,释放资源。[31]

更新计数

使用 Statement 或 PreparedStatement 对象的 executeUpdate() 方法执行更新语句时,返回结果是一个 int 值,表示更新的行数,这就是更新计数。更新计数可以用来判断 SQL 语句是否执行成功。[31]

输出参数

输出参数是一种特殊的参数,可以用来从存储过程或者函数中返回值,而不是从结果集中返回值。一般由 CallableStatement 对象的 registerOutParameter() 方法输出参数的类型和位置,execute() 方法执行存储过程或者函数,以及使用 getXXX() 方法来获取输出参数的值,其中 XXX 表示输出参数的数据类型,比如getInt()、getString() 等。[32]

输出参数的值可以用来进行逻辑判断、统计或者显示,或者作为其他 SQL 语句的输入参数。一般来说,如果输出参数有值,表示执行成功,如果输出参数没有值,表示执行失败或者没有返回任何值。[32]

参考资料 32

  1. The material in this chapter is based on JDBC tm API Tutorial — [Top] [Prev] [Next] Introduction NOTE
  2. Lesson: JDBC Introduction (The Java? Tutorials > JDBC Database Access) — Documentation
  3. API Documentation — JAVA
  4. SUN SHIPS JDK 1.1 -- JAVABEANS INCLUDED — JAVA
  5. TheJavaCommunityProcess(SM)Program — JAVA Community process
  6. Oracle JDBC — Oracle
  7. Spring Framework — Data Access with JDBC
  8. Hibernate ORM 5.4.33.Final User Guide — Table of Contents
  9. Persistence (Release 7) — Part VIII
  10. IBM Documentation — IBM
  11. IBM Documentation — IBM
  12. A Timeline of Data base History — Quickbase
  13. Linux/UNIX ODBC — What is ODBC?
  14. The material in this chapter is based on JDBC tm API Tutorial — [Top] [Prev] [Next] Introduction NOTE
  15. JDK5.0JavaDatabaseConnectivity(JDBC) — related APIs & Developer Guides -- from Sun Microsystems
  16. Connection interface: JDBC 4.0 features — java.sql.
  17. JDBC 4.1-only features — JAVA
  18. JDBC 4.2 — Java Documentation
  19. Package java.sql — (Java SE 10 & JDK 10 )
  20. JDBC Architecture — The Java? Tutorials > JDBC Database Access > JDBC Introduction
  21. 参考 21
  22. 参考 22
  23. Package java.sql — (Java SE 19 & JDK 19)
  24. About Database Adapters — JDBC Drivers
  25. JDBC-ODBC Bridge — Java SE Documentation
  26. JDBC Driver — javatpoint
  27. Java JDBC API — Java Documentation
  28. Establishing a Connection — The Java? Tutorials > JDBC Database Access > JDBC Basics
  29. Processing SQL Statements with JDBC — The Java? Tutorials > JDBC Database Access > JDBC Basics
  30. The material in this chapter is based on JDBC tm API Tutorial a — [Top] [Prev] [Next] Connection NOTE
  31. The material in this chapter is based on JDBC tm API Tutorial an — [Top] [Prev] [Next] ResultSet NOTE
  32. The material in this chapter is based on JDBC tm API Tut — [Top] [Prev] [Next] CallableStatement NOTE
广告位:底部(ad-bottom)—— 请到中台「公共区块」编辑此内容