关系数据库概述

原文: https://docs.oracle.com/javase/tutorial/jdbc/overview/database.html

数据库是一种以可以从中检索信息的方式存储信息的方法。简单来说,关系数据库是在包含行和列的表中显示信息的数据库。表在某种意义上被称为关系,它是相同类型(行)的对象的集合。表中的数据可以根据公共密钥或概念进行关联,并且从表中检索相关数据的能力是术语关系数据库的基础。数据库管理系统(DBMS)处理数据的存储,维护和检索方式。对于关系数据库,关系数据库管理系统(RDBMS)执行这些任务。本书中使用的 DBMS 是包含 RDBMS 的通用术语。

关系表遵循某些完整性规则,以确保它们包含的数据保持准确并始终可访问。首先,关系表中的行应该都是不同的。如果存在重复行,则可能存在解决两个可能选择中的哪一个是正确选择的问题。对于大多数 DBMS,用户可以指定不允许重复行,如果这样做,DBMS 将阻止添加任何复制现有行的行。

传统关系模型的第二个完整性规则是列值不能是重复的组或数组。数据完整性的第三个方面涉及空值的概念。数据库通过使用空值来指示缺少值,从而处理数据可能不可用的情况。它不等于空白或零。空白被认为等于另一个空白,零等于另一个零,但两个空值不被认为是相等的。

当表中的每一行不同时,可以使用一列或多列来标识特定行。此唯一列或列组称为主键。作为主键一部分的任何列都不能为空;如果是,则包含它的主键将不再是完整的标识符。此规则称为实体完整性。

Employees表说明了其中一些关系数据库概念。它有五列六行,每行代表不同的员工。

Employees Table | Employee_Number | First_name | Last_Name | Date_of_Birth | Car_Number | | —- | —- | —- | —- | —- | | 10001 | 约翰 | 华盛顿 | 28 - 8 - 43 | 五 | | 10083 | 阿维德 | 夏尔马 | 24-NOV-54 | 空值 | | 10120 | 乔纳斯 | 金斯伯格 | 01-JAN-69 | 空值 | | 10005 | 佛罗伦萨 | Wojokowski | 04 - 07 月 71 | 12 | | 10099 | 肖恩 | 华盛顿 | 09 月 21 日 66 | 空值 | | 10035 | 伊丽莎白 | 山口 | 24 日 - 12 月 59 | 空值 |

该表的主键通常是员工编号,因为每个人都保证不同。 (对于进行比较,数字也比字符串更有效。)也可以使用First_NameLast_Name,因为两者的组合也只能识别我们的示例数据库中的一行。单独使用姓氏是行不通的,因为有两名员工的姓氏为“华盛顿”。在这种特殊情况下,名字都是不同的,因此可以想象使用该列作为主键,但最好避免使用可能发生重复的列。如果 Elizabeth Jones 在这家公司工作并且主键是First_Name,则 RDBMS 将不允许添加她的名字(如果已经指定不允许重复)。因为表中已经有一个 Elizabeth,所以添加第二个会使主键无法用作识别一行的方法。请注意,尽管使用First_NameLast_Name是此示例的唯一复合键,但在较大的数据库中它可能不是唯一的。另请注意,Employees表假设每位员工只能有一辆车。

SQL 是一种旨在与关系数据库一起使用的语言。有一组基本的 SQL 命令被认为是标准的,并且被所有 RDBMS 使用。例如,所有 RDBMS 都使用SELECT语句。

SELECT语句(也称为查询)用于从表中获取信息。它指定一个或多个列标题,一个或多个要从中选择的表,以及一些选择标准。 RDBMS 返回满足所述要求的列条目的行。如下所示的SELECT语句将获取拥有公司汽车的员工的名字和姓氏:

  1. SELECT First_Name, Last_Name
  2. FROM Employees
  3. WHERE Car_Number IS NOT NULL

结果集(满足Car_Number列中不具有 null 的要求的行集)如下。为满足要求的每一行打印名字和姓氏,因为SELECT语句(第一行)指定列First_NameLast_NameFROM子句(第二行)给出了将从中选择列的表。

FIRST_NAME LAST_NAME
约翰 华盛顿
佛罗伦萨 Wojokowski

下面的代码生成一个包含整个表的结果集,因为它要求 Employees 表中没有限制的所有列(没有WHERE子句)。请注意,SELECT *表示“SELECT所有列”。

  1. SELECT *
  2. FROM Employees

SELECT语句中的WHERE子句提供了选择值的条件。例如,在下面的代码片段中,只有当它们出现在Last_Name列以字符串“Washington”开头的行中时才会选择值。

  1. SELECT First_Name, Last_Name
  2. FROM Employees
  3. WHERE Last_Name LIKE 'Washington%'

关键字LIKE用于比较字符串,它提供了可以使用包含通配符的模式的功能。例如,在上面的代码片段中,’Washington’末尾有一个百分号(%),表示包含字符串’Washington’和零个或多个附加字符的任何值都将满足此选择条件。所以’华盛顿’或’华盛顿’将是比赛,但’洗’不会。 LIKE子句中使用的另一个通配符是下划线(_),它代表任何一个字符。例如,

  1. WHERE Last_Name LIKE 'Ba_man'

会匹配’Barman’,’Badman’,’Balman’,’Bagman’,’Bamman’等等。

下面的代码片段有一个WHERE子句,它使用等号(=)来比较数字。它选择分配了汽车 12 的员工的名字和姓氏。

  1. SELECT First_Name, Last_Name
  2. FROM Employees
  3. WHERE Car_Number = 12

下一个代码片段选择员工编号大于 10005 的员工的名字和姓氏:

  1. SELECT First_Name, Last_Name
  2. FROM Employees
  3. WHERE Employee_Number > 10005

WHERE子句可以在多个条件下得到相当复杂的,在某些 DBMS 中,嵌套条件也是如此。本概述不会涵盖复杂的WHERE子句,但以下代码片段具有WHERE子句,其中包含两个条件;此查询选择员工编号小于 10100 且没有公司汽车的员工的名字和姓氏。

  1. SELECT First_Name, Last_Name
  2. FROM Employees
  3. WHERE Employee_Number < 10100 and Car_Number IS NULL

一种特殊类型的WHERE子句涉及连接,这将在下一节中介绍。

关系数据库的一个显着特征是可以从所谓的连接中的多个表中获取数据。假设在检索拥有公司汽车的员工的姓名后,人们想知道谁拥有哪辆汽车,包括车牌号码,里程数和汽车年份。此信息存储在另一个表Cars中:

Cars Table | Car_Number | License_Plate | Mileage | Year | | —- | —- | —- | —- | | 五 | ABC123 | 5000 | 1996 年 | | 12 | DEF123 | 7500 | 1999 年 |

两个表中必须有一列才能将它们相互关联。此列必须是一个表中的主键,在另一个表中称为外键。在这种情况下,出现在两个表中的列是Car_Number,它是表Cars的主键和表Employees中的外键。如果 1996 年车牌号为 ABC123 的车被破坏并从Cars表中删除,那么Car_Number 5 也必须从Employees表中删除,以维持所谓的参照完整性。否则,Employees表中的外键列(Car_Number)将包含未引用Cars表中任何内容的条目。外键必须为 null 或等于其引用的表的现有主键值。这与主键不同,主键可能不为空。表Employees中的Car_Number列中有几个空值,因为员工可能没有公司汽车。

以下代码询问拥有公司汽车的员工的名字和姓氏,以及这些汽车的车牌号码,里程数和年份。请注意,FROM子句列出了EmployeesCars表,因为所请求的数据都包含在两个表中。在列名称前使用表名和点(.)表示哪个表包含该列。

  1. SELECT Employees.First_Name, Employees.Last_Name,
  2. Cars.License_Plate, Cars.Mileage, Cars.Year
  3. FROM Employees, Cars
  4. WHERE Employees.Car_Number = Cars.Car_Number

这将返回一个类似于以下内容的结果集:

FIRST_NAME LAST_NAME LICENSE_PLATE MILEAGE YEAR
约翰 华盛顿 ABC123 5000 1996 年
佛罗伦萨 Wojokowski DEF123 7500 1999 年

SQL 命令分为几类,两个主要是数据操作语言(DML)命令和数据定义语言(DDL)命令。 DML 命令处理数据,检索或修改数据以使其保持最新。 DDL 命令创建或更改表和其他数据库对象,例如视图和索引。

以下列出了更常见的 DML 命令:

  • SELECT —用于查询和显示数据库中的数据。 SELECT语句指定要包含在结果集中的列。应用程序中使用的绝大多数 SQL 命令都是SELECT语句。

  • INSERT —向表中添加新行。 INSERT用于填充新创建的表或向已存在的表添加新行(或行)。

  • DELETE —从表中删除指定的行或行集

  • UPDATE —更改表中列或列组中的现有值

更常见的 DDL 命令如下:

  • CREATE TABLE —创建一个包含用户提供的列名的表。用户还需要为每列中的数据指定类型。数据类型因 RDBMS 而异,因此用户可能需要使用元数据来建立特定数据库使用的数据类型。 CREATE TABLE通常比数据操作命令使用频率低,因为表只创建一次,而添加或删除行或更改单个值通常更频繁地发生。

  • DROP TABLE —删除所有行并从数据库中删除表定义。需要 JDBC API 实现来支持 SQL92,Transitional Level 指定的 DROP TABLE 命令。但是,对DROP TABLECASCADERESTRICT选项的支持是可选的。此外,当定义了引用被删除表的视图或完整性约束时,DROP TABLE的行为是实现定义的。

  • ALTER TABLE —在表中添加或删除列。它还添加或删除表约束并更改列属性

满足查询条件的行称为结果集。结果集中返回的行数可以是零,一个或多个。用户可以一次访问结果集中的数据,并且游标提供了执行此操作的方法。可以将游标视为指向包含结果集行的文件的指针,并且该指针能够跟踪当前正在访问哪一行。游标允许用户从上到下处理结果集的每一行,因此可以用于迭代处理。大多数 DBMS 在生成结果集时自动创建游标。

早期的 JDBC API 版本为结果集的游标添加了新功能,允许它向前和向后移动,并允许它移动到指定行或位置相对于另一行的行。

有关详细信息,请参阅从结果集中检索和修改值。

当一个用户访问数据库中的数据时,另一个用户可能同时访问相同的数据。例如,如果第一个用户正在同时更新表中的某些列,而第二个用户正在从同一个表中选择列,则第二个用户可能获得部分旧数据和部分更新数据。因此,DBMS 使用事务来维护数据处于一致状态(数据一致性),同时允许多个用户同时访问数据库(数据并发)。

事务是一组构成逻辑工作单元的一个或多个 SQL 语句。事务以提交或回滚结束,具体取决于数据一致性或数据并发性是否存在任何问题。 commit 语句使得事务中的 SQL 语句产生的更改永久化,并且 rollback 语句撤消了事务中 SQL 语句导致的所有更改。

锁是一种机制,禁止两个事务同时操作相同的数据。例如,如果该表上存在未提交的事务,则表锁可防止删除表。在某些 DBMS 中,表锁还会锁定表中的所有行。行锁可防止两个事务修改同一行,或者它阻止一个事务在另一个事务仍在修改它时选择一行。

有关详细信息,请参阅使用事务

存储过程是一组可以按名称调用的 SQL 语句。换句话说,它是可执行代码,一个迷你程序,执行一个特定的任务,可以调用一个可以调用函数或方法的方式。传统上,存储过程是用 DBMS 特定的编程语言编写的。最新一代的数据库产品允许使用 Java 编程语言和 JDBC API 编写存储过程。用 Java 编程语言编写的存储过程在 DBMS 之间是可移植的字节码。一旦编写了存储过程,就可以使用它并重用它,因为支持存储过程的 DBMS 将顾名思义将其存储在数据库中。有关编写存储过程的信息,请参见使用存储过程

数据库存储用户数据,它们还存储有关数据库本身的信息。大多数 DBMS 都有一组系统表,它们列出数据库中的表,每个表中的列名,主键,外键,存储过程等。每个 DBMS 都有自己的函数来获取有关表格布局和数据库功能的信息。 JDBC 提供了接口DatabaseMetaData,驱动程序编写者必须实现该接口,以便其方法返回有关为其编写驱动程序的驱动程序和/或 DBMS 的信息。例如,大量方法返回驱动程序是否支持特定功能。此接口为用户和工具提供了获取元数据的标准方法。通常,编写工具和驱动程序的开发人员最有可能关注元数据。