前言
Java Database Connectivity简称JDBC,属于Java核心API的一部分,是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口。支持ANSI SQL-92标准,通过调用这些类和接口提供的成员方法,我们可以方便地连接各种不同的数据库,进而使用标准的SQL命令对数据库进行查询、插入、删除、更新等操作。
一、JDBC结构
1.Java程序
主要功能是根据JDBC方法实现对数据库的访问和操作。
主要任务有:请求与数据库建立连接,向数据库发送SQL请求,为结果集定义存储应用和数据类型,查询结果,处理错误,控制传输、提交及关闭连接等。
2.JDBC管理器
即驱动程序管理器,动态地管理和维护数据库查询查询所需要的所有驱动程序对象,实现Java程序与特定驱动程序的连接。
主要任务有:为特定数据库选择驱动程序,处理JDBC初始化调用,为每个驱动程序提供JDBC功能的入口,为JDBC调用执行参数等
3.驱动程序
主要任务:建立与数据库的连接,向数据库发送请求,用户程序请求是执行编译,将错误代码格式化成标准的JDBC错误代码。
编程所使用的数据库系统不同,所需要的驱动程序也有所不同。
4.数据库
按数据结构来存储和管理数据的计算机软件。
常见的数据库比如mysql、Oracle、SqlServer等。
二、JDBC编程的步骤
一次完整的JDBC实现过程分为以下几步:
1、导入包
在程序首部将相关的包导入程序
代码语言:javascript复制import java.sql.*;
2、加载驱动程序
使用Class.forName()
方法来加载相应的驱动程序。不同数据库所需要加载的驱动程序也不同:
// 加载mysql的驱动程序
Class.forName("com.mysql.jdbc.Driver");
//加载oracle的驱动程序
Class.forName("oracle.jdbc.driver.oracleDriver");
3、设置JDBC的连接地址信息
指定JDBC要连接的地址、端口、数据库、用户名、密码等信息
代码语言:javascript复制String username = "root";
String password = "root";
String url = "jdbc:mysql://localhost:3306/test";
// 如果要往表中插入中文,还需要设置编码为utf-8
String url = "jdbc:mysql://localhost:3306/test?seUnicode=true&characterEncoding=utf8";
其中,"jdbc:mysql"是连接协议,“localhost”是连接地址,“3306”是mysql的连接端口(mysql的默认连接端口是3306),“test”是要连接操作的数据库。
4、创建数据库连接
DriverManager 类中的getConnection() 方法用上一步设置好的url作为参数来创建一个连接对象,并返回这个连接对象给Connection的实例。
代码语言:javascript复制//url是上一步创建的连接地址
Connection conn = DriverManager.getConnection(url,username,password);
5、使用SQL语句操作数据库
JDBC中执行SQL语句可以使用Statement接口以及其子接口PreparedStatement接口,下面分别使用不同接口来举例简单说明其用法:
5.1.Statement接口方法创建表:
代码语言:javascript复制/**
* 例子:Statement接口执行创建表,并且插入一组数据
*/
// 在当前数据库下创建一个学生表,表中包含主键字段id、姓名name、以及更新时间updatetime
String sql1 = "create table student(id int NOT NULL AUTO_INCREMENT primary key,name char(10),updateTime Datetime)";
// 向创建的student表添加一组信息
String sql2 = "insert into student(name,updatetime) values('qwe',sysdate())";
// 创建一个Statement对象
Statement st = conn.createStatement();
// 用executeUpdate()函数执行不返回任何内容的sql语句,如INSERT、UPDATE、DELETE以及其他DDL(数据定义语言)等。其参数为SQL语句
// 执行建表SQL语句
st.executeUpdate(sql1);
// execute()函数可以执行传进来的任意SQL语句
// 执行插入数据的SQL语句
st.execute(sql2);
// 释放资源
st.close();
5.2.PreparedStatement接口:
代码语言:javascript复制/**
* 例子:PreparedStatement接口执行查询表中数据的SQL语句
*/
String sql3 = "select * from student";
// 创建一个PreparedStatement对象,同时对传入的SQL语句进行预编译
PreparedStatement ps = conn.prepareStatement(sql3);
// PreparedStatement接口中的execute()方法是没有参数的,因为SQL语句在创建对象时已传入并且预编译了
ResultSet result = ps.executeQuery();
while(rs.next()){
// 通过索引来获取查询到的值
int id = rs.getInt(1);
String name = rs.getString(2);
// 通过列名来获取查询到的值
Date date = rs.getDate("updateTime");
}
// 释放资源
ps.close();
6、关闭连接
用完就要释放所连接的数据库及JDBC资源,关闭与数据库的连接
代码语言:javascript复制conn.close();
上面就是是JDBC编程的基本流程,下面对这个过程中涉及到的一些类与方法做简单介绍:
三、相关的类与方法
1、DriverManager类 ——管理驱动
用于管理一组JDBC驱动程序的基本服务。
官方文档介绍:DriverManager (Java Platform SE 8 ) (langp.wang)
其常用成员方法如下:
返回值 | 方法体 | 说明 |
---|---|---|
static Connection | getConnection(String url) | 用指定的数据库URL来创建连接 |
static Connection | getConnection(String url, Properties info) | 用指定的数据库URL和相关信息(用户名、用户密码等属性列表)来创建连接 |
static Connection | getConnection(String url, String user, String password) | 用指定的数据库URL、用户名和用户密码来创建连接 |
static Driver | getDriver(String url) | 定位在给定URL下的驱动程序。 DriverManager尝试从已注册的JDBC驱动程序集中选择适当的驱动程序。 |
static void | deregisterDriver(Driver driver) | 从DriverManager的已注册驱动程序列表中删除指定的驱动程序。 |
static void | println(String message) | 将消息输出到当前JDBC日志流。 |
static void | setLoginTimeout(int seconds) | 驱动程序尝试连接数据库时将等待的最长时间,以秒为单位。 |
2、Connection接口 ——建立连接
负责建立与指定数据库的连接。
默认情况下,Connection对象处于自动提交模式,这意味着它在执行每个语句后自动提交更改。 如果禁用了自动提交模式,则必须显式调用方法commit()方法才能提交更改;否则,将不会保存数据库更改。
官方文档介绍: Connection (Java Platform SE 8 ) (langp.wang)
其常用成员方法如下:
返回值 | 方法体 | 说明 |
---|---|---|
Statement | createStatement() | 创建一个Statement对象,用于将SQL语句发送到数据库。 |
PreparedStatement | prepareStatement(String sql) | 创建一个PreparedStatement对象,用于将参数化的SQL语句发送到数据库。 |
void | close() | 立即释放此Connection对象的数据库和JDBC资源,而不是等待它们自动释放。 |
void | commit() | 使自上一次提交/回退以来进行的所有更改永久生效,并释放此Connection对象当前持有的所有数据库锁。 |
void | rollback() | 撤销对数据库执行的添加、删除或者修改记录等操作,并释放此Connection对象当前持有的所有数据库锁。 |
3、Statement接口 ——执行SQL语句
用于执行静态SQL语句并返回其产生的结果的对象。
默认情况下,每个Statement对象只能同时打开一个ResultSet对象。 因此,如果一个ResultSet对象的读取与另一个的读取交错,则每个都必须由不同的Statement对象生成。 如果当前存在打开的语句,Statement接口中的所有执行方法都会隐式关闭该语句的当前ResultSet对象。
官方文档介绍: Statement (Java Platform SE 8 ) (langp.wang)
其常用成员方法如下:
返回值 | 方法体 | 说明 |
---|---|---|
Connection | getConnection() | 检索产生此Statement对象的Connection对象 |
void | close() | 立即释放此Statement对象的数据库和JDBC资源,而不是在自动关闭时等待它发生 |
boolean | execute(String sql) | 执行给定的SQL语句,该语句可能返回多个结果 |
ResultSet | executeQuery(String sql) | 执行给定的SQL语句,该语句返回一个ResultSet对象 |
int | executeUpdate(String sql) | 执行给定的SQL语句,该语句可以是INSERT,UPDATE或DELETE语句,也可以是不返回任何内容的SQL语句,例如SQL DDL语句 |
ResultSet | getResultSet() | 以ResultSet对象的形式检索当前结果 |
executeUpdate()
、executeQuery()
与execute()
方法的区别:
- execute()函数:可以执行所有SQL语句。 当执行查询语句时,返回的boolean值指示查询结果的形式,返回值为true时表示查询结果为ResultSet,反之为false(即认为没有查到);执行其他语句时,如果第一个结果是更新计数或不存在任何结果,则返回false
- executeUpdate():执行insert、update、delete等不返回任何内容的非查询语句。
- executeQuery():用于执行select语句。返回一个ResultSet对象,其中包含由给定查询产生的数据; 永不为空
4、PreparedStatement接口 ——执行SQL语句
表示预编译的SQL语句的对象。是Statement的子接口。
创建PreparedStatement对象时需传入一个SQL语句,该SQL语句已预编译并存储在PreparedStatement对象中。然后可以使用该对象多次有效地执行该语句。
官方文档介绍: PreparedStatement (Java Platform SE 8 ) (langp.wang)
其常用成员方法如下:
返回值 | 方法体 | 说明 |
---|---|---|
boolean | execute() | 在此PreparedStatement对象中执行SQL语句,可以是任何类型的SQL语句 |
ResultSet | executeQuery() | 在此PreparedStatement对象中执行SQL查询,并返回查询生成的ResultSet对象 |
int | executeUpdate() | 在此PreparedStatement对象中执行SQL语句,该对象必须是SQL数据操作语言(DML)语句,例如INSERT,UPDATE或DELETE; 或不返回任何内容的SQL语句,例如DDL语句 |
5、ResultSet接口 ——存放查询之后返回的结果
表示数据库结果集的数据表,通常通过执行查询数据库的语句来生成。
ResultSet对象有一个游标,该游标指向其当前数据行。 最初,光标位于第一行之前。next()方法可将光标移动到下一行,当ResultSet对象中没有更多行时它将返回false,因此可以在while循环中使用它来迭代结果集。例如:
代码语言:javascript复制// 假设rs是前面进行查询操作返回的ResultSet对象
while(rs.next()){
// 输出结果
}
用next()方法可以实现访问每一个数据行,那么如何获取数据行中的每一列数据呢?ResultSet接口提供了用于从当前行中检索列值的getter方法,方法名是get 类型,如getBoolean(),getInt()。
getter方法的参数可以是列的索引值或者列的名称,对应的是用索引或者列名来从当前数据行中检索列值。
通常,使用列索引会更有效。 列从1开始编号。为实现最大的可移植性,应按从左到右的顺序读取每一行中的结果集列,并且每一列只能读取一次。
getter方法用列名检索时传入的列名称不区分大小写。 当多个列具有相同的名称时,将返回第一个匹配列的值。 对于在查询中未明确命名的列,最好使用列的索引。 如果使用了列名,则应注意确保它们唯一地引用了预期的列,这可以通过SQL AS子句来确保。
例如:
代码语言:javascript复制// 假设rs是前面进行查询操作返回的ResultSet对象
while(rs.next()){
// 使用索引来检索
int id = rs.getInt(1);
// 使用列的名称来检索
String name = rs.getString("name");
// 且列名不区分大小写
Date updateTime = rs.getDate("UPDATETIME");
}
官方文档介绍: ResultSet (Java Platform SE 8 ) (langp.wang)
其常用成员方法如下:
返回值 | 方法体 | 说明 |
---|---|---|
boolean | absolute(int row) | 将光标移动到此ResultSet对象中的给定行号 |
boolean | first() | 将光标移动到此ResultSet对象的第一行 |
void | beforeFirst() | 将光标移动到此ResultSet对象的前面,紧挨着第一行 |
boolean | isFirst() | 检索光标是否在此ResultSet对象的第一行上 |
boolean | last() | 将光标移动到此ResultSet对象的最后一行 |
void | afterLast() | 将光标移动到此ResultSet对象的末尾,紧接在最后一行之后 |
boolean | isLast() | 检索光标是否在此ResultSet对象的最后一行 |
boolean | next() | 将光标从当前位置向前移动一行 |
void | insertRow() | 将插入行的内容插入到此ResultSet对象和数据库中 |
void | updateRow() | 使用此ResultSet对象的当前行的新内容更新底层数据库 |
void | deleteRow() | 从此ResultSet对象和底层数据库中删除当前行 |
void | update类型(int ColumnIndex,类型 x) | 使用给定类型x更新指定列 |
int | get类型(int ColumnIndex) | 以Java类型的形式获取此ResultSet的对象的当前行中指定列的值 |
主要参考资料: 《数据库系统概论(第5版)》 王珊 萨师煊 编著 Java SE 1.8 官方文档