关系数据库概述
数据库是以一种可以从中检索信息的方式存储信息的方法。用最简单的术语来说,关系数据库是一种在具有行和列的表中呈现信息的数据库。从某种意义上说,表是关系的集合,它是相同类型(行)的对象的集合。表中的数据可以根据通用键或概念进行关联,并且从表中检索相关数据的能力是术语关系数据库的基础。数据库 管理 系统(DBMS)处理数据的存储,维护和检索方式。对于关系数据库,关系数据库 管理 系统(RDBMS)执行这些任务。本书中使用的 DBMS 是一个通用术语,其中包括 RDBMS。
Integrity Rules
关系表遵循某些完整性规则,以确保其中包含的数据保持准确并始终可访问。首先,关系表中的行应全部不同。如果存在重复的行,则可能无法解决两个可能的选择中的一个是正确的选择。对于大多数 DBMS,用户可以指定不允许重复的行,如果这样做,则 DBMS 将阻止添加任何与现有行重复的行。
传统关系模型的第二个完整性规则是,列值一定不能是重复的组或数组。数据完整性的第三个方面涉及空值的概念。数据库通过使用空值指示缺少值来处理数据可能不可用的情况。它不等于空白或零。一个空白被视为等于另一个空白,一个零等于另一个零,但两个空值不被视为相等。
当表中的每一行都不同时,可以使用一个或多个列来标识特定行。此唯一列或一组列称为主键。属于主键的任何列都不能为 null。如果是这样,则包含它的主键将不再是完整的标识符。此规则称为实体完整性。
Employees
表说明了其中一些关系数据库概念。它有五列和六行,每行代表一个不同的员工。
Employees
表*
Employee_Number | First_name | Last_Name | Date_of_Birth | Car_Number |
---|---|---|---|---|
10001 | John | Washington | 28-Aug-43 | 5 |
10083 | Arvid | Sharma | 24-Nov-54 | null |
10120 | Jonas | Ginsberg | 01-Jan-69 | null |
10005 | Florence | Wojokowski | 04-Jul-71 | 12 |
10099 | Sean | Washington | 21-Sep-66 | null |
10035 | Elizabeth | Yamaguchi | 24-Dec-59 | null |
该表的主键通常是员工号,因为保证每个人都不同。 (进行比较时,数字也比字符串 更有效.)也可以使用First_Name
和Last_Name
,因为两者的组合也只能标识示例数据库中的一行。仅使用姓氏是行不通的,因为有两个员工的姓氏为“ Washington”。在这种特殊情况下,名字全都不同,因此可以想象使用该列作为主键,但是最好避免使用可能发生重复的列。如果 Elizabeth Jones 在这家公司找到工作并且主键是First_Name
,则 RDBMS 将不允许添加她的名字(如果已指定不允许重复)。因为表中已经有一个伊丽莎白,所以添加第二个伊丽莎白会使主键无用,因为它只能识别一行。请注意,尽管对于此示例,使用First_Name
和Last_Name
是唯一的复合键,但在较大的数据库中可能并非唯一。另请注意,Employees
表假定每个员工只能有一辆汽车。
SELECT 语句
SQL 是一种设计用于关系数据库的语言。有一组被认为是标准的基本 SQL 命令,并且所有 RDBMS 都使用这些命令。例如,所有 RDBMS 都使用SELECT
语句。
SELECT
语句(也称为查询)用于从表中获取信息。它指定一个或多个列标题,要从中选择的一个或多个表以及一些选择条件。 RDBMS 返回满足规定要求的列条 Object 行。诸如此类的SELECT
语句将获取拥有公司汽车的员工的名字和姓氏:
SELECT First_Name, Last_Name
FROM Employees
WHERE Car_Number IS NOT NULL
结果集(满足Car_Number
列中不包含 null 的要求的行集)如下。因为SELECT
语句(第一行)指定了First_Name
和Last_Name
列,所以满足要求的每一行都会打印出名字和姓氏。 FROM
子句(第二行)提供了从中选择列的表。
FIRST_NAME | LAST_NAME |
---|---|
John | Washington |
Florence | Wojokowski |
下面的代码生成的结果集包含整个表,因为它要求无限制(没有WHERE
子句)的表 employees 中的所有列。请注意,SELECT *
表示“ SELECT
所有列”。
SELECT *
FROM Employees
WHERE Clauses
SELECT
语句中的WHERE
子句提供了选择值的条件。例如,在以下代码段中,仅当值出现在列Last_Name
以字符串“华盛顿”开头的行中时,才选择值。
SELECT First_Name, Last_Name
FROM Employees
WHERE Last_Name LIKE 'Washington%'
关键字LIKE
用于比较字符串,它具有可以使用包含通配符的 Pattern 的功能。例如,在上面的代码片段中,“华盛顿”的末尾有一个百分号(%
),表示任何包含字符串“华盛顿”加上零个或多个其他字符的值都将满足此选择条件。因此,“华盛顿”或“华盛顿”将是匹配项,但“洗涤”将不是匹配项。 LIKE
子句中使用的另一个通配符是下划线(_
),代表任何一个字符。例如,
WHERE Last_Name LIKE 'Ba_man'
会匹配“ Barman”,“ Badman”,“ Balman”,“ Bagman”,“ Bamman”等。
下面的代码片段包含一个WHERE
子句,该子句使用等号(=
)比较数字。它选择分配了汽车 12 的员工的名字和姓氏。
SELECT First_Name, Last_Name
FROM Employees
WHERE Car_Number = 12
下一个代码片段选择员工号大于 10005 的员工的名字和姓氏:
SELECT First_Name, Last_Name
FROM Employees
WHERE Employee_Number > 10005
WHERE
子句可以很复杂,有多个条件,在某些 DBMS 中有嵌套条件。本概述不会涵盖复杂的WHERE
子句,但是下面的代码片段具有一个WHERE
子句,其中有两个条件。此查询选择雇员姓名小于 10100 且没有公司汽车的雇员的名字和姓氏。
SELECT First_Name, Last_Name
FROM Employees
WHERE Employee_Number < 10100 and Car_Number IS NULL
WHERE
子句是一种特殊的类型,它涉及联接,下一节将对此进行说明。
Joins
关系数据库的一个显着 Feature 是,可以从称为联接的多个表中获取数据。假设在检索了拥有公司汽车的雇员的姓名之后,一个人想要找出谁拥有哪辆汽车,包括车牌号,里程和车龄。此信息存储在另一个表Cars
中:
Cars
表*
Car_Number | License_Plate | Mileage | Year |
---|---|---|---|
5 | ABC123 | 5000 | 1996 |
12 | DEF123 | 7500 | 1999 |
两个表中必须存在一列,以便将它们彼此关联。该列必须是一个表中的主键,在另一表中称为外键。在这种情况下,出现在两个表中的列是Car_Number
,这是表Cars
的主键和表Employees
的外键。如果 1996 年车牌号为 ABC123 的汽车被撞毁并从Cars
表中删除,则也必须从Employees
表中删除Car_Number
5,以保持所谓的参照完整性。否则,Employees
表中的外键列(Car_Number
)将包含一个未引用Cars
表中任何内容的条目。外键必须为 null 或等于它所引用表的现有主键值。这不同于主键,主键不能为空。表Employees
的Car_Number
列中有几个空值,因为员工可能没有公司的车。
以下代码要求拥有公司汽车的雇员的名字和姓氏,以及这些汽车的车牌号,里程和年份。请注意,FROM
子句同时列出了Employees
和Cars
表,因为请求的数据都包含在两个表中。使用表名和列名前的点(.
)指示哪个表包含该列。
SELECT Employees.First_Name, Employees.Last_Name,
Cars.License_Plate, Cars.Mileage, Cars.Year
FROM Employees, Cars
WHERE Employees.Car_Number = Cars.Car_Number
这将返回一个类似于以下内容的结果集:
FIRST_NAME | LAST_NAME | LICENSE_PLATE | MILEAGE | YEAR |
---|---|---|---|---|
John | Washington | ABC123 | 5000 | 1996 |
Florence | Wojokowski | DEF123 | 7500 | 1999 |
常用 SQL 命令
SQL 命令分为几类,主要的两个是数据操作语言(DML)命令和数据定义语言(DDL)命令。 DML 命令处理数据,可以检索数据或对其进行修改以使其保持最新状态。 DDL 命令创建或更改表以及其他数据库对象,例如视图和索引。
以下是更常见的 DML 命令的列表:
-
SELECT —
用于查询和显示数据库中的数据。SELECT
语句指定要包含在结果集中的列。应用程序中使用的绝大多数 SQL 命令都是SELECT
语句。 -
INSERT —
将新行添加到表中。INSERT
用于填充新创建的表或向现有表添加新的一行。 -
DELETE —
从表中删除指定的一行或一组行 -
UPDATE —
更改表中一列或一组列中的现有值
更常见的 DDL 命令如下:
-
CREATE TABLE —
使用用户提供的列名创建一个表。用户还需要为每一列中的数据指定一种类型。数据类型从一个 RDBMS 到另一个 RDBMS,所以用户可能需要使用元数据来构建特定数据库使用的数据类型。通常,CREATE TABLE
的使用频率比数据操作命令要少,这是因为表仅创建一次,而添加或删除行或更改单个值通常会更频繁地发生。 -
DROP TABLE —
删除所有行,并从数据库中删除表定义。需要一个 JDBC API 实现来支持 SQL92 过渡级别所指定的 DROP TABLE 命令。但是,对DROP TABLE
的CASCADE
和RESTRICT
选项的支持是可选的。此外,当定义了引用要删除的表的视图或完整性约束时,DROP TABLE
的行为由实现定义。 -
ALTER TABLE —
从表中添加或删除列。它还添加或删除表约束并更改列属性
结果集和游标
满足查询条件的行称为结果集。结果集中返回的行数可以为零,一或很多。用户可以一次访问一行结果集中的数据,而游标提供了这样做的手段。游标可被视为指向包含结果集各行的文件的指针,并且该指针具有跟踪当前正在访问的行的能力。游标允许用户从上到下处理结果集的每一行,因此可以用于迭代处理。大多数 DBMS 在生成结果集时会自动创建一个游标。
较早的 JDBC API 版本为结果集的游标添加了新功能,从而使其可以向前和向后移动,还可以将其移动到指定的行或位置相对于另一行的行。
有关更多信息,请参见从结果集中检索和修改值。
Transactions
当一个用户访问数据库中的数据时,另一用户可能同时访问同一数据。例如,如果第一位用户正在同时更新表中的某些列,而第二位用户正在从同一表中选择列,则第二位用户有可能获得部分旧数据和部分更新数据。因此,DBMS 使用事务将数据维持在一致状态(数据一致性),同时允许多个用户同时访问数据库(数据并发)。
事务是组成逻辑工作单元的一组一个或多个 SQL 语句。事务以提交还是回滚结束,具体取决于数据一致性或数据并发性是否存在问题。 commit 语句使事务中的 SQL 语句导致的更改永久生效,而 rollback 语句撤消事务中的 SQL 语句导致的所有更改。
锁是一种机制,它禁止两个事务同时处理相同的数据。例如,如果表锁上有未提交的事务,则表锁可防止该表被删除。在某些 DBMS 中,表锁还锁定表中的所有行。行锁可防止两个事务修改同一行,或者防止一个事务选择一行而另一事务仍在修改它。
有关更多信息,请参见Using Transactions。
Stored Procedures
存储过程是一组可以按名称调用的 SQL 语句。换句话说,它是可执行代码,是一个微型程序,它执行特定的任务,可以像调用函数或方法一样调用该任务。传统上,存储过程是使用 DBMS 特定的编程语言编写的。最新一代的数据库产品允许使用 Java 编程语言和 JDBC API 编写存储过程。用 Java 编程语言编写的存储过程是 DBMS 之间可移植的字节码。编写存储过程后,就可以使用和重用它,因为支持存储过程的 DBMS 顾名思义会将其存储在数据库中。有关编写存储过程的信息,请参见使用存储过程。
Metadata
数据库存储用户数据,并且它们还存储有关数据库本身的信息。大多数 DBMS 都有一组系统表,这些系统表列出了数据库中的表,每个表中的列名,主键,外键,存储过程等。每个 DBMS 都有其自己的功能来获取有关表布局和数据库功能的信息。 JDBC 提供了interfaceDatabaseMetaData
,驱动程序编写者必须实现该interfaceDatabaseMetaData
,以便其方法返回有关驱动程序和/或为其编写驱动程序的 DBMS 的信息。例如,大量方法返回驱动程序是否支持特定功能。该interface为用户和工具提供了一种获取元数据的标准化方法。通常,编写工具和驱动程序的开发人员最可能与元数据有关。