数据库系统由数据库、数据库管理系统和应用系统、数据库管理员构成。数据库管理系统简称DBMS,是数据库系统的关键组成部分,包括数据库定义、数据查询、数据维护等。JDBC技术是连接数据库与应用程序的纽带,开发一款应用程序,需要使用数据库来保存数据,使用JDBC技术可以快速地访问和操作数据库,如查找满足条件的记录,向数据库中添加、修改、删除数据等。
19.1 数据库基础知识
19.1.1 什么是数据库
数据库是一种存储结构,它允许使用各种格式输入、处理和检索数据,不必在每次需要数据时重新输入。
数据库的主要特点:
1. 实现数据共享;
2. 减少数据的冗余度;
3. 数据的独立性;
4. 数据实现集中控制;
5. 数据的一致性和可维护性,以确保数据的安全性和可靠性,主要包括:
1) 安全性控制,以防止数据丢失、错误更新和越权使用;
2) 完整性控制,保证数据的正确性、有效性和相容性;
3) 并发控制,使在同一时间周期内,允许对数据实现多路存取,又能防止用户之间的不正常交互作用;
4) 故障的发现和恢复。
数据库的基本结构分为3个层次:
1. 物理数据层
是数据库的最内层,是物理存储设备上实际存储的数据集合,这些数据是原始数据,是用户加工的对象,由内部模式描述的指令操作处理的字符和字组成。
2. 概念数据层
是数据库的中间一层,是数据库的整体逻辑表示,指出了每个数据的逻辑定义及数据间的逻辑联系,是存储记录的集合。它所涉及的是数据库所有对象的逻辑关系,而不是它们的物理情况,是数据库管理员概念下的数据库。
3. 逻辑数据层
是用户所看到和使用的数据库,是一个或一些特定用户使用的数据集合,即逻辑记录的集合。
19.1.2 数据库的种类及功能
数据库系统一般基于某种数据模型,可以分为层次型、网状型、关系型及面向对象型等。
1. 层次性数据库
类似于树结构,是一组通过链接而相互联系在一起的记录,特点是记录之间的联系通过指针实现。由于层次模型层次顺序严格而且复杂,因此对数据进行各项操作都很困难。
2. 网状型数据库
网络模型是使用网络结构表示实体类型、实体间联系的数据模型。网络模型容易实现多对多的联系,但在编写应用程序时,需要熟悉数据库的逻辑结构。
3. 面向对象型数据库
建立在面向对象模型基础上。
4. 关系型数据库
是基于关系模型建立的数据库,由一系列表格组成。
从JDK 6开始,在JDK的安装目录中,除了传统的bin、jre等目录,还新增了名为db的目录,这便是Java DB,这是一个纯Java实现的、开源的数据库管理系统(DBMS),源于Apache软件基金会(ASF)名下的项目Derby,只有2MB大小。
19.1.3 SQL语言
SQL(Structure Query Language,结构化查询语言)主要包含以下4部分:
1. 数据定义语言(Data Definition Language,DDL),如create、alter、drop等
2. 数据操作语言(Data Manipulation Language,DML),如select、insert、update、delete等
3. 数据控制语言(Data Control Language,DCL),如grant、revoke等
4. 事务控制语言(Transaction Control Language,TCL),如commit、rollback等
数据操作语言的相关语句:
1. select语句:从数据表中检索数据
语法:
select 所选字段列表 from 数据表名 where 条件表达式 group by 字段名 having 条件表达式(指定分组的条件) order by 字段名[asc|desc]
2. insert语句:向表中插入新数据
语法:
insert into 表名[(字段名1, 字段名2, ...)] values(属性值1, 属性值2, ...)
3. update语句:更新数据表中的某些记录
语法:
update 数据表名 set 字段名 = 新的字段值 where 条件表达式
4. delete语句:删除数据
语法:
delete from 数据表名 where 条件表达式
19.2 JDBC概述
JDBC是一种可用于执行SQL语句的Java API,是连接数据库和Java应用程序的接口。
19.2.1 JDBC-ODBC桥
JDBC-ODBC桥是一个JDBC驱动程序,完成了从JDBC操作到ODBC操作之间的转换工作,允许JDBC驱动程序被用作ODBC的驱动程序。
使用JDBC-ODBC桥连接数据库的步骤:
1. 加载JDBC-ODBC桥的驱动程序
代码语言:javascript复制Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”);
2. 使用java.sql包中的Connection接口,并通过DriverManager类的静态方法getConnection()创建连接对象
代码语言:javascript复制Connection conn = DriverManager.getConnection(“jdbc:odbc:数据源名字”, “user name”, “password”);
3. 向数据库发送SQL语句
代码语言:javascript复制Statement sql = conn.createStatement();
JDBC-ODBC桥作为连接数据库的过渡性技术,现已经不被Java广泛应用了,现被广泛应用的是JDBC技术。由于ODBC技术被广泛地使用,使得Java可以利用JDBC-ODBC桥访问几乎所有的数据库,JDBC-ODBC桥作为sun.jdbc.odbc包与JDK一起自动安装,不需要特殊配置。
19.2.2 JDBC技术
JDBC的全称是Java DataBase Connectivity,是一套面向对象的应用程序接口,指定了统一的访问各种关系型数据库的标准接口。
JDBC技术主要完成以下3个任务:
1. 与数据库建立一个连接;
2. 向数据库发送SQL语句;
3. 处理从数据库返回的结果。
注:JDBC不能直接访问数据库,必须依赖于数据库厂商提供的JDBC驱动程序。
19.2.3 JDBC驱动程序的类型
JDBC的总体结构由4个组件——应用程序、驱动程序管理器、驱动程序和数据源组成。
JDBC驱动基本上分为4种:
1. JDBC-ODBC桥
依靠ODBC驱动器和数据库通信,这种连接方式必须将ODBC二进制代码加载到使用该驱动程序的每台客户机上。这种类型的驱动程序最适合于企业网或者用Java编写的三层结构的应用程序服务器代码。
2. 本地API一部分用Java编写的驱动程序
这类驱动程序把客户机的API上的JDBC调用转换为Oracle、DB2、Sybase或其他DBMS的调用,这种驱动程序也需要将某些二进制代码加载到每台客户机上。
3. JDBC网络驱动
这种驱动程序将JDBC转换为与DBMS无关的网络协议,又被某个服务器转换为一种DBMS协议,是一种利用Java编写的JDBC驱动程序,也是最灵活的JDBC驱动程序。这种方案的提供者提供了适合于企业内部互联网用的产品,为使这种产品支持Internet访问,需要处理Web提出的安全性、通过防火墙的访问等额外的要求。
4. 本地协议驱动
这是一种纯Java的驱动程序,这种驱动程序将JDBC调用直接转换为DBMS所使用的网络协议,允许从客户机上直接调用DBMS服务器,是一种很实用的访问Intranet的解决方法。
注:JDBC网络驱动和本地协议驱动是JDBC访问数据库的首选。
19.3 JDBC中常用的类和接口
19.3.1 Connection接口
Connection接口代表与特定的数据库的连接,在连接上下文中执行SQL语句并返回结果。
Connection接口的常用方法:
19.3.2 Statement接口
Statement接口用于在已经建立连接的基础上向数据库发送SQL语句。在JDBC中有3种Statement对象,分别是Statement、PreparedStatement和CallableStatement。Statement对象用于执行不带参数的简单的SQL语句;PreparedStatement继承了Statement,用来执行动态的SQL语句;CallableStatement继承了PreparedStatement,用于执行对数据库的存储过程的调用。
Statement接口中常用的方法:
1.3.3 PreparedStatement接口
PreparedStatement接口用来动态地执行SQL语句,通过PreparedStatement实例执行的动态SQL语句,将被预编译并保存到PreparedStatement实例中,从而可以反复地执行该SQL语句。
PreparedStatement接口的常用方法:
19.3.4 DriverManager类
DriverManager类用来管理数据库中的所有驱动程序,它是JDBC的管理层,作用于用户和驱动程序之间,跟踪可用的驱动程序,并在数据库的驱动程序之间建立连接。如果通过getConnection()方法可以建立连接,则经连接返回,否则抛出SQLException异常。
DriverManager类的常用方法:
19.3.5 ResultSet接口
ResultSet接口类似于一个临时表,用来暂时存放数据库查询操作所获得的结果集。ResultSet实例具有指向当前数据行的指针,指针开始的位置在第一条记录的前面,通过next()方法可将指针向下移。
在JDBC 2.0(JDK 1.2)之后,该接口添加了一组更新方法updateXXX(),该方法有两个重载方法,可根据列的索引号和列的名称来更新指定列。但该方法并没有将对数据进行的操作同步到数据库中,需要执行updateRow()或insertRow()方法更新数据库。
ResultSet接口提供的常用方法:
19.4 数据库操作
19.4.1 连接数据库
要访问数据库,首先要加载数据库的驱动程序(只需要在第一次访问数据库时加载一次),然后每次访问数据时创建一个Connection对象,接着执行操作数据库的SQL语句,最后在完成数据库操作后销毁前面创建的Connection对象,释放与数据库的连接。
代码语言:javascript复制package core;
import java.sql.*;
public class Conn {
Connection con;
public Connection getConnection() {
try {
Class.forName("com.mysql.cj.jdbc.Driver");//加载数据驱动程序
System.out.println("数据库驱动加载成功");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
//con = DriverManager.getConnection("jdbc:mysql://localhost:3306/chenxiaohuan?serverTimezone=UTC","root","123456");
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/chenxiaohuan","root","123456");
System.out.println("数据库连接成功");
} catch(SQLException e) {
e.printStackTrace();
}
return con;
}
public static void main(String[] args) {
Conn c = new Conn();
c.getConnection();
}
}
运行结果:
19.4.2 向数据库发送SQL语句
要执行SQL语句首选要获得Statement类对象:
代码语言:javascript复制Statement sql = con.createStatement();
19.4.3 处理查询结果集
有了Statement对象后,可调用相应的方法实现对数据库的查询和修改,并将查询的结果集存放在ResultSet类的对象中:
代码语言:javascript复制ResultSet res = sql.executeQuery(“select * from tb_stu”);
1.4.4 顺序查询
代码语言:javascript复制package core;
import java.sql.*;
public class Gradation {
static Connection con;
static Statement sql;
static ResultSet res;
public Connection getConnection() {
try {
Class.forName("com.mysql.cj.jdbc.Driver");//加载数据驱动程序
System.out.println("数据库驱动加载成功");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
//con = DriverManager.getConnection("jdbc:mysql://localhost:3306/chenxiaohuan?serverTimezone=UTC","root","123456");
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/chenxiaohuan","root","123456");
System.out.println("数据库连接成功");
} catch(SQLException e) {
e.printStackTrace();
}
return con;
}
public static void main(String[] args) {
Gradation c = new Gradation();
c.getConnection();
try {
sql = con.createStatement();
res = sql.executeQuery("select * from tb_stu");
while(res.next()) {
String id = res.getString("id");
String name = res.getString("name");
String sex = res.getString("sex");
System.out.print("编号:" id);
System.out.print(" 姓名:" name);
System.out.println(" 性别:" sex);
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
运行结果:
19.4.5 模糊查询
SQL语句中提供了LIKE操作符用于模糊查询,可使用“%”来代替0个或多个字符,使用下划线“_”来代替一个字符,例如:
代码语言:javascript复制select * from tb stu where name link ‘张%’
19.4.6 预处理语句
向数据库发送一个SQL语句,数据库中的SQL解释器负责把SQL语句生成底层的内部命令,然后执行该命令,完成相关的数据操作。如果不断地向数据库提交SQL语句,会增加数据库中SQL解释器的负担,影响执行的速度。
对于JDBC,可以通过Connection对象的PreparedStatement(String sql)方法对SQL语句进行预处理,生成数据库底层的内部命令,即应用程序能针对连接的数据库,将SQL语句解释为数据库底层的内部命令,然后让数据库执行这个命令,这样可以减轻数据库的负担,提高访问数据库的速度。
对SQL进行预处理时可以使用通配符“?”来代替任何的字段值,例如:
代码语言:javascript复制sql = con.preparedStatement(“select * from tb_stu where id = ?”);
在执行预处理语句前,必须用相应的方法来设置通配符所表示的值,例如:
代码语言:javascript复制sql.setInt(1,2);
上述语句中1表示从左向右的第1个通配符,2表示设置的通配符的值。