数据库系统(PostgreSQL)

数据库系统

  • 数据库系统基础
  • 数据库操作语言SQL
    • 数据定义SQL语句(创建、修改、删除)
    • 数据操纵SQL语句
    • 数据查询SQL语句
    • 数据控制SQL语句
    • 视图SQL语句
  • 数据库管理
    • 事务管理
    • 备份与恢复
  • 数据库应用编程
    • 数据库连接技术
    • Java Web数据库编程
    • 存储过程编程
    • 触发器编程

数据库系统基础

几个关键词:
DB 数据库
DBS 数据库系统
DBMS 数据库管理系统
OS 操作系统

数据库管理系统是一种运行与管理数据库的软件系统。目前,大部分的DBMS都是关系数据库管理系统。关系数据模型是以关系代数理论为基础,通过二维表结构来表示数据记录之间联系的数据模型。

I. MySQL
最流行的开源数据库管理系统。支持多用户、多线程SQL数据库管理系统。采用客户/服务器结构,由一个服务器守护程序mysqld和很多不同的客户程序、库组成。常用的数据库管理工具:Navicat Premium等。

II. PostgreSQL
开源的对象-关系数据库管理系统。它不但具有关系数据库的功能特点,同时还支持面向对象数据管理,每一个表都被当成了一个对象的集合,可以与其他的表之间有继承关系。采用经典的客户/服务器结构。常用的数据库管理工具:Navicat Premium、pgAdmin等。

数据库操作语言SQL

数据定义SQL语句(创建、修改、删除)

I. 数据库的定义

  • 创建数据库yyDB
CREATE DATABASE yyDB;
  • 修改数据库yyDB属性,包括更改数据库名称、数据库所有者等等
ALTER DATABASE yyDB RENAME TO yyDBnew;
ALTER DATABASE yyDB OWNER TO yy;
  • 删除数据库yyDB
DROP DATABASE yyDB;

II. 数据库表的定义

  • 创建数据库表
CREATE TABLE Student(
<列名>    		<数据类型>    	<列完整性约束>,
StudentID		char(13)		PRIMARY Key,
StudentName 	varchar(10)		NOT NULL,
BirthDay		date 			NULL,
Major			varchar(30)		NULL
);

a. 表中的键:
键:唯一标识元组的属性列
复合键:唯一标识元组的多个属性列
候选键:关系表中多个列可作为键,统称为候选键
主键:最有代表性的一个候选键,每个关系表仅能定义一个
外键:在一种通过主键属性相关联的两个关系表中(一个表中的主键属性列和另一个表非主键属性列关联),该主键属性在一个表(主表)中作为主键,对应在另一个表(子表)中则作为外键。

b. 关系模型完整性约束:
1.实体完整性约束:约束主键,必须不为NULL,且必须唯一
2.参照完整性约束:约束关系表,两个关系表之间如果存在一个或多个相同属性列,则该属性列在两表中分别作为主键和外键,需要保证主键和外键的值一致
3.用户自定义完整性约束:
CHECK (Transportation IN('飞机','火车','公交车','私家车','自行车','步行'))(该属性列的所有元素只在这些范围内有效)
DEFAULT '闭卷考试'(默认值为“闭卷考试”)

c. 列完整性约束包括:
PRIMARY Key(主键)、NULL(空值)、NOT NULL(非空值)、UNIQUE(值唯一)、CHECK(有效性检查)、DEFAULT(缺省值)

使用列约束关键词只能定义单个主键,若要定义多个列构成的复合主键、代理键、外键时,需要使用表约束关键词:CONSTRAINT

1.表约束定义复合主键

CREATE TABLE Plan(
CourseID 		char(4) 		NOT NULL,
TeacherID 		char(4) 		NOT NULL,
CourseName 		varchar(20),
CourseRoom 		varchar(30),
CONSTRAINT 		CoursePlan_PK 		PRIMARY Key(CourseID, TeacherID)   --定义复合主键
);

2.表约束定义代理键
可以使用代理键来代替复合主键,这样可以方便地对主键操作和提高处理性能。在PostgreSQL数据库管理系统中,可以使用表约束CONSTRAINT和自动递增序列数据类型Serial来定义代理键。这样一来会自动在表所在Schema中创建一个序列,该序列为代理键提供值。

CREATE TABLE Plan(
CoursePlanID	serial			NOT NULL,  --设置代理键数据类型为serial
CourseID 		char(4) 		NOT NULL,
TeacherID 		char(4) 		NOT NULL,
CourseName 		varchar(20),
CourseRoom 		varchar(30),
CONSTRAINT 		CoursePlan_PK 		PRIMARY Key(CoursePlanID)   --定义代理键
);

3.表约束定义外键

CREATE TABLE Register(
CourseRegID		serial			NOT NULL,
CoursePlanID	int				NOT NULL,  
StudentID 		char(13) 		
CONSTRAINT 		CourseRegID_PK 		PRIMARY Key(CourseRegID),   --定义代理键
CONSTRAINT CoursePlanID_FK FOREIGN Key(CoursePlanID)  --定义外键1
REFERENCES Plan(CoursePlanID)  --参考表的主键列
 ON DELETE CASCADE,  --级联删除
CONSTRAINT StudentID_FK FOREIGN Key(StudentID)  --定义外键2
REFERENCES Student(StudentID)  --参考表的主键列
 ON DELETE CASCADE  --级联删除
);

级联删除DELETE CASCADE:是指当主表(parent table)中的一条记录被删除,子表中关联的记录也相应的自动删除

外键的一些约束:
1.在对子表(有FOREIGN KEY关键词的表)进行数据操作时,外键的取值或者变更必须与其关联表的主键的列值一致。(不能是不存在的值)

2.主表元素删除或者主键值变更,子表中参照的外键值应对应变更,要么取空值,要么引用主表中存在的主键值,以保持关联数据表数据一致。

  • 修改数据库表
ALTER TABLE Student ADD StudentGender char(2) NULL;
ALTER TABLE Student DROP COLUMN BirthDay;
ALTER TABLE Student RENAME TO StudentNew;
ALTER TABLE Student ALTER COLUMN StudentName TYPE varchar(12);
  • 删除数据库表
DROP TABLE Student;

需要注意: 不能直接删除由FOREIGN KEY约束引用的表。只有先删除FOREIGN KEY约束或引用的表后,才能删除本表。即:先删子表(有FOREIGN Key关键词的表)再删主表(被关联的表)。

III. 数据库索引的定义

在数据库中,通常一些表会包含大量数据,若要对这些表进行数据查询,最基本的搜索信息方式是全表搜索,即将所有行数据一一取出,与查询条件进行逐一对比,然后返回满足条件的行数据。这样的的查询会消耗大量数据库系统时间,并造成大量磁盘I/O操作。因此,可以在数据库中建立类似于图书目录的索引结构,并将索引列的值索引指针数据保存在索引结构中。索引是一种针对表中指定列的值进行排序的数据结构,使用它可以加快表中数据的查询

索引文件组织经常使用B_树的变形,其中B+树是一种应用广泛的变形。
二叉搜索(排序)树和平衡二叉树是作用作内查找的数据结构,即被查找的数据集不大,可以放在内存中。而B_树B+树是用作外查找的数据结构,其中的数据存放在外存中。3层的B+树可以表示上百万的数据。

优点:

  • 可以大大加快数据的检索速度,这也是创建索引的最主要原因。
  • 可以加速表和表之间的连接。

缺点:

  • 创建索引和维护索引要耗费时间,这会随着数据量的增大而增大。
  • 索引需要占用物理空间
  • 当对表中数据进行增加、删除和修改时,索引也需要进行动态维护,这样会降低数据的维护速度

因此,仅对需要快速查询的数据库表相应列建立索引。此外,在数据库中,一般是对表的主键列创建索引。

  • 创建索引
CREATE INDEX BirthDay_Idx ON Student (BirthDay);

这样创建的索引可能会有重复值,使用关键词UNIQUE可创建唯一索引:

CREATE UNIQUE INDEX BirthDay_Idx ON Student (BirthDay);
  • 修改索引
ALTER INDEX BirthDay_Idx RENAME TO BDay_Idx;
  • 删除索引
DROP INDEX BirthDay_Idx;

数据操纵SQL语句

I. 插入数据

INSERT INTO Student VALUES ('2017220302028','YuanYuan','1999-04-01','软件工程');
INSERT INTO Student VALUES ('2017220302029','LiJiaxin','1999-07-08','软件工程');

注意,在插入语句中,integernumeric(带小数的变长定点数)等类型数值不使用引号标注,但charvarchardatedatetime等类型必须使用单引号。(这里举例的数据类型为PostgreSQL的数据类型)

II. 更新数据

UPDATE Student
SET BirthDay='1999-02-15'
WHERE StudentName='YuanYuan';

千万不忘记WHERE条件,否则会更新表中所有行该列的值。

III. 删除数据

DELETE FROM Student
WHERE StudentName='YuanYuan';

千万不忘记WHERE条件,否则会删除表中所有行数据。

数据查询SQL语句

I. 从单表读取指定列

SELECT StudentID, StudentName
FROM Student;
SELECT *  --查询所有列
FROM Student;

II. 从单表读取指定行

SELECT *  --查询所有列
FROM Student
WHERE Major='软件工程';

III. 从单表读取指定行和列

SELECT StudentID, StudentName
FROM Student
WHERE Major='软件工程';

IV. WHERE子句条件

  • 利用BETWEEN...AND限定范围
SELECT *
FROM Student
WHERE BirthDay BETWEEN '1999-01-01' AND '1999-12-31';
  • 利用LIKE与通配符限定范围
SELECT *
FROM Student
WHERE StudentName LIKE '袁_';

通配符 _代表一个未指定的字符,通配符 %代表一个或多个未指定的字符。

SELECT *
FROM Student
WHERE Major LIKE '软件%';
  • 利用NOT LIKE给出不在范围中的条件
SELECT *
FROM Student
WHERE Major NOT LIKE '软件%';

V. 查询结果排序

SELECT *
FROM Student
ORDER BY BirthDay;

默认情况,按升序排序。可使用关键词ASCDESC选定升序或降序。
例如:先按专业升序排序,在这基础上再按出生日期降序排序:

SELECT *
FROM Student
ORDER BY Major ASC, BirthDay DESC;

VI. 聚合函数的使用
AVG():计算平均值
MIN():计算最小值
MAX():计算最大值
SUM():计算该列所有值的和
COUNT():计算结果集行数

SELECT COUNT(*) AS 学生人数
FROM Student;

关键词DISTINCT消除结果集中的重复行:

SELECT COUNT(DISTINCT Major) AS 专业数  --DISTINCT关键词可消除重复行
FROM Student;

VII. 查询结果分组处理

SELECT Major AS 专业, COUNT(StudentID) AS 学生人数
FROM Student
GROUP BY Major;

可以使用HAVING子句和WHERE子句分别限定查询条件。如果要同时使用这两个条件子句,则应该使用WHERE子句过滤数据集,使用HAVING子句限定分组数据。

SELECT Major AS 专业, COUNT(StudentID) AS 学生人数
FROM Student
WHERE StudentGender='女'  --过滤数据集:性别为女
GROUP BY Major  --根据专业来分组
HAVING COUNT(*)>3;  --限定分组数据:行数大于3的

VIII. 使用子查询处理多表
在SELECT查询语句中,使用子查询方式,可实现多表关联查询
即:在SELECT语句的WHERE子句中嵌套一层或多层SELECT子查询语句。(当然,这些表一定应该有一列或多列属性是一致的)

比如,需要检索出“信软学院”的教师名单。该操作需要关联教师信息表(Teacher)和学院信息表(College),通过共同属性CollegeID来实现关联查询:

SELECT TeacherID, TeacherName
FROM Teacher
WHERE CollegeID IN   --嵌套SELECT子查询语句
(SELECT CollegeID
FROM College
WHERE CollegeName='信软学院')
ORDER BY TeacherID;

但是,SQL查询语句不宜嵌套过多子查询,会降低性能

IX. 使用连接查询多表
连接查询的基本思想:将关联表的主键值外键值进行匹配比对,从中检索出符合条件的关联表信息。

SELECT TeacherID, TeacherName
FROM Teacher, College
WHERE Teacher.CollegeID = College.CollegeID AND College.CollegeName='信软学院'   --主、外键匹配,再限定条件为信软学院
ORDER BY TeacherID;

可以发现,连接查询可以实现子查询的相同功能。但需要注意的是:当SELECT查询结果集的数据均来自于同一个表时,使用子查询才有用。如果查询的结果集来自多张表时,子查询就不能满足要求了,此时必须使用连接查询来处理。

X. JOIN…ON连接

实现多表关联查询还可以使用JOIN...ON关键词。

  • 内连接
SELECT C.CourseName AS 课程名称, T.TeacherName AS 教师, COUNT(R.CoursePlanID) AS 选课人数
FROM Course AS C JOIN Plan AS P  --FORM <表1> JOIN <表2>
ON C.CourseID=P.CourseID  --'ON'后跟连接条件
JOIN Teacher AS T ON P.TeacherID=T.TeacherID  --JOIN <表3>
JOIN Register AS R ON P.CoursePlanID=R.CoursePlanID  --JOIN <表4>
GROUP BY C.CourseName, T.TeacherName;
  • 外连接
    • 左(外)连接:即使右表中没有匹配,也从左表中返回所有的行
    • 右(外)连接:即使左表中没有匹配,也从右表中返回所有的行
    • 全外连接:只要其中一个表中存在匹配,就返回行。

左连接:

SELECT C.CourseName AS 课程名称, T.TeacherName AS 教师, COUNT(R.CoursePlanID) AS 选课人数
FROM Course AS C JOIN Plan AS P
ON C.CourseID=P.CourseID
JOIN Teacher AS T ON P.TeacherID=T.TeacherID
LEFT JOIN Register AS R ON P.CoursePlanID=R.CoursePlanID  --左连接
GROUP BY C.CourseName, T.TeacherName;

Q1: 数据库查询结果集去重方法?

  • DISTINCT 关键词
    两条记录或者多条记录的每一个字段值完全相同,这种情况去重复最简单,用关键字distinct就可以去掉。
  • GROUP BY 分组
    两条记录之间之后只有部分字段的值是有重复的,但是表存在主键或者唯一性ID。如果是这种情况的话用DISTINCT是过滤不了的,这就要用到主键id的唯一性特点及group by分组。

Q2: 数据库分页查询?

MySQL中,使用 limit 关键字可以实现查询多行数据:

select * from table limit 5; --返回前5行
select * from table limit 0,5; --同上,返回前5行
select * from table limit 5,10; --返回6-10行

数据控制SQL语句

数据控制语言是一种可以对用户数据访问权限进行控制的操作语句。

  • GRANT语句
    赋予学生角色(RoleS)对表Student的数据进行查询、插入、更新、删除的权限。学生角色可以将这些权限赋予用户。
GRANT SELECT, INSERT, UPDATE, DELETE ON Student TO RoleS;
  • REVOKE语句
    收回用户或角色的权限。如下,收回赋予给学生角色(RoleS)的删除表Student数据的权限:
REVOKE DELETE ON Student FROM RoleS;
  • DENY语句
    拒绝给该用户或角色授予权限,并防止用户或角色通过其他用户或角色来继承权限。如下,拒绝教师角色(RoleT)对Teacher表数据的删除权限:
DENY DELETE ON Teacher TO RoleT;

视图SQL语句

视图是一种建立在SELECT查询结果集上的虚拟表。视图可以基于数据库表或其他视图来构建,它本身没有自己的数据,而是使用了存储在基础表中的数据。在基础表中的任何数据都可以在视图中看到。如果在视图中对数据进行了修改,其基础表的数据也要发生变化

视图一旦被定义,它便作为对象存储在数据库中,但视图本身并不存储数据,而是通过其虚拟视窗映射到表中的数据。对视图的操作与对数据库表的操作一样,可以对其数据进行查询和一定约束的修改与删除。

I. 视图的创建与删除
一个数据库不允许有两个视图同名。在视图名后可以定义视图的各个列名,如果没有定义列名,则默认采用基础表的查询结果集的所有列作为视图列。

CREATE VIEW <视图名>[(列名1),(列名2),...] AS <SELECT查询>;

CREATE VIEW StudentView AS
SELECT StudentID, StudentName, BirthDay
FROM Student
WHERE Major='软件工程';

删除视图:

DROP VIEW StudentView;

II. 视图的使用

  • 使用视图简化复杂SQL查询操作
    通过视图,可以将复杂的查询语句封装在视图内,使外部程序只需要使用简单方式访问视图,便可获得所需数据。
  • 使用视图提高数据访问安全性
    通过视图可以将基础表的某些敏感数据隐藏起来,外部用户无法获得数据库表的完整数据,降低风险。
  • 提供一定程度的数据逻辑安全性
    当基础表结构发生改变时(例如增加或删除字段),只要视图结构不变,应用程序可以不做修改。
  • 集中展示用户所感兴趣的特定数据
    视图可以将用户不关心的数据进行过滤,仅提供他们所感兴趣的数据。

数据库管理

事务管理

事务 是指由构成单个逻辑处理单元的一组数据库访问操作,这些操作的SQL语句被封装在一起,它们要么都被成功执行,要么都不被执行。在关系数据库中,一个事务程序可以由一条SQL语句组成,也可以由一组SQL语句组成。一个数据库应用程序可以包含一个事务程序,也可以包含多个事务程序。

BEGIN;
SQL语句1;
SQL语句2;
...
SQL语句n;
COMMIT;

其中每条语句执行后,并不立即提交数据库,而是在执行COMMIT语句后,才将所有的SQL执行结果提交数据库。

事务的特性:

  • 原子性:事务中SQL语句对数据的修改操作,要么全部正确地执行,要么全部都不执行。
  • 一致性:事务的执行结果从数据库一种正确数据状态变迁到另一种正确数据状态。
  • 隔离性:当多个事务并发执行时,一个事务的执行不能被其他事务干扰,即各个并发事务之间不能相互影响。
  • 持续性:一个事务一旦提交,它对数据库中的数据的改变应该是永久的。

事务并发运行时可能会出现的问题:

  • 脏读:当多个事务并发运行时,其中一个事务读取了被另一个事务修改后的共享数据,但修改数据的事务因为某种原因修改失败,未能成功提交修改数据到数据库,导致读取共享数据的事务得到一个垃圾数据。脏数据是对未提交的修改数据的统称。
  • 不可重复读:一个事务对同一共享数据先后重复读取两次,但是发现原有数据改变或者丢失。原因:另一事务同时在对共享数据进行修改或删除操作。
  • 幻像读:一个事务对同一共享数据重复读取两次,但是发现第2次读取比第一次读取的结果中增加了一些数据。原因:另一事务同时在对共享数据进行添加操作。
  • 丢失更新:一个事务对一个共享数据进行更新处理,但以后查询该数据值时,发现该数据与自己的更新值不一致。原因:另一事务对共享数据进行了更新,并改变了前面事务的更新值。

事务隔离级别:
为了避免事务并发运行可能出现的脏读、不可重复读、幻像读、丢失更新问题,可在DBMS中设置事务隔离级别选项参数

隔离级别 脏读 不可重复读 幻像读 丢失更新
读取未提交 可能 可能 可能 可能
读取已提交 不可能 可能 可能 可能
可重复读 不可能 不可能 可能 可能
可串行化 不可能 不可能 不可能 不可能

可串行化调度:并发事务调度的执行结果与这些事务串行执行的结果相同时,才能保证并发事务执行的数据结果是正确的。

从上往下隔离级别依次增高。隔离级别越高,DBMS越能保证数据的完整性和一致性,但是对并发性能的影响也越大。

备份与恢复

I. 数据库备份
典型的DBMS大都支持以下4种备份方式:

  • 完整数据库备份:备份数据库的所有内容,包括用户表、系统表、索引、视图、存储过程等所有数据库对象。但要花费很多的备份时间和存储空间。
  • 差异数据库备份:只备份上次数据库备份以来发生变化的数据,比完整数据库备份花的时间和存储空间都更少。
  • 事务日志备份:只备份上一次日志备份以来的事务日志数据。
  • 文件备份:数据库通常由存储在磁盘上的若干数据文件构成,因此可以直接通过复制数据库文件方式实现数据库备份。这种文件备份方式与事务日志备份方式结合才有意义。

II. 数据库恢复
数据库恢复技术是利用数据库备份文件和数据库事务日志文件来实现数据库恢复处理。应根据用户恢复要求,采用前滚事务方式或回滚事务方式恢复数据库。

  • 若需要对故障前的数据库备份文件进行恢复,可采用前滚事务恢复方式。
  • 若需要对故障后的数据库备份文件进行恢复,可采用回滚事务恢复方式。

数据库应用编程

数据库连接技术

  • ODBC技术:Windows下开放的数据库连接。由于不同的数据库有不同的API(应用程序编程接口),编程应用相对比较复杂,为了解决这种问题,ODBC提供了一组规范,并为多种数据库的开发提供了统一的API接口,可以为不同数据库的客户端应用程序提供服务。
  • JDBC技术:Java数据库连接,是Java语言支持SQL功能而提供的与数据库相连的用户接口。JDBC包括一组用Java语言写的接口和类,独立于特定的DBMS,统一对数据库的操作。有了JDBC,就可以方便地在Java语言中使用SQL,从而使Java应用程序或Java Applet可以对分布在网络上的各种关系数据库进行访问。但JDBC不能直接操作数据库,而是通过接口加载数据库的驱动来操作数据库。JDBC的接口封装在java.sql和Javax.sql两个包中,因此,用Java开发连接数据库的应用程序时必须加载这两个包,同时还需要导入相应的JDBC的数据库驱动程序,加载mysql驱动的代码为:Class.forName("com.mysql.jdbc.Driver");
    url = 协议名+IP地址+端口+数据库名称,后面可以用'?'来连接参数。
    例如:url: jdbc:mysql://localhost:3306/ptp?useSSL=false&allowMultiQueries=true

Java Web数据库编程

  • Servlet技术:Servlet是运行在服务器端的程序,可以被认为是服务器端的Applet。Servlet被Web服务器加载和执行,就如同Applet被浏览器加载和执行一样。Servlet的主要功能在于允许用户交互式地浏览和修改数据,生成动态Web内容。
  • MyBatis访问数据库技术:MyBatis是基于Java的、支持普通SQL查询、存储过程和高级映射的优秀持久层框架。

存储过程编程

存储过程是一种数据库对象,由一组能完成特定功能的SQL语句集构成。它把经常会被重复使用的SQL语句逻辑块封装起来,经过编译后,存储在数据库服务器端,当再次被调用时,不需要再次编译,当客户端连接到数据库时,用户通过指定存储过程的名称并给出参数,数据库就可以找到相应的存储过程并予以调用。

创建存储过程:

CREATE OR REPLACE FUNCTION countRecords ()
RETURNS integer AS $count$
DECLARE 
	count integer;    --声明段
BEGIN 
	SELECT count(*) INTO count FROM Student;    --函数体语句
	RETURN count;
END;
$count$ LANGUAGE plpgsql;

触发器编程

触发器也是一种数据库对象,但它与存储过程不同,存储过程是通过其他程序来启动运行或者直接启动运行,而触发器则是由一个事件触发启动运行。

创建触发器之前必须检查要创建的触发器所依赖的表或视图是否存在,如果不存在,必须首先创建该表或视图。

第一步:创建触发器的执行函数

CREATE OR REPLACE FUNCTION score_audit()
	RETURNS TRIGGER AS $score_audit$
	BEGIN
		IF (TG_OP = 'DELETE') THEN
			INSERT INTO Audit_score SELECT user, old.sid, odl.cid, now(), OLD.score;
			RETURN OLD;
		END IF;
		RETURN NULL;
	END;
$score_audit$ LANGUAGE plpgsql;

NEW:数据类型是record,该变量为行级触发器中的INSERT/UPDATE操作,保存数据行。
OLD:数据类型是record,该变量为行级触发器中的UPDATE/DELETE操作,保存数据行。

第二步:创建触发器

CREATE TRIGGER score_audit_trigger
AFTER DELETE ON Stu_score
FOR EACH ROW EXECUTE PROCEDURE score_audit();

你可能感兴趣的:(计算机基础)