MySql笔记二——约束&事务

一、约束

1、概念:对表中的数据进行限定,保证数据的正确性、有效性和完整性。

2、分类:

  1. 主键约束:primary key
  • 含义:非空且唯一
  • 一张表只能有一个字段为主键
  • 主键就是表中记录的唯一标识
  1. 非空约束:not null
    • 值不能为null
  2. 唯一约束:unique
    • 值不能重复
    • MySql中唯一约束限定的列的值可以有多个null
  3. 外键约束:foreign key
    • 让表于表产生关系,从而保证数据的正确性。(阿里规范:不得使用外键与级联,一切外键概念必须在应用层解决)

3、语法

1、主键约束语法

1、创建表时添加

在创建表时,添加主键约束
		create table 表名(
			id int primary key,-- 给id添加主键约束
			name varchar(20)
		);

2、创建表后添加

语法:
ALTER TABLE 表名 add primary key(字段名);

举例:
ALTER TABLE stu add primary key(id);

3、删除主键

ALTER TABLE 表名 DROP PRIMARY KEY;

4、自动增长

概念:如果某一列是数值类型的,使用 auto_increment 可以来完成值得自动增长

1. 在创建表时,添加主键约束,并且完成主键自增长
		create table stu(
			id int primary key auto_increment,-- 给id添加主键约束
			name varchar(20)
		);
		
2.创建表后添加
	ALTER TABLE stu MODIFY id INT AUTO_INCREMENT;
	
3. 删除自动增长
	ALTER TABLE stu MODIFY id INT;

2、唯一约束

1、创建表时添加约束

CREATE TABLE stu(
			id INT,
			phone_number VARCHAR(20) UNIQUE -- 添加了唯一约束
		
		);
* 注意mysql中,唯一约束限定的列的值可以有多个null

2、创建表后添加约束

ALTER TABLE 表名 add unique(字段名);

3、删除唯一约束

1.先查看约束名
show create table 表名;

2.找到唯一约束名,然后删除
ALTER TABLE 表名 DROP INDEX 约束名;

3、外键约束

1、创建表时添加约束

create table 表名(
				....
				外键列
				constraint 外键名称 foreign key (外键列名称) references 主表名称(主表列名称)
			);

2、创建表后添加约束

ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段名称) REFERENCES 主表名称(主表列名称);

3、删除非空约束

ALTER TABLE 表名 DROP FOREIGN KEY 外键名称;

2、非空约束语法

1、创建表时添加约束

CREATE TABLE stu(
			id INT,
			NAME VARCHAR(20) NOT NULL -- name为非空
		);

2、创建表后添加约束

ALTER TABLE 表名 MODIFY 字段名 字段类型 NOT NULL;

3、删除非空约束

ALTER TABLE 表名 MODIFY 字段名 字段类型;

5、级联操作

用于操作具有外键关系的表,使其级联更新或级联删除。(阿里规范:不得使用外键与级联,一切外键概念必须在应用层解决)

1、添加级联

LTER TABLE 表名 ADD CONSTRAINT 外键名称 
					FOREIGN KEY (外键字段名称) REFERENCES 主表名称(主表列名称) ON UPDATE CASCADE ON DELETE CASCADE  ;

2、分类

  • 级联更新:ON UPDATE CASCADE
  • 级联删除:ON DELETE CASCADE

二、数据库的设计

2.1 多表之间的关系

1、多表之间的关系分类

  • 一对一(了解)

    如:人和身份证

    分析:一个人只有一个身份证,一个身份证只能对应一个人

  • 一对多(多对一):

    如:部门和员工

    分析:一个部门有多个员工,一个员工只能对应一个部门

  • 多对多:

    如:学生和课程

    分析:一个学生可以选择很多门课程,一个课程也可以被很多学生选择

2、实现关系

  • 一对一实现方式:一对一关系实现,可以在任意一方添加唯一外键指向另一方的主键。
  • 一对多实现方式:在多的一方建立外键,指向一的一方的主键
  • 多对多实现方式:多对多关系实现需要借助第三张中间表。中间表至少包含两个字段,这两个字段作为第三张表的外键,分别指向两张表的主键

3、小练习

-- 创建旅游线路分类表 tab_category
		-- cid 旅游线路分类主键,自动增长
		-- cname 旅游线路分类名称非空,唯一,字符串 100
		CREATE TABLE tab_category (
			cid INT PRIMARY KEY AUTO_INCREMENT,
			cname VARCHAR(100) NOT NULL UNIQUE
		);
		
		-- 创建旅游线路表 tab_route
		/*
		rid 旅游线路主键,自动增长
		rname 旅游线路名称非空,唯一,字符串 100
		price 价格
		rdate 上架时间,日期类型
		cid 外键,所属分类
		*/
		CREATE TABLE tab_route(
			rid INT PRIMARY KEY AUTO_INCREMENT,
			rname VARCHAR(100) NOT NULL UNIQUE,
			price DOUBLE,
			rdate DATE,
			cid INT,
			FOREIGN KEY (cid) REFERENCES tab_category(cid)
		);
		
		/*创建用户表 tab_user
		uid 用户主键,自增长
		username 用户名长度 100,唯一,非空
		password 密码长度 30,非空
		name 真实姓名长度 100
		birthday 生日
		sex 性别,定长字符串 1
		telephone 手机号,字符串 11
		email 邮箱,字符串长度 100
		*/
		CREATE TABLE tab_user (
			uid INT PRIMARY KEY AUTO_INCREMENT,
			username VARCHAR(100) UNIQUE NOT NULL,
			PASSWORD VARCHAR(30) NOT NULL,
			NAME VARCHAR(100),
			birthday DATE,
			sex CHAR(1) DEFAULT '男',
			telephone VARCHAR(11),
			email VARCHAR(100)
		);
		
		/*
		创建收藏表 tab_favorite
		rid 旅游线路 id,外键
		date 收藏时间
		uid 用户 id,外键
		rid 和 uid 不能重复,设置复合主键,同一个用户不能收藏同一个线路两次
		*/
		CREATE TABLE tab_favorite (
			rid INT, -- 线路id
			DATE DATETIME,
			uid INT, -- 用户id
			-- 创建复合主键
			PRIMARY KEY(rid,uid), -- 联合主键
			FOREIGN KEY (rid) REFERENCES tab_route(rid),
			FOREIGN KEY(uid) REFERENCES tab_user(uid)
		);

2.2 数据库设计的范式

1、概念:设计数据库时,需要遵循的一些规范。要遵循后边的范式要求,必须先遵循前边的所有范式要求

​ 设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,各种范式呈递次规范,越高的范式数据库冗余越小。

​ 目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。

2、范式分类

  • 第一范式(1NF):每一列都是不可分割的原子数据项。

    • 每一列属性都是不可再分的属性值,确保每一列的原子性

    • 两列的属性相近或相似或一样,尽量合并属性一样的列,确保不产生冗余数据。

  • 第二范式(2NF):在1NF的基础上,非码属性必须完全依赖于码(在1NF基础上消除非主属性对主码的部分函数依赖)。

    • 每一行的数据只能与其中一列相关,即一行数据只做一件事。只要数据列中出现数据重复,就要把表拆分开来。

如上图,一个人同时订几个房间,就会出来一个订单号多条数据,这样子联系人都是重复的,就会造成数据冗余。我们应该把他拆开来。

  • 第三范式(3NF):在2NF基础上,任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖)。

    • 数据不能存在传递关系,即没个属性都跟主键有直接关系而不是间接关系。像:a-->b-->c 属性之间含有这样的关系,是不符合第三范式的。

3、扩充

* 几个概念:
		1. 函数依赖:A-->B,如果通过A属性(属性组)的值,可以确定唯一B属性的值。则称B依赖于A
		
					例如:学号-->姓名。  (学号,课程名称) --> 分数
					
		2. 完全函数依赖:A-->B, 如果A是一个属性组,则B属性值得确定需要依赖于A属性组中所有的属性值。
		
					例如:(学号,课程名称) --> 分数
					
		3. 部分函数依赖:A-->B, 如果A是一个属性组,则B属性值得确定只需要依赖于A属性组中某一些值即可。
		
					
					例如:(学号,课程名称) -- > 姓名
		4. 传递函数依赖:A-->B, B -- >C . 如果通过A属性(属性组)的值,可以确定唯一B属性的值,在通过B属性(属性组)的值可以确定唯一C属性的值,则称 C 传递函数依赖于A
		
					例如:学号-->系名,系名-->系主任
					
		5. 码:如果在一张表中,一个属性或属性组,被其他所有属性所完全依赖,则称这个属性(属性组)为该表的码
		
					例如:该表中码为:(学号,课程名称)
					* 主属性:码属性组中的所有属性
					* 非主属性:除过码属性组的属性

4、总结

三大范式的作用:优化数据库的结构,减少数据库的冗余。

一范式:确定表的原子性,表中的每一列都不可再分。

二范式:在1范式的基础上,消除表中的部分函数依赖--》需要确保表中的每一列都和主键相关,而不能只于主键中的某一部分相关。(主要针对联合主键)

如:假设存在联合主键(a,b),其他列c,d。则该表需要满足:(a,b)-->c ,(a,b)-->d。

如果出现:a-->c则该表不符合规范

三范式:在2范式的基础上,消除表中的传递依赖--》需要确保表中的每一列都和主键直接相关,而不能间接相关。

如:假设存在主键m,非主键x,y。则需要满足,m-->x	m-->y。

如果出现:m-->x , x-->y 然后得出 m-->y 则该表不符合规范。

如何使用三大范式去验证表设计的是否规范?

表中的每一列都与主键或联合主键直接相关。

其他列只与主键的某一部分相关 ×

通过主键和非主键列确定其他列 ×

三、事务

事务的基本介绍

1、什么是事务?

事务是由单独单元的一个或多个sql组成,这个单元中的sql之间是相互依赖的。当单独单元中的一个sql发生错误,则事务失败,会将整个单元回滚到事务开始之前。当单独单元中的所有sql都执行成功,则事务会顺利进行。

举一个不太恰当的例子,在炎热的夏天你想从冰箱拿一瓶可乐,你可以将从冰箱拿可乐看作一个事务,这个事务包括这几个操作:打开冰箱、选择可乐、关闭冰箱。如果这三个中的任何一个操作失败,你都会回到打开冰箱前的状态,如果这三个操作都成功了,你才可以喝可乐。

2、操作

  • 开启事务:start transaction;
  • 提交事务:commit;
  • 回滚事务:rollback;

3、例子

CREATE TABLE account (
			id INT PRIMARY KEY AUTO_INCREMENT,
			NAME VARCHAR(10),
			balance DOUBLE
		);
		-- 添加数据
		INSERT INTO account (NAME, balance) VALUES ('zhangsan', 1000), ('lisi', 1000);
		SELECT * FROM account;
		UPDATE account SET balance = 1000;
		-- 张三给李四转账 500 元
		
		-- 0. 开启事务
		START TRANSACTION;
		-- 1. 张三账户 -500
		
		UPDATE account SET balance = balance - 500 WHERE NAME = 'zhangsan';
		-- 2. 李四账户 +500
		-- 出错了...
		UPDATE account SET balance = balance + 500 WHERE NAME = 'lisi';
		
		-- 发现执行没有问题,提交事务
		COMMIT;
		
		-- 发现出问题了,回滚事务
		ROLLBACK;

4、MySQL数据库中事务默认自动提交

5、事务提交的两种方式

  • 自动提交

    • mysql就是自动提交的
    • 一条DML(增删改)语句会自动提交一次事务。
  • 手动提交:

    • Oracle 数据库默认是手动提交事务
    • 需要先开启事务,再提交

6、修改事务的默认提交方式

  • 查看事务的默认提交方式:SELECT @@autocommit; -- 1 代表自动提交 0 代表手动提交
  • 修改默认提交方式: set @@autocommit = 0;

事务的ACID原则与隔离级别

1、事务的四大特征

  • 原子性:每一个事务都是不可分割的最小操作单位,要么同时成功,要么同时失败。
  • 一致性:事务操作前后,数据总量不变。如银行转账,事务执行前后,数据的总量是一致的,不会凭空增加,也不会凭空减少。
  • 持久性:当事务提交或回滚后,数据库会持久化的保存数据。
  • 隔离性:多个事务之间,相互独立,互不干扰。

2、事务的隔离级别

  1. 概念:多个事务之间隔离的,相互独立的。但是如果多个事务操作同一批数据,则会引发一些问题,设置不同的隔离级别就可以解决这些问题。

  2. 存在问题

    • 脏读:一个事务读取到另一个事务未提交的数据。
    • 不可重复读:一个事务读取表中的某一行数据,多次读取的结果不一致。
    • 幻读:在一个事务内读取到别的事务插入的数据,导致前后读取不一致。

tip:

  1. 脏读和不可重复读的区别:脏读是读取前一事务未提交的数据,而不可重复读是重新读取了前一事务已提交的数据。
  2. 幻读与不可重复读的区别:不可重复读读取到的是更新(update)数据,而幻读读取到的是插入(insert)数据。

在某些情况下,不可重复读与幻读是允许存在的,但是脏读是不允许存在的。

  1. 隔离级别

    1、read uncommitted:读未提交

    • 产生的问题:脏读、不可重复读、幻读

    2、read committed:读已提交 (Oracle)

    • 产生的问题:不可重复读、幻读

    3、repeatable read:可重复读 (MySQL默认)

    • 产生的问题:幻读

    4、serializable:串行化

    • 可以解决所有的问题
  • 注意:隔离级别从小到大安全性越来越高,但是效率越来越低
  • 数据库查询隔离级别:
    • select @@tx_isolation;
  • 数据库设置隔离级别:
    • set global transaction isolation level 级别字符串;
* 演示:
		set global transaction isolation level read uncommitted;
		start transaction;
		-- 转账操作
		update account set balance = balance - 500 where id = 1;
		update account set balance = balance + 500 where id = 2;
posted @ 2020-12-26 16:19  沙滩拾贝  阅读(49)  评论(0编辑  收藏  举报