几个关键词:
DB
数据库
DBS
数据库系统
DBMS
数据库管理系统
OS
操作系统
数据库管理系统是一种运行与管理数据库的软件系统。目前,大部分的DBMS都是关系数据库管理系统
。关系数据模型是以关系代数理论为基础,通过二维表
结构来表示数据记录之间联系的数据模型。
I. MySQL
最流行的开源数据库管理系统。支持多用户、多线程SQL数据库管理系统。采用客户/服务器
结构,由一个服务器守护程序mysqld
和很多不同的客户程序、库组成。常用的数据库管理工具:Navicat Premium等。
II. PostgreSQL
开源的对象-关系数据库管理系统
。它不但具有关系数据库的功能特点,同时还支持面向对象
数据管理,每一个表都被当成了一个对象的集合,可以与其他的表之间有继承关系。采用经典的客户/服务器
结构。常用的数据库管理工具:Navicat Premium、pgAdmin等。
I. 数据库的定义
CREATE DATABASE yyDB;
ALTER DATABASE yyDB RENAME TO yyDBnew;
ALTER DATABASE yyDB OWNER TO yy;
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;
I. 插入数据
INSERT INTO Student VALUES ('2017220302028','YuanYuan','1999-04-01','软件工程');
INSERT INTO Student VALUES ('2017220302029','LiJiaxin','1999-07-08','软件工程');
注意,在插入语句中,integer
和numeric
(带小数的变长定点数)等类型数值不使用引号标注,但char
、varchar
、date
、datetime
等类型必须使用单引号。(这里举例的数据类型为PostgreSQL的数据类型)
II. 更新数据
UPDATE Student
SET BirthDay='1999-02-15'
WHERE StudentName='YuanYuan';
千万不忘记WHERE
条件,否则会更新表中所有行该列的值。
III. 删除数据
DELETE FROM Student
WHERE StudentName='YuanYuan';
千万不忘记WHERE
条件,否则会删除表中所有行数据。
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;
默认情况,按升序排序。可使用关键词ASC
和DESC
选定升序或降序。
例如:先按专业升序排序,在这基础上再按出生日期降序排序:
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
分组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行
数据控制语言是一种可以对用户数据访问权限进行控制的操作语句。
GRANT
语句GRANT SELECT, INSERT, UPDATE, DELETE ON Student TO RoleS;
REVOKE
语句REVOKE DELETE ON Student FROM RoleS;
DENY
语句DENY DELETE ON Teacher TO RoleT;
视图是一种建立在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语句组成。一个数据库应用程序可以包含一个事务程序,也可以包含多个事务程序。
BEGIN;
SQL语句1;
SQL语句2;
...
SQL语句n;
COMMIT;
其中每条语句执行后,并不
立即提交数据库,而是在执行COMMIT
语句后,才将所有的SQL执行结果提交数据库。
事务的特性:
事务并发运行时可能会出现的问题:
脏数据
是对未提交的修改数据
的统称。事务隔离级别:
为了避免事务并发运行可能出现的脏读、不可重复读、幻像读、丢失更新问题,可在DBMS中设置事务隔离级别选项参数
。
隔离级别 | 脏读 | 不可重复读 | 幻像读 | 丢失更新 |
---|---|---|---|---|
读取未提交 | 可能 | 可能 | 可能 | 可能 |
读取已提交 | 不可能 | 可能 | 可能 | 可能 |
可重复读 | 不可能 | 不可能 | 可能 | 可能 |
可串行化 | 不可能 | 不可能 | 不可能 | 不可能 |
可串行化调度:并发事务调度的执行结果与这些事务串行执行的结果相同时,才能保证并发事务执行的数据结果是正确的。
从上往下隔离级别依次增高。隔离级别越高,DBMS越能保证数据的完整性和一致性,但是对并发性能的影响也越大。
I. 数据库备份
典型的DBMS大都支持以下4种备份方式:
II. 数据库恢复
数据库恢复技术是利用数据库备份文件和数据库事务日志文件来实现数据库恢复处理。应根据用户恢复要求,采用前滚事务方式或回滚事务方式恢复数据库。
不能直接操作数据库
,而是通过接口
加载数据库的驱动
来操作数据库。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
允许用户交互式地浏览和修改数据
,生成动态Web内容。存储过程是一种数据库对象
,由一组能完成特定功能的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();