赞
踩
所有内容均总结自自中国大学慕课 MOOC-北京信息科技大学-车蕾老师的数据库系统基础课程 https://www.icourse163.org/shortUrl/parse/RcDZo可以从该链接直接观看讲解视频和课件
背景
特点
背景
特点
文件系统的缺陷
标志着数据库技术诞生的三个事件
层次数据模型 | 第一代数据库系统 |
网状数据模型 | |
关系数据模型(二维表) | 第二代数据库系统 |
保证数据的一致性
数据独立性是指数据的组织和存储方式与应用程序互不依赖、彼此独立。
保证数据正确的特性在数据库中称之为数据完整性。
在多个用户同时使用数据库时,能够保证不产生冲突和矛盾,保证数据的一直信奉和正确性。
能比较真实地模拟现实世界 | 概念数据模型(认知模型) |
容易被人们理解 | |
便于在计算机上实现 | 组织数据模型(实现模型) |
描述现实世界的数据模型成为概念模型或概念数据模型。
E-R(Entity Relationship)的三要素
1 层次数据模型
2 网状数据模型
3 关系数据模型
1 数据库管理系统的基本功能
DBMS基本功能:
2 数据库的三层模式结构
3 数据独立性:
指应用程序与数据的组织和存储结构相互独立的特性。(具体说,就算修改数据的组织方法和存储结构,应用程序不用修改)。
4 数据库管理系统的基本框架
当一个用户程序通过DBMS读取一条记录时,
以数据为主体的数据库,和管理数据库的系统软件数据库管理系统(DBMS),····。
1 三要素:实体、属性、联系
2 概念
实体:客观存在并可以相互区分的客观事物或抽象事件
属性:实体的特征(性质);
实体集:具有相同属性的一类实体的集合;
弱实体:仅靠自身的特征不能区分一个个实体,需要借助其他实体的特征才能够进行区分;
联系:数据之间的关联集合。
3 实体之间的基本联系
1:1;
1:n;
m:n;
4 依赖联系
被弱实体所依赖的实体集也称作强实体集,强弱实体机之间的联系叫依赖联系。
由于技术上的原因,不直接使用多对多,而是将它们转换为一对多联系。
并且,两个实体之间多对多的联系一定能转换成一对多的联系!
SQL的特点:
用户可以直接进行操作的:基本表和视图.
master数据库
用于存储所有系统级信息,包括:
tempdb数据库
用于保存所有的临时表和临时存储过程,还可以满足任何其它的临时存储要求
model数据库
是一个模板数据库,必须一直存在于SQL Server系统中。
数据库的物理存储基本上是由SQL Server自动管理的。
1. 主数据文件
2. 次数据文件
3. 事务日志文件
1. 三个要素
a.关系数据结构:
实体及实体与实体之间的联系均用关系来表示,关系就是数二维表;
b.关系操作集合:
关系操作可以用代数操作(通过代数对关系的运算来表达查询要求的方式)和逻辑方式(通过关系演算、用谓词表达对关系的查询要求的方法)来表示;
关系数据语言分三类:关系代数语言、关系演算语言、具有双重特点的SQL语言。
c.关系完整性约束:
分三类:实体完整性、参照完整性、用户自定义完整性。
2.关系的形式定义
a.
b.
需要说明两点:
X
实体完整性约束:每个元组都是可识别和唯一的;
参照完整性约束:参照关系中的值要么取空,要么是被参照元组中的值;
交, 并, 差, 广义笛卡尔积
SELECT | 选择运算 | 行筛选 | |
PROJECT | 投影运算 | 列筛选 | |
![]() | JOIN | 连接运算(选择某些行形成新关系) | 自然连接(除去重复) |
÷ | DIVISION | 除运算 | ![]() |
对于Y=f(X),给定一个X,都有一个Y对应,则X决定Y(X→Y),Y依赖于X;
严格形式化定义:
"不良"函数依赖:传递, 部分.
定义
把一个关系模式分解成两个或多个关系模式,在分解的过程中消除那些“不良”的函数依赖,从而获得好的关系模式。
例如:
仓库(仓库号,地点,设备号,设备名,库存数量)
-----> 分解为:仓库(仓库号,地点)
设备(设备号,设备名)
库存(仓库号,设备号,库存数量)。
要求:
自反律、增广率、传递律
定理:Amstrong公理是正确的
Amstrong公理的推论及正确性
合并、分解、伪传递
引理:
根据合并规则和分解规则,可以推导出:
属性集闭包
直接计算F的闭包太复杂,所以引入了属性集闭包。
算法:
举例:
例1:关系模式R(U,F),U={A,B,C,D,E},F={AB→C,B→D,C→E,EC→B,AC→B},求。
1 | 令 |
2 |
|
3 | |
4 | 则F中左部为{A,B,C,D}的任意子集的函数依赖有:AB→C,B→D,C→E,AC→B |
5 | |
6 | 因为 |
1 覆盖和等价
2 最小函数依赖
证明:
方法:
也就是X的任何真子集Z无法把X→A的所有内容包括,即A完全函数依赖于X 。
举例:
例1:假设有属性集U={A,B,C,D,E},函数依赖集F={A→B,B→C,AD→E},请问F是否是最小函数依赖。
1 | F中任一函数依赖的右部都仅含有一个属性; | √ |
2 | 只用找左部个数大于1的就行 | √ |
3 | ![]() | √ |
求解
算法:
举例:
例3:关系模式R(U,F), U={A,B,C,D,E},F={AB→E,DE→B,B→C,C→E,E→A},求F的最小覆盖。 。
1 | 因为右部都是单一属性,所以不需要用分解规则化简; |
2 | 化简左侧使得每一个函数依赖的左部没有多余属性 等价变换后的函数依赖集为:{B→E,DE→B,B→C,C→E,E→A} |
3 | 令G=F-{B→E}={DE→B,B→C,C→E,E→A},则
|
4 | 令G=F-{DE→B}={B→C,C→E,E→A},则
|
5 | 令G=F-{B→C}={DE→B,C→E,E→A},则
|
6 | 同样,检验C→E,E→A都不是多余函数依赖,不能去除。
|
规范化的目的就说要设计“好”的关系,使关系尽量减少操作异常甚至拒绝操作异常现象。
所有分量都必须是不可分的最小数据项。
如果R(U,F) ∈1NF,并且R中的每个非主属性都完全函数依赖于关键字,则R (U,F) ∈2NF。
判断关系模式是否满足2NF的方法:
如果R(U,F) ∈2NF,并且所有非主属性都不传递依赖于关键字,则R(U,F) ∈3NF。
判断是否为第三范式的方法:
定义:
结论:
不能将3NF分解成BCNF。
1 无损连接
a 形式定义
b 判断一个分解是否具有无损连接特性的法则
关系模式R分解为R1和R2时无损链接分解的充要条件:
2 保持函数依赖
a 定义
分解后的函数依赖的集合,与原函数依赖等价
b 判断
判断一个分解是否保持函数依赖,可以根据函数依赖的最小覆盖和等价来判断。
3 例题
例1.设有关系模式R(U,F),U={职工号,仓库号,城市},F={职工号→仓库号, 仓库号→城市},如下分解哪个是保持函数依赖和保证无损连接的分解。
A . ρ1={R1 (职工号,Φ),R2 (仓库号, Φ),R3 (城市, Φ)}
显然不满足函数依赖,都是Φ,无法推出F; ∵ R1∩R2=Φ ∴ 及不存在R1∩R2→R1-R2,也不存在R1 ∩ R2 → R2 – R1 ∴ ρ1不满足无损连接 |
B. ρ2={R1 ({职工号,仓库号},{职工号→仓库号}), R2 ({职工号,城市},{职工号→城市})}
∵ R1∩R2={职工号},R1-R2={仓库号} 又 ∵ 存在公共号→仓库号 ∴ 存在R1∩R2→R1-R2 ∴ 满足无损链连接; 由ρ2无法推导出仓库号→城市 ∴ ρ2不满足保持函数依赖 |
∵ R1∩R2={仓库号},R2-R1={城市} 又∵ 存在仓库号→城市 ∴ 存在R1∩R2→R2-R1 ∴ 满足无损连接; 由ρ3可以推导出职工号→仓库号,仓库号→城市 ∴ρ3还满足保持函数依赖。 |
例2.设有关系模式R(U,F),U={A,B,C,D},F={AD→C, B→D }, ρ={R1 (A,B,C),R2 (B,D)} 为R的一个分解,那么分解ρ为:
A 保持函数依赖和无损连接
B 无损连接,但不保持函数依赖
C 不是无损连接,但保持函数依赖
D 即不是无损连接,也不保持函数依赖
∵ R1∩R2={B},R1-R2={A,C},R2-R1={D} 又∵ 存在B→D ∴ 存在R1∩R2→R2-R1 ∴ 满足无损连接; 由于ρ中,A、D、C三个并没有放在一个函数依赖中,因此AD→C丢失了 ∴ ρ不满足保持函数依赖 |
例3. 设有关系模式R(U,F),U={A,B,C,D},F={A→B, C→D },ρ={={R1(A,B),R2(C,D)}为R的一个分解,那么分解ρ为:
∵ R1∩R2=Φ,R1-R2={A,B},R2-R1={C,D} ∴ Φ 无法决定R1-R2或R2-R1 ∴ 不满足无损链接; 满足保持函数依赖。 |
重要结论:
例题
0 |
先求候选关键字:
因为所有函数的依赖的右部都没有
AB,所以首先求
|
1 | 计算得到F={B→C} |
2 | 不终止 |
3 | R0({A},Φ),R1({B,C},{B→C}) |
4 | 不存在分组问题 |
5 |
ρ={R0 ({A},Φ),R1 ({B,C},{B→C}),U={B,C}
|
6 | X = {A,B},Rx({A,B},Φ)
τ=ρ∪Rx (X,Fx )
={R0 ({A},Φ),R1 ({B,C},{B→C}),Rx ({A,B},Φ)
|
7 | U0 |
8 |
![]()
分解结果:τ={R1({B,C},{B→C}),Rx({A,B},Φ)}
|
例2.设有关系模式R=({C,T,S,N,G},{C→T,CS→G,S→N})
解:
0 | 关键字X={C,S} |
1 | F={C→T,CS→G,S→N} |
2 | 不终止 |
3 | 无R0 |
4 | R1=({C,T},{C→T)} R2=({C,S,G},{CS→G}) R3=({S,N},{S→N}) |
5 | ρ=(R1,R2,R3) ={({C,T}, {C→T} ) , ({C,S,G}, {CS→G}) , ({S,N}, {S→N})} |
6 | Rx({C,S},{Φ})
τ=ρ∪({C,S} ,{Φ})
={({C,S} , Φ), ({C,T}, {C→T}) , ({C,S,G}, {CS→G}) , ({S,N}, {S→N})}
|
7 | X
即τ={({C,T}, {C→T}) , ({C,S,G}, {CS→G}) , ({S,N}, {S→N})}
|
8 | 最终的τ就是分解结果 |
描述了 现实世界的数据管理需求。
这里只关注侠义的,即数据模型的设计。
设计关系数据模型,决定了用什么方法来实现现实世界的数据管理需求。
确定各个关系模式的主关键字、外部关键字、属性的约束,三种完整性约束,设计视图。
① 将每一个实体转换为一个关系模式,使其包含对应实体的全部属性,并确定关键字
② 联系:
例1 1:1联系
或者↓
亦或者↓
例2 1:n联系
例3 m:n联系
例4 单选
答案:C
决定如何去实现现实世界的数据管理。
一般涉及如下内容:(就是一堆SQL语句实现的东西)
例:建立“仓储订货”数据库,其中数据主文件的初始大小为10MB,最大为50MB,增 量为5MB;日志文件的初始大小为5MB,最大为25MB,增量为5MB,并将数据 文件安排在c盘\mssql\data\文件夹下,把日志文件安排在d盘的\mssql\log\文件夹下。
- CREATE DATABASE 仓储订货
- ON
- (NAME = order_dat,
- FILENAME = 'C:\mssql\data\orderdat.mdf',
- SEIZE = 10MB, MAXSIZE = 50MB, FILEGROWTH = 5MB)
- LOG ON
- (NAME = order_log,
- FILENAME = 'D:\mssql\log\orderlog.ldf',
- SIZE = 5MB, MAXSIZE = 25MB, FILEGROWTH = 5MB)
下面是建了三个文件组来存放数据文件,然后一个来放日志文件
一个逻辑上的概念,是数据库中一组用户对象的逻辑集合。通过架构(schema)管理对象
CREATE SCHEMA shema_name [AUTHORIATION owner_name]
架构通常由数据库管理员创建,AUTHORIATION owner_name可以指定架构的管理者(默认是创建者)。
DROP SCHEMA schema_name
只有在架构为空 不包含任何对象时才可以删除。
主要内容:1.CREATE TABLE命令的基本格式; 2.列的定义; 3.计算列的定义; 4.表级约束
Tips:
ON DELETE 和ON UPDATE少了 SET NULL和SET DEFAULT(因为没有外键约束或参照完整性约束)
在列的定义后面,例如:
PRIMARY KEY(column1,column2,...)
UNIQUE(column1,column2,...)
- CREATE TABLE 订货.订购明细(
- 订购单号 CHAR(5) FOREIGN KEY REFERENCES 订货.订购单
- ON DELETE CASCADE ON UPDATE CASCADE,
- 序号 SMALLINT CHECK(序号>=1),
- 器件号 CHAR(8) FOREIGN KEY REFERENCES 基础.器件,
- 单价 SMALLMONEY,
- 数量 INT CONSTRAINT num CHECK(数量>=0),
- PRIMARY KEY(订购单号,序号)
- )
在完整性约束中:
- /*删除完整性约束*/
- ALTER TABLE 基础.职工
- DROP CONSTRAINT ref_wh
-
- /*添加完整性约束*/
- ALTER TABLE 基础.职工
- ADD CONSTRAINT ref_wh
- FOREIGN KEY(仓库号) REFERENCES 仓储.仓库(仓库号)
- ON DELETE SET NULL
- ON UPDATE CASCADE
-
- /*增加和删除字段*/
- ALTER TABLE 订货.订购明细
- ADD 完成日期 datatime
-
- ALTER TABLE 订货.订购明细
- DROP COLUMN 完成日期
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
Tips:
INSERT INTO 订货.订购明细 VALUES('OR67',1,'P2',120,5)
DELETE FROM 仓储.仓库 WHERE 仓库号='WH4'
删除操作只与参照完整性有关,并且只有删除被参照表的记录时,才需要检查参照完整性,这时,系统会根据定义参照完整性时确定的处理方法(拒绝删除-ON ACTION、控制删除-SET NULL、默认值删除-SET DEFAULT、级联删除-CASCADE)进行处理
UPDATE 仓储.仓库 SET 面积=800 WHERE 仓库号='WH1'
更新操作可以看作时先删除旧记录再插入新记录,因此更新操作的数据完整性检查综合了插入操作和删除操作的数据完整性检查。
- SELECT * FROM 基础.职工
-
- /*查询职工的年工资(=工资*12)*/
- SELECT 姓名,工资*12 AS 年工资 FROM 基础.职工 --用AS对查询到的列命名,AS可以省略
-
- /*去掉重复行*/
- SELECT DISTINCT 班组长 FROM 基础.职工
如这张图(简单的大于 小于 BETWEEN IS NULL就不说了)
格式为:列名[NOT] LIKE 匹配串;
匹配串类型:可以是字符串常量,也可以含有通配符;
通配符种类:
%(百分号) | 匹配0或多个字符 |
_(下划线) | 匹配1个字符 |
[] | 匹配括号中的字符,如[a-f]=[abcdef] |
[^] | 不匹配括号中的字符 |
字符串,LIKE后面的匹配串记着加' '。
- --查询名字有三个字,且中间是靖的员工
- SELECT * FROM 基础员工 WHERE 姓名 LIKE '_靖_'
-
- --查询任意位置包含字符串'DDR'的所有记录
- SELECT * FROM 基础.器件 WHERE 规格 LIKE '%DDR%'
-
- --查询前三位是OR6、最后一位为0~9的所有订购单记录
- SELECT * FROM 订货.订购单 WHERE 订购单号 LIKE 'OR7[0-9]'
以下两个SQL语句等价
- SELECT * FROM 基础.器件 WHERE 器件名称 IN ('内存','鼠标')
-
- SELECT * FROM 基础.器件 WHERE 器件名称 = '内存' OR 器件名称 = '鼠标'
使用INTO短语将查询结果存储到指定的新表中
SELECT 订购单号,供货方,订购日期 INTO 订货.E3 FROM 订货.订购单 WHERE 经手人 = 'E3'
ORDER BY order_expression[ASC|DESC](默认ASC升序)
- --按单价升序列出所有器件信息
- SELECT * FROM 基础.器件 ORDER BY 单价
!如果ORDER BY column1, column2 DESC,指的是先按column1升序,再按column2降序!
- --查询所有订购明细,先按订购单号升序排序,再按金额降序排序
- SELECT * FROM 订货.订购明细 ORDER BY 订购单号,金额 DESC
TOP(expression) [PERCENT] [WITH TIES]
内连接:
- -- 查询在北京或是上海工作的员工的仓库号、职工号、姓名
- SELECT 职工.仓库号, 职工号, 姓名
- FROM 基础.职工 JOIN 仓储.仓库
- ON 职工.仓库号 = 仓库.仓库号
- WHERE 城市 IN('北京','上海')
如果连接的列名相同,那么就需要表明哪个表的列
只是逻辑上通过取别名的方法,来把一张表分成两张,物理上仍是一张表。
左右全连接要理解!
COUNT(计数)、AVG(平均数)、MIN(最小值)、MAX(最大值)、SUM(求和)
- --找出供应商所在地的数目
- SELECT COUNT (DISTINCT 地址) FROM 订货.供应商
-
- --求支付的工资总数、职工人数、所有职工的平均工资、最高工资、最低工资
- SELECT SUM(工资) 总工资,COUNT(*) 人数,
- AVG(工资) 平均工资,
- MAX(工资) 最高工资,MIN(工资) 最低工资
- FROM 基础.职工
在聚合函数遇到空值的时候,除COUNT(*)外,其他都跳过空值而只处理非空值。
- --查询每个仓库的职工人数和平均工资
- SELECT 仓库号,COUNT(*) 人数,AVG(工资) 平均工资
- FROM 基础.职工
- GROUP BY 仓库号
这里可以看出来,HAVING的用法和WHERE很像,那么可以使用WHERE来代替吗?
Tip:只有确切知道子查询返回的是单值时,才可以使用比较运算符(>、<、=、>=、<=、<>)。
- --查询哪些仓库目前还没有职工
- SELECT * FROM 仓储.仓库
- WHERE 仓库号 NOT IN
- (SELECT 仓库号 FROM 基础.职工)
-
- --找出哪些城市的仓库向北京的供应商发出了订购单
- SELECT 城市 FROM 仓储.仓库
- WHERE 仓库号 IN (SELECT 仓库号 FROM 基础.职工
- WHERE 职工号 IN (SELECT 经手人 FROM 订货.订购单
- WHERE 供货方 IN (SELECT 供应商号 FROM 订货.供应商
- WHERE 地址='北京')))
Tip:EXISTS或NOT EXISTS是用来检查在子查询中是否有结果返回的
- INSERT INTO 仓储.库存
- SELECT 'WH3',器件号,NULL FROM 基础.器件
- --第一列、第二列是常量,第二列时从器件表查询到的器件号,查询结果插入库存表
- UPDATE 订货.订购单 SET 金额 =
- (SELECT SUM(金额*数量) FROM 订货.订购明细
- WHERE 订购单号 = 订购单.订购单号)
- DELETE FROM 订货.供应商 WHERE 供应商号 NOT IN
- (SELECT 供货方 FROM 订货.订购单 WHERE 供货方 IS NOT NULL)
- --删除现在没有任何订购单记录的供应商记录
从单个基本表选取某些行和某些列,并且包含基本表的关键字所定义的视图
- CREATE VIEW emp_v1 AS
- SELECT 职工号,仓库号,姓名
- FROM 基础.职工
视图是虚拟表,所有对视图的操作实际上都要转换成对基本表的操作!
执行查询:等价于AS后面的SELECT语句;
SELECT * FROM emp_v1
同时,也可以对视图进行插入、删除、更新等,这里就提一下插入:
INSERT INTO emp_v1 VALUES('E13','WH1','张三')
等价于对基本表中,被选取的职工号、仓库号、姓名这三列进行插入,其他的列会为NULL或DEFAULT,这时可能会因为完整性约束而导致插入失败。
WITH CHECK OPTION
:视图上的插入或更新操作必须满足视图定义的WHERE条件,否则操作会被拒绝并产生错误。WITH CHECK OPTION
:插入或更新操作不会受视图WHERE条件的限制,但插入或更新后的数据可能不会在视图中显示出来。- CREATE VIEW emp_v2 AS
- SELECT 仓库.仓库号,城市,职工号,姓名
- FROM 基础.职工 JOIN 仓储.仓库 ON 职工.仓库号 = 仓库.仓库号
之后查询:
- SELECT 职工号,姓名 FROM emp_v2
- WHERE 城市 = '北京'
- --定义视图的时候可以指定列名,只是一般都直接用基本表的名字,所以省略了
- CREATE VIEW emp_v3(职工号,姓名,月工资,年工资) AS
- SELECT 职工号,姓名,工资,工资*12
- FROM 基础.职工
修改:
删除:
变量声明
DECLARE @<变量名> <数据类型> [,@<变量名> <数据类型>...]
注意:变量名前必须有@前缀,以便和关系的属性名相区分
赋值
DECLARE <游标名> CURSOR FOR <SELECT-查询>
游标可以看作是一个临时存储或临时文件,它的内容就是SELECT语句的查询结果。
- DECLARE wh_cursor CURSOR FOR
- SELECT 仓库号,城市,面积 FROM 仓储.仓库
执行该语句意味着执行CURSOR语句中的SELECT查询,并使游标指针指向查询结果的第一条记录。只能打开已经声明但还没有打开的游标。
OPEN wh_cursor
INTO后的主变量要与游标中的SELECT的字段相对应。
该语句的功能是取出游标的当前记录并送入主变量,同时使游标指针指向下一条记录。
使用全局变量@@FETCH_STATUS来判断FETCH语句对游标的操作状态
循环是否继续读取游标: WHILE @@FETCH_STATUS=0
- FETCH FROM wh_cursor INTO @whno,@city,@area
- WHILE @@FETCH_STATUS=0
- BEGIN
- PRINT @whno+' '+@ciry+STR(@area,4)
- FETCH FROM wh_cursor INTO @whno,@city,@area
- END
CLOSE <游标名>
此时系统并没有完全释放游标,可以再次OPEN打开
CLOSE wh_cursor
DEALLOCATE <游标名>
释放以后就无法再OPEN打开了
DEALLOCATE wh_cursor
游标还可以嵌套:
来源于C/S服务器数据库体系结构,在C/S结构的数据库中,数据库端还可以存放程序,因为这些程序以数据库对象的形式存储在数据库中,所以称为存储过程。
几点说明:
使用带有参数和返回值的简单过程查询指定仓库订单金额大于指定值的订单数,查询结果通过RETURN语句返回
- --创建
- CREATE PROCEDURE useGetOrderNum
- @whno char(6), @sum money
- AS
- DECLARE @count int
- SELECT @count = COUNT(*) FROM 订货.订购单
- WHERE 金额>=@sum AND 经手人 IN
- (SELECT 职工号 FROM 基础.职工 WHERE 仓库号 = @whno)
- RETURN @count
-
-
- --执行
- DECLARE @count int
- EXECUTE @count = uspGetOrderNum 'WH1',1000
- PRINT 'WH1仓库金额在1000以上的订单数是:'+STR(@count)
触发器和存储过程都是事先设计好存储在数据库中的,但是不同的是,触发器不需要专门调用或执行。(有DML(数据操作语言)、DDL(数据定义语言)、LOGIN触发器)
1. DML触发器依附于表(或视图)。
2. DML触发器分为
3. 触发器的三个要素:
它们的作用:
1 使用包含提醒消息的DML触发器
- CREATE TRIGGER reminder1
- ON 仓储.库存
- FOR UPDATE
- AS
- DECLARE @amount int
- SELECT @amount=数量 FROM
- inserted
- IF @amount<5
- RAISERROR (‘库存数量已经小于5!’, 16, 10) --报错语句
2 由于CHECK约束只能定义列级或表级约束,表间的任何约束或业务规则都必须通过定义触发器来实现。
- CREATE TRIGGER isSameCity ON 订货.订购单
- FOR INSERT,UPDATE AS
- DECLARE @city char(10), @addr char(20), @sno char(5)
- --从新欸顶订货单记录得到供货方和经手人信息
- SELECT @sno = 供货方, @eno = 经手人 FROM inserted
- --若指定了供应商则做如下操作
- IF @sno IS NOT NULL
- BEGIN --得到发出该订单仓库所在城市
- SELECT @city = 城市 FROM 仓储.仓库 WHERE 仓库号 IN
- (SELECT 仓库号 FROM 基础.职工 WHERE 职工号 = @eno)
- --得到供应商的地址
- SELECT @addr = 地址 FROM 订货.供应商 WHERE 供应商号 = @sno
- --如果仓库和供应商在不同城市,且存在同城的供应商则拒绝
- IF @city!=@addr AND
- EXISTS (SELECT * FROM 订货.供应商 WHERE @city = 地址)
- BEGIN
- RAISERROR('本地有供应商,订购单不许发往异地!',16,1)
- ROLLBACK TRANSACTION
- END
- END
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
保证数据库安全是对数据库系统的基本要求。
数据库安全的核心问题:防止数据被非法使用和恶意破坏,是要防范非法用户的故意窃取和破坏(人为)
数据库安全的核心问题是:身份识别。
谁来管理?
要访问哪个数据库,就必须在此数据库下建立与登录用户相对应的数据库用户
在已经 USE 本数据库之后,建立角色不需要指定数据库
角色一般分为:系统管理员角色、后台数据管理角色、客户角色
1.可以将用户指定为角色的成员
2.用户自动从角色继承权限
3.可以取消用户的角色成员资格
数据库管理中角色代表了一种只能,,每个数据库用户可以担当一个或多个角色,为此需要将数据库用户指定为数据库角色的成员。
先切换到sa用户
系统初始只有一个sa用户,每个数据库用户的权限都来源于sa
通过授权GRANT,收回授权REVOKE动态管理权限
例题:仓储订货”数据库的安全控制解决方案
- --将wang指定为”仓储订货“的DBA
- sp_addrolemember 'db_owner','wang'
-
- --授权所有用户都可以查询除职工工资以外的所有信息
- GRANT SELECT ON 仓储.仓库 TO public
- GRANT SELECT ON 仓储.库存 TO public
- GRANT SELECT ON 基础.职工(职工号,仓库号,姓名,班组长) TO public
- GRANT SELECT ON 基础.器件 TO public
- GRANT SELECT ON 订货.供应商 TO public
- GRANT SELECT ON 订货.订购单 TO public
- GRANT SELECT ON 订货.订购明细 TO public
-
- --建立角色store_man和order_man,然后按要求授权
- CREATE ROLE store_man
- CREATE ROLE order_man
-
- GRANT INSERT,UPDATE(数量),DELETE ON 仓储.库存 TO store_man
-
- GRANT INSERT,UPDATE(经手人,供货方,订购日期,金额),DELETE ON 订货.订购单 TO order_man
- GRANT INSERT,UPDATE(数量,单价),DELETE ON 订货.订购明细 TO order_man WITH GRANT OPTION
-
- --指定用户zhang为角色store_man的成员,指定wu为角色order_man的成员
- sp_addrolemember 'store_man','zhang'
- sp_addrolemember 'order_man','wu'
-
- --授权用户zhang可以对”器件“表进行插入操作
- GRANT INSERT ON 基础.器件 TO zhang WITH GRANT OPTION
-
- --授权zhang可以对”器件“表进行删除操作
- GRANT DELETE ON 基础.器件 TO zhang
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
在这之后,登陆zhang,给huang授权向基础.器件的插入、删除操作,插入可以成功,因为有 WITH GRANT OPTION。
但是,以wu的身份给huang授权:
GRANT INSERT,DELETE ON 订货.订购明细 TO huang
这时就不能成功了,因为wu的这个权限是从order_man身上继承下来的,继承要用AS短语说明以哪个角色进行授权,所以应该:
GRANT INSERT,DELETE ON 订货.订购明细 TO huang AS order_man
REVOKE INSERT ON 基础.器件 FROM huang
同样,如果以wu的身份收回对huang的授权,也无法收回,因为wu是以order_man角色完成授权的,要加AS:
REVOKE INSERT ON 订货.订购明细 FROM huang AS order_man
架构:对象的容器
通过用户管理对象,删除用户时,通过该用户建的表或对象都要删除,为安全管理带来很多麻烦
通过架构管理对象的特点:
- --用户wang以DBA身份将对架构”仓储“的INSERT权限授予zhang
- GRANT INSERT ON SCHEMA :: 仓储 TO zhang
-
- --用户wang以DBA身份授予zhang在”仓储“架构上的CONTROL权限
- GRANT CONTROL ON SCHEMA :: 仓储 TO zhang
- --收回用户zhang在架构”仓储“上的INSERT权限
- REVOKE INSERT ON SCHEMA :: 仓储 FROM zhang
- --将”器件“表的所有权传递给用户wu
- ALTER AUTHORIZATION ON 基础.器件 TO wu
-
- --将”基础“架构的所有权传递给用户tang
- ALTER AUTHORIZATION ON SCHEMA :: 基础 TO tang
-
- --将”器件“表的所有权传递给所属架构的所有者
- ALTER AUTHORIZATION ON 基础.器件 TO SCHEMA OWNER
- --将器件表从基础架构移动到仓储架构
- ALTER SCHEMA 仓储 TRANSFER 基础.器件
授权可以成功,但是只有用户zhang在”仓储“架构下可以创建表,tang在”基础“架构下可以创建表,wu在两种架构下都无法创建表。
一个用户的权限包括:
执行DENY X TO A的效果
BEGIN TRANSACTION
成功:COMMIT TRANSACTION
失败:ROLLBACK TRANSACTION(回到事务起始点)
保存:SAVE TRANSACTION savepoint_name
取消:ROLLBACK TRANSACTION savepoint_name
可串行性描述的是事务的隔离性。
读封锁,简称S锁; 在读数据的时候,不允许其他用户对该数据进行任何修改;
排他锁,简称X锁; 进行修改操作时,拒绝来自其他用户的任何封锁,但不拒绝一般的查询(即不能避免脏读)
防止其他用户在同一时刻修改同意记录
WITH(<table_hint>)
关键字:
TABLOCK | 对表共享封锁,读完立即释放 | 可以避免脏读,但不具有可重复读 |
HOLDLOCK | 与TABLOCK一起用,将共享锁持续到事务结束 | 保证可重复读 |
NOLOCK | 不进行封锁,仅应用于SELECT | 可能会读取未提交的数据,导致脏读 |
TABLOCKX | 实施独占封锁 | |
UPDLOCK | 实施更新封锁 | 可以对其他记录实施共享封锁,但是不允许对表实施共享封锁和独占封锁 |
没有发生死锁也有可能某个事务永远处于等待状态
避免活锁:先来先服务(排队)
隔离级别 | 封锁 | 脏读 | 不可重复读 | 幻象 | 丢失更新 |
未提交读(READ UNCOMMITTED) | NOLOCK | 是 | 是 | 是 | 是 |
提交读(READ COMMITTED) | TABLOCK | 否 | 是 | 是 | 是 |
可重复读(REPEATABLE READ) | TABLOCK+HOLDLOCK | 否 | 否 | 否 | 是 |
可串行化(SERIALIZABLE) | TABLOCKX 或UPDLOCK | 否 | 否 | 否 | 否 |
优化存储的手段
- --为”仓储订货“数据库增加一个5M大小的物理文件
- ALTER DATABASE 仓储.订货
- ADD FILE
- (NAME = Test1dat2,
- FILENAME = 'C:\mssql\data\t1dat2.ndf',
- SIZE = 5MB,
- MAXSIZE = 100MB,
- FILEGROWTH = 5MB)
-
- -- 将”仓储订货“数据库test1dat2所对应的物理文件增加到10M大小
- ALTER DATABASE 仓储.订货
- MODIFY FILE
- (NAME = test1dat2,
- SIZE = 10MB)
-
- -- 将“仓储订货”数据库的test1dat2文件改名为test1dat1
- ALTER DATABASE 仓储.订货
- MODIFY FILE
- (NAME = Test1dat2,
- NEWNAME = Test1dat1)
-
- -- 将“仓储订货”数据库的test1dat1文件删除
- ALTER DATABASE 仓储订货
- REMOVE FILE test1dat1
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
例:将“仓储订货”数据库的主数据文件orderdat/mdf(逻辑文件名是order_dat)移动到
d:\mssql\data目录下
实现步骤:
- ALTER DATABASE 仓储订货
- MODIFY FILE
- (NAME = order_dat,
- FILENAME = 'd:\mssql\dadta\orderdat.mdf')
文件组是将物理存储文件分组;
文件组分为主文件组和用户定义文件组(FILEGROUP指定)两大类;
一个物理文件值只可以是一个文件组的成员;
文件组与日志无关,日志空间与数据空间是分开管理的;
使用文件组可以把指定数据存储到指定位置。
解决硬件空间不够 ;
提高对数据库的访问速度。
例6 创建一个数据库MyDB,该数据库包括一个主数据文件、一个用户定义文件组和一个日志文件。
如何验证MyTable及其数据存储到了指定物理文件?
添加文件组
添加物理文件
双热机备份:作为服务器的两台计算机同时同步工作,一个主,一个从,连哥哥服务器的数据每时每刻都同步;
双工备份:一台计算机上有双路存储通道(两个控制器和两组存储介质,每组存储介质在各自控制器控制下),计算机工作时两组存储介质同步更新;
镜像:一个存储控制器下有两组存储介质,以镜像方式工作,具有相同数据;
冗余磁盘阵列:RAID0,RAID1,RAID2;
数据库备份技术(数据库管理系统功能,前面几个都是操作系统的):将数据库存储介质上的数据备份到脱机的存储介质上。
备份是定期的,不是定时的,因此不能完全恢复数据库,只能恢复到制作备份的那一时刻;
日志是实时的,是对备份的补充,记录下所有对数据库的更新操作;
为了保证日志的安全,应该将日志和主数据库安排在不同的存储设备上。
简单恢复模型 :恢复到最新的备份,只能做数据库备份,不能做日志备份,会丢失数据;
完全恢复模型:恢复到故障点状态,使用数据库备份和事务日志备份提供对介质故障的完全防范。
'ALTER DATABASE database_name SET RECOVERY FULL' 修改为完全恢复。
恢复的时候不允许操作,备份的时候允许操作。
例子
系统数据库也要备份,必须经常性地、定期地备份master数据库(只能进行全备份)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。