sql之约束事务与视图
Posted eyes++
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sql之约束事务与视图相关的知识,希望对你有一定的参考价值。
一:约束
含义:一种限制,用于限制表中的数据,为了保证表中数据的准确和可靠性
分类:六大约束
NOT NULL:非空约束,用于保证该字段的值不能为空
DEFAULT:默认约束,用于保证该字段有默认值
PRIMARY KEY:主键约束,用于保证该字段唯一且非空
UNIQUE:唯一约束,用于保证该字段具有唯一性,但可以为空
CHECK:检查约束(mysql中不支持,如果写了也不会报错)
FOREIGN KEY:外键约束,用于限制两个表的关系,保证该字段的值必须来自于主表关联列的值
添加约束的时机:
1. 创建表时
2. 修改表时
约束的添加分类:
列级约束:六大约束语法都支持,但外键约束没有效果
表级约束:除了非空和默认约束,其他都支持
事实上对于外键约束,有的大佬有一些看法,如下,大佬的csdn博客账号是:去吧猫头夜鹰
![](https://image.cha138.com/20211017/905470d6e9d9456faaf7861590125965.jpg)
![](https://image.cha138.com/20211017/35a22ff275d94e14b2713ebdaaaacafb.jpg)
![](https://image.cha138.com/20211017/ebc0f0de3b9040feb00094afdba13b39.jpg)
1. 创建表时添加列级约束
依次执行后创建两个表。
CREATE DATABASE students;
CREATE TABLE major(
id INT PRIMARY KEY,
majorName VARCHAR(20)
);
CREATE TABLE stuinfo (
id INT PRIMARY KEY, # 主键约束
stuName VARCHAR (20) NOT NULL, # 非空约束
gender CHAR(1) CHECK (gender = "男" OR gender = "女"), # 检查约束
seat INT UNIQUE, # 唯一约束
age INT DEFAULT 18, # 默认约束
majorId INT REFERENCES major(id) # 外键约束
) ;
查看stuinfo表详情如下:
2. 创建表时添加表级约束
表级约束在各个字段的最下面
语法:constraint 约束名 约束类型(字段名)
DROP TABLE IF EXISTS stuinfo;
CREATE TABLE stuinfo(
id INT,
stuname VARCHAR(20),
gender CHAR(1),
seat INT,
age INT,
majorid INT,
CONSTRAINT pk PRIMARY KEY(id), # 主键
CONSTRAINT uq UNIQUE(seat), # 唯一键
CONSTRAINT ck CHECK(gender = '男' OR gender = '女'), # 检查
CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id) # 外键
);
SHOW INDEX FROM stuinfo;
事实上约束名不是必须的,因此还可以这样:
DROP TABLE IF EXISTS stuinfo;
CREATE TABLE stuinfo(
id INT,
stuname VARCHAR(20),
gender CHAR(1),
seat INT,
age INT,
majorid INT,
PRIMARY KEY(id), # 主键
UNIQUE(seat), # 唯一键
CHECK(gender = '男' OR gender = '女'), # 检查
FOREIGN KEY(majorid) REFERENCES major(id) # 外键
);
SHOW INDEX FROM stuinfo;
由下可见此时除主键外字段名成为了约束名。
3. 创建表时添加约束的通用写法
DROP TABLE IF EXISTS stuinfo;
CREATE TABLE stuinfo (
id INT PRIMARY KEY,
stuName VARCHAR (20) NOT NULL,
gender CHAR(1) CHECK (gender = "男" OR gender = "女"),
seat INT UNIQUE,
age INT DEFAULT 18,
majorId INT,
CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id)
) ;
SHOW INDEX FROM stuinfo;
4. 修改表时添加约束
添加列级约束:
alter table 表名 modify column 字段名 字段类型 新约束;
添加表级约束:
alter table 表名 [constraint 约束名] 约束类型(字段名) [外键的引用];
示例代码如下:
DROP TABLE IF EXISTS stuinfo;
CREATE TABLE stuinfo(
id INT,
stuname VARCHAR(20),
gender CHAR(1),
seat INT,
age INT,
majorid INT
);
# 1.添加非空约束
ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20) NOT NULL;
# 2.添加默认约束
ALTER TABLE stuinfo MODIFY COLUMN age INT DEFAULT 18;
# 3.添加主键约束
ALTER TABLE stuinfo MODIFY COLUMN id INT PRIMARY KEY; # 列级约束
ALTER TABLE stuinfo ADD PRIMARY KEY(id); # 表级约束
# 4.添加唯一约束
ALTER TABLE stuinfo MODIFY COLUMN seat INT UNIQUE; # 列级约束
ALTER TABLE stuinfo ADD UNIQUE(seat); # 表级约束
# 5.添加外键
ALTER TABLE stuinfo ADD FOREIGN KEY(majorid) REFERENCES major(id); # 默认约束名
ALTER TABLE stuinfo ADD CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id); # 自定义约束名
5. 修改表时删除约束
# 1.删除非空约束
ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20) NULL;
# 2.删除默认约束
ALTER TABLE stuinfo MODIFY COLUMN age INT;
# 3.删除主键约束
ALTER TABLE stuinfo DROP PRIMARY KEY;
# 4.删除唯一约束
ALTER stuinfo DROP INDEX seat;
# 5.删除外键
ALTER TABLE stuinfo DROP FOREIGN KEY majorid;
二:事务
事务是在数据库上按照一定的逻辑顺序执行的任务序列,既可以由用户手动执行,也可以由某种数据库程序自动执行。
事务实际上就是对数据库的一个或者多个更改。当你在某张表上创建更新或者删除记录的时,你就已经在使用事务了。控制事务以保证数据完整性,并对数据库错误做出处理,对数据库来说非常重要。
实践中,通常会将很多 SQL 查询组合在一起,并将其作为某个事务一部分来执行。
事务具有以下四个标准属性,通常用缩略词 ACID 来表示:
- 原子性:保证任务中的所有操作都执行完毕;否则,事务会在出现错误时终止,并回滚之前所有操作到原始状态。
- 一致性:如果事务成功执行,则数据库的状态得到了进行了正确的转变。
- 隔离性:保证不同的事务相互独立、透明地执行。
- 持久性:即使出现系统故障,之前成功执行的事务的结果也会持久存在。
1.事务的使用
事务的创建
隐式事务:事务没有明显的开启和结束的标记,比如insert、update、delete语句。
显式事务:事务具有明显的开启和结束的标记
前提:必须先设置自动提交功能为禁用,禁用语句为:set autocommit=0
一个标准的事务流程如下:
# 步骤一:开启事务
set autocommit=0;
start transaction; # 可选
# 步骤二:编写事务中的sql语句(select insert update delete)
语句一;
语句二;
...
# 步骤三:结束事务
commit; # 提交事务
rollback; # 回滚事务
示例如下:
先插入数据,方便事务操作:
ALTER TABLE stuinfo ADD money INT;
INSERT INTO stuinfo(id, stuname, money)
VALUE (1, "张三", 200);
INSERT INTO stuinfo(id, stuname, money)
VALUE (2, "罗老师", 600);
SELECT * FROM stuinfo;
然后张三和罗老师进行转账业务,罗老师给张三150元拿到张三事迹的使用权。转账流程如下:
# 开始事务操作
SET autocommit = 0;
START TRANSACTION;
UPDATE stuinfo SET money = 350 WHERE id = 1;
UPDATE stuinfo SET money = 450 WHERE id = 2;
COMMIT;
SELECT * FROM stuinfo;
如果没有执行到
commit
,那么操作是不会真正被执行的,比如下面的操作,在commit之前执行回滚,那么数据就不会发生变化。
SET autocommit = 0;
START TRANSACTION;
UPDATE stuinfo SET money = 5000 WHERE id = 1;
UPDATE stuinfo SET money = 4500 WHERE id = 2;
ROLLBACK;
#commit;
SELECT * FROM stuinfo;
2.事务的隔离级别
对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,如果没有采取必要的隔离机制,就会导致各种并发问题:
- 脏读:对于两个事务T1、T2,T1读取了已经被T2更新但还没有被提交的字段之后,若T2回滚,则T1读取的内容就是临时且无效的。
- 不可重复读:对于两个事务T1、T2,T1读取了一个字段,然后T2更新了该字段之后,T1再次读取了同一个字段,值就不同了。
- 幻读:对于两个事务T1、T2,T1从一个表中读取了一个字段,然后T2在该表中插入了一些新的行,之后如果T1再次读取同一个表,就会多出几行。
不可重复读和幻读比较:两者有些相似,但是前者针对的是update或delete,后者针对的insert。
鉴于上述并发问题,人们就为事务设置了隔离性,即数据库系统必须具有隔离并发运行各个事务的能力,使他们不会互相影响,避免各种并发问题。
数据库提供四种事务隔离级别:
- Read uncommitted:读未提交,顾名思义,就是可以读到未提交的内容。因此,在这种隔离级别下,查询是不会加锁的,也由于查询的不加锁,所以这种隔离级别的一致性是最差的,可能会产生“脏读”、“不可重复读”、“幻读”。如无特殊情况,基本是不会使用这种隔离级别的。
- Read committed:读提交,顾名思义,就是只能读到已经提交了的内容。这是各种系统中最常用的一种隔离级别,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”,但不能避免“幻读”和“不可重复读取”。该级别适用于大多数系统。这里多说点:那为什么“读提交”同“读未提交”一样,都没有查询加锁,但是却能够避免脏读呢?这就要说道另一个机制“快照(snapshot)”,而这种既能保证一致性又不加锁的读也被称为“快照读(Snapshot Read)”假设没有“快照读”,那么当一个更新的事务没有提交时,另一个对更新数据进行查询的事务会因为无法查询而被阻塞,这种情况下,并发能力就相当的差。而“快照读”就可以完成高并发的查询,不过,“读提交”只能避免“脏读”,并不能避免“不可重复读”和“幻读”。
- Repeatable read:可重复读,顾名思义,就是专门针对“不可重复读”这种情况而制定的隔离级别,自然,它就可以有效的避免“不可重复读”。在这个级别下,普通的查询同样是使用的“快照读”,但是,和“读提交”不同的是,当事务启动时,就不允许进行“修改操作(Update)”了,而“不可重复读”恰恰是因为两次读取之间进行了数据的修改,因此,“可重复读”能够有效的避免“不可重复读”,但却避免不了“幻读”,因为幻读是由于“插入或者删除操作(Insert or Delete)”而产生的。
- Serializable:这是数据库最高的隔离级别,这种级别下,事务“串行化顺序执行”,也就是一个一个排队执行。这种级别下,“脏读”、“不可重复读”、“幻读”都可以被避免,但是执行效率奇差,性能开销也最大,所以基本没人会用。
Oracle支持的2种事务隔离级别:READ COMMITED和SERIALIZABLE,Oracle默认的事务隔离级别是READ COMMITED。而MySQL支持四种事务隔离级别,MySQL的默认事务隔离级别是:REPEATABLE READ。
查看当前的事务隔离级别:
# 以下四种方法都可以查看
SHOW VARIABLES LIKE 'transaction%';
SHOW VARIABLES LIKE '%iso%';
SELECT @@GLOBAL.transaction_isolation;
SELECT @@SESSION.transaction_isolation;
注意show variables like 'tx_isolation%';
已经在MySQL5.7.20后被弃用。
设置隔离级别:
# 设置全局隔离级别
set global transaction isolation level REPEATABLE READ;
set global transaction isolation level READ COMMITTED;
set global transaction isolation level READ UNCOMMITTED;
set global transaction isolation level SERIALIZABLE;
# 设置会话隔离级别
set session transaction isolation level REPEATABLE READ;
set session transaction isolation level READ COMMITTED;
set session transaction isolation level READ UNCOMMITTED;
set session transaction isolation level SERIALIZABLE;
#通过配置文件设置隔离级别(重启生效)
[mysqld]
transaction-isolation = REPEATABLE-READ
transaction-isolation = READ-COMMITTED
transaction-isolation = READ-UNCOMMITTED
transaction-isolation = SERIALIZABLE
3.回滚点的演示
事务里面还有一个关键词savepoint
,功能类似于保存点,用法是:
savepoint 节点名;
示例如下:
SET autocommit=0;
START TRANSACTION;
UPDATE stuinfo SET money=300 WHERE id=1;
SAVEPOINT a; # 设置保存点
UPDATE stuinfo SET money=100 WHERE id=2;
ROLLBACK TO a; # 回滚到保存点
SELECT * FROM stuinfo;
三:视图
MySQL 从5.0.1版本开始提供视图功能,视图(View)是一种虚拟存在的表,同真实表一样,视图也由列和行构成,但视图并不实际存在于数据库中。行和列的数据来自于定义视图的查询中所使用的表,并且还是在使用视图时动态生成的。
数据库中只存放了视图的定义,并没有存放视图中的数据,这些数据都存放在定义视图查询所引用的真实表中。使用视图查询数据时,数据库会从真实表中取出对应的数据。因此,视图中的数据是依赖于真实表中的数据的。一旦真实表中的数据发生改变,显示在视图中的数据也会发生改变。
视图可以从原有的表上选取对用户有用的信息,那些对用户没用,或者用户没有权限了解的信息,都可以直接屏蔽掉,作用类似于筛选。这样做既使应用简单化,也保证了系统的安全。
视图的应用场景:
- 多个地方用到同样的查询结果
- 该查询结果使用的sql语句较为复杂
视图不同于数据表,他们的区别在于以下几点:
- 视图不是数据库中真实的表,而是一张虚拟表,其结构和数据是建立在对数据中真实表的查询基础上的。
- 存储在数据库中的查询操作 SQL 语句定义了视图的内容,列数据和行数据来自于视图查询所引用的实际表,引用视图时动态生成这些数据。
- 视图没有实际的物理记录,不是以数据集的形式存储在数据库中的,它所对应的数据实际上是存储在视图所引用的真实表中的。
- 视图是数据的窗口,而表是内容。表是实际数据的存放单位,而视图只是以不同的显示方式展示数据,其数据来源还是实际表。
- 视图是查看数据表的一种方法,可以查询数据表中某些字段构成的数据,只是一些 SQL 语句的集合。从安全的角度来看,视图的数据安全性更高,使用视图的用户不接触数据表,不知道表结构。
- 视图的建立和删除只影响视图本身,不影响对应的基本表。
视图与表在本质上虽然不相同,但视图经过定义以后,结构形式和表一样,可以进行查询、修改、更新和删除等操作。同时,视图具有如下优点:
- 定制用户数据,聚焦特定的数据:在实际的应用过程中,不同的用户可能对不同的数据有不同的要求。例如,当数据库同时存在时,如学生基本信息表、课程表和教师信息表等多种表同时存在时,可以根据需求让不同的用户使用各自的数据。学生查看修改自己基本信息的视图,安排课程人员查看修改课程表和教师信息的视图,教师查看学生信息和课程信息表的视图。
- 简化数据操作:在使用查询时,很多时候要使用聚合函数,同时还要显示其他字段的信息,可能还需要关联到其他表,语句可能会很长,如果这个动作频繁发生的话,可以创建视图来简化操作。
- 提高数据的安全性:视图是虚拟的,物理上是不存在的。可以只授予用户视图的权限,而不具体指定使用表的权限,来保护基础数据的安全。
- 共享所需数据:通过使用视图,每个用户不必都定义和存储自己所需的数据,可以共享数据库中的数据,同样的数据只需要存储一次。
- 更改数据格式:通过使用视图,可以重新格式化检索出的数据,并组织输出到其他应用程序中。
- 重用 SQL 语句:视图提供的是对查询操作的封装,本身不包含数据,所呈现的数据是根据视图定义从基础表中检索出来的,如果基础表的数据新增或删除,视图呈现的也是更新后的数据。视图定义后,编写完所需的查询,可以方便地重用该视图。
使用视图的时候,还应该注意以下几点:
- 创建视图需要足够的访问权限。
- 创建视图的数目没有限制。
- 视图可以嵌套,即从其他视图中检索数据的查询来创建视图。
- 视图不能索引,也不能有关联的触发器、默认值或规则。
- 视图可以和表一起使用。
- 视图不包含数据,所以每次使用视图时,都必须执行查询中所需的任何一个检索操作。如果用多个连接和过滤条件创建了复杂的视图或嵌套了视图,可能会发现系统运行性能下降得十分严重。因此,在部署大量视图应用时,应该进行系统测试。
1.视图的创建
创建视图的语法:
create view 视图名
as
查询语句;
使用示例:
USE myemployees;
# 查询邮箱中包含a字符的员工名、部门名和工种信息
CREATE VIEW myv1 # 创建视图
AS
SELECT last_name, department_name, job_title
FROM employees e
JOIN departments d ON e.department_id = d.department_id
JOIN jobs j ON j.job_id = e.job_id;
SELECT * FROM myv1 WHERE last_name LIKE '%a%';
2.视图的修改
方式一:
create or replace view 视图名
as
查询语句;
使用示例:
CREATE OR REPLACE VIEW myv1
AS
SELECT last_name, first_name, department_name, job_title
FROM employees e
JOIN departments d ON e.department_id = d.department_id
JOIN jobs j ON j.job_id = e.job_id;
SELECT * FROM myv1 WHERE last_name LIKE '%a%';
方式二:
alter view 视图名
as
查询语句;
使用示例:
ALTER VIEW myv1
AS
SELECT first_name, last_name, department_name, job_title
FROM employees e
JOIN departments d ON e.department_id = d.department_id
JOIN jobs j ON j.job_id = e.job_id
WHERE e.first_name LIKE '%s%';
SELECT * FROM myv1 WHERE last_name LIKE '%a%';
3.视图的查看和删除
查看语法:
DESC myv1; # 查看视图结构
SHOW CREATE VIEW myv1; # 可以查看视图的创建语句
查看得到的sql如下:
CREATE ALGORITHM = UNDEFINED DEFINER = `root` @`localhost` SQL SECURITY DEFINER VIEW `myv1` AS
SELECT
`e`.`first_name` AS `first_name`,
`e`.`last_name` AS `last_name`,
`d`.`department_name` AS `department_name`,
`j`.`job_title` AS `job_title`
FROM
(
(
`employees` `e`
JOIN `departments` `d`
ON (
(
`e`.`department_id` = `d`.`department_id`
)
)
)
JOIN `jobs` `j`
ON ((`j`.`job_id` = `e`.`job_id`))
)
WHERE (`e`.`first_name` LIKE '%s%')
删除语法:
drop view 视图名, 视图名,...
如果有兴趣了解更多相关内容,可以来我的个人网站看看:eyes++的个人空间
以上是关于sql之约束事务与视图的主要内容,如果未能解决你的问题,请参考以下文章