From 085239451d20ca994bffb8c9ce571cde3d14db64 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BA=84=E7=8F=8A=E7=8F=8A?= <3106036048@qq.com>
Date: Wed, 25 Oct 2023 23:25:29 +0800
Subject: [PATCH 1/2] =?UTF-8?q?=E4=BD=9C=E4=B8=9A?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
"48 \345\272\204\347\217\212\347\217\212/20230920 RBAC.md" | 3 ++-
.../20231014 \345\201\232\347\273\203\344\271\240.md" | 1 +
...200\201\345\270\210\350\256\262\351\242\230\347\233\256.md" | 1 +
...237\245\350\257\206\347\202\271\351\233\206\345\220\210.md" | 0
4 files changed, 4 insertions(+), 1 deletion(-)
create mode 100644 "48 \345\272\204\347\217\212\347\217\212/20231014 \345\201\232\347\273\203\344\271\240.md"
create mode 100644 "48 \345\272\204\347\217\212\347\217\212/20231015 \350\200\201\345\270\210\350\256\262\351\242\230\347\233\256.md"
create mode 100644 "48 \345\272\204\347\217\212\347\217\212/20231025 \347\237\245\350\257\206\347\202\271\351\233\206\345\220\210.md"
diff --git "a/48 \345\272\204\347\217\212\347\217\212/20230920 RBAC.md" "b/48 \345\272\204\347\217\212\347\217\212/20230920 RBAC.md"
index cd7e326..194f8c8 100644
--- "a/48 \345\272\204\347\217\212\347\217\212/20230920 RBAC.md"
+++ "b/48 \345\272\204\347\217\212\347\217\212/20230920 RBAC.md"
@@ -1,6 +1,7 @@
## RBAC是一种权限系统管理模型
-**RBAC**:基本模型有三个元素:用户、角色和权限。模型设计基于“多对多”原则,即多个用户可以具有相同的角色,一个用户可以具有多个角色。同样,可以将同一权限分配给多个角色,也可以将同一角色分配给多个权限。
+**RBAC**:什么是RBAC
+RBAC。英文名称Role-Based Access Control。顾名思义,就是基于**角色的权限控制系统**。理解的基本思路就是,在角色的前提下,**按照角色不同将权限分配到对应的角色,再将管理员设置成对应的角色,进而管理员获得权限。在管理员请求某个业务权限的时候,从数据库中查询该管理员所拥有的权限,并将请求的业务权限跟数据库比对。以此进行权限控制**
复习复习我又忘记这个了啊啊啊啊啊啊啊啊啊啊啊啊啊啊!!!!!
diff --git "a/48 \345\272\204\347\217\212\347\217\212/20231014 \345\201\232\347\273\203\344\271\240.md" "b/48 \345\272\204\347\217\212\347\217\212/20231014 \345\201\232\347\273\203\344\271\240.md"
new file mode 100644
index 0000000..d45a476
--- /dev/null
+++ "b/48 \345\272\204\347\217\212\347\217\212/20231014 \345\201\232\347\273\203\344\271\240.md"
@@ -0,0 +1 @@
+这天好像是做练习,然后去学点其他的好了 qwq
\ No newline at end of file
diff --git "a/48 \345\272\204\347\217\212\347\217\212/20231015 \350\200\201\345\270\210\350\256\262\351\242\230\347\233\256.md" "b/48 \345\272\204\347\217\212\347\217\212/20231015 \350\200\201\345\270\210\350\256\262\351\242\230\347\233\256.md"
new file mode 100644
index 0000000..0fb0432
--- /dev/null
+++ "b/48 \345\272\204\347\217\212\347\217\212/20231015 \350\200\201\345\270\210\350\256\262\351\242\230\347\233\256.md"
@@ -0,0 +1 @@
+了解了一下多对多的关系判断,每次都感觉自己又行了,做题又是依托shit
\ No newline at end of file
diff --git "a/48 \345\272\204\347\217\212\347\217\212/20231025 \347\237\245\350\257\206\347\202\271\351\233\206\345\220\210.md" "b/48 \345\272\204\347\217\212\347\217\212/20231025 \347\237\245\350\257\206\347\202\271\351\233\206\345\220\210.md"
new file mode 100644
index 0000000..e69de29
--
Gitee
From bb9bb492e6207dbaf04beda1c6adebce0a026f10 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BA=84=E7=8F=8A=E7=8F=8A?= <3106036048@qq.com>
Date: Wed, 25 Oct 2023 23:27:35 +0800
Subject: [PATCH 2/2] =?UTF-8?q?=E4=BD=9C=E4=B8=9A?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...06\347\202\271\351\233\206\345\220\210.md" | 0
...06\347\202\271\351\233\206\345\220\210.md" | 1119 +++++++++++++++++
2 files changed, 1119 insertions(+)
delete mode 100644 "48 \345\272\204\347\217\212\347\217\212/20231025 \347\237\245\350\257\206\347\202\271\351\233\206\345\220\210.md"
create mode 100644 "48 \345\272\204\347\217\212\347\217\212/20231025\347\237\245\350\257\206\347\202\271\351\233\206\345\220\210.md"
diff --git "a/48 \345\272\204\347\217\212\347\217\212/20231025 \347\237\245\350\257\206\347\202\271\351\233\206\345\220\210.md" "b/48 \345\272\204\347\217\212\347\217\212/20231025 \347\237\245\350\257\206\347\202\271\351\233\206\345\220\210.md"
deleted file mode 100644
index e69de29..0000000
diff --git "a/48 \345\272\204\347\217\212\347\217\212/20231025\347\237\245\350\257\206\347\202\271\351\233\206\345\220\210.md" "b/48 \345\272\204\347\217\212\347\217\212/20231025\347\237\245\350\257\206\347\202\271\351\233\206\345\220\210.md"
new file mode 100644
index 0000000..43389c4
--- /dev/null
+++ "b/48 \345\272\204\347\217\212\347\217\212/20231025\347\237\245\350\257\206\347\202\271\351\233\206\345\220\210.md"
@@ -0,0 +1,1119 @@
+
+
+# 1.ER图
+
+
+
+## 1、先看图熟悉E-R图中图形及代表的意思
+
+长方形:表示实体。
+
+什么是实体?实体是客观存在的事物。例如用户、商品、订单、供应商等。说直白点!!!你数据库的表名就可以做一个实体对象。一个系统是由很多个实体对象构成的,然后它们之间存在一定的关系和属性。
+
+椭圆形:表示属性。
+
+什么是属性?举例子:用户实体拥有属性【id、姓名、年龄、电话、身份证号】、商品实体拥有属性【id、商品名称、商品类型、商品价格、商品图片、商品描述、供应商名称】、订单实体拥有属性【id、订单编号、用户名称、商品名称、下单日期】、供应商实体拥有属性【id、名称、地址、联系电话】。
+
+菱形:表示关系。
+
+什么是关系?例如用户和商品应该购买关系(一个用户购买多件商品)、订单与商品应该是包含关系(一个订单中包含多件商品)。
+
+## 2、ER图中关联关系有三种
+
+一对一(1:1) :1对1关系是指对于实体集A与实体集B,A中的每一个实体至多与B中一个实体有关系;反之,在实体集B中的每个实体至多与实体集A中一个实体有关系。
+
+**例如:一个用户只能拥有一张身份证,而一张身份证只属于一个用户。所以这就是一对一的关系。**
+
+一对多(1:n) :1对多关系是指实体集A与实体集B中至少有n(n>0)个实体有关系;并且实体集B中每一个实体至多与实体集A中一个实体有关系。
+
+**例如:一对多和多对一是一样的。一个用户拥有多张银行卡,但是一张银行卡只属于一个用户。所以这就是一对多的关系。反过来说法就是多对一。**
+
+在例如:一个用户拥有多张银行卡,但是银行卡的拥有人只能是银行卡的主人
+
+多对多(m:n) :多对多关系是指实体集A中的每一个实体与实体集B中至少有m(m>0)个实体有关系,并且实体集B中的每一个实体与实体集A中的至少n(n>0)个实体有关系。
+
+**例如:用户与商品的关系,一个用户可拥有多件商品。同样一件商品可被多个用户所拥有。所以这就是多对多的关系。**
+
+# 2.三大范式
+
+数据库设计的三大范式(项目小偷懒用反范式)
+
+1. 第一范式:每个属性,也就是字段要求**不可再分割**,也就要求有原子性
+2. 第二范式:在满足第一范式的基础上,要求非主键字段要完全依赖主键(有联合主键时,非主键要同时完全依赖这两个主键,而不能部分依赖)
+3. 第三范式:在满足第二范式的基础上,要求非主键字段要直接依赖于主键(建多个表)
+
+# 3.RBAC是一种权限系统管理模型
+
+**RBAC**:什么是RBAC
+RBAC。英文名称Role-Based Access Control。顾名思义,就是基于**角色的权限控制系统**。理解的基本思路就是,在角色的前提下,**按照角色不同将权限分配到对应的角色,再将管理员设置成对应的角色,进而管理员获得权限。在管理员请求某个业务权限的时候,从数据库中查询该管理员所拥有的权限,并将请求的业务权限跟数据库比对。以此进行权限控制**
+
+实际开发怎么实现
+而在常规的后台开发中,权限其实对应的就是业务的控制权,再细化下去就是业务开发中,对应实现业务的代码。比如MVC模式中,就是对应的每一个Controller的Action,因为Action实现的就是暴露给外界的控制入口。那么实现过程就是,将这些实现业务的每一个代码接口【控制入口】列出来,每一个接口就是一个**permission,将这些接口保存到permission表;在admin表中设置一个默认的管理员。比如:super_admin;在role表个中设置一个拥有所有权限的角色。比如:super_role;在role_admin表中添加角色管理员关联的数据;在role_permission表中添加对应角色拥有的权限。那么在管理员登陆后要对后台的某个业务进行操作时,获取该操作的业务接口;在role_admin中查询获取该管理员对应的角色;在role_permission**表中查询对应角色拥有的权限;最后将请求的业务接口权限是否存在查询的数据中,比对一下就可以得知该管理员是否有操作权限
+
+
+
+复习复习我又忘记这个了啊啊啊啊啊啊啊啊啊啊啊啊啊啊!!!!!
+
+## 数据定义语言(DDL)
+
+由CREATE、ALTER、DROP和TRUNCATE四个语法组成
+
+## 数据操纵语言(DML)
+
+主要有insert、update、delete语法组成。
+
+## 数据查询语言(DQL)
+
+即最常用的select语句
+
+## 数据控制语言(DCL)
+
+比如常见的授权、取消授权、回滚、提交等等操作。
+
+# 4.关于spu和sku的图文理解
+
+
+
+
+
+
+
+**SPU和SKU**都是属性的集合
+
+SPU是公共属性的集合, SPU定义了产品,但不是商品,产品描述了商品的公共属性,不影响库存和价格。一个SPU可以拥有多个SKU,影响库存和价格。
+
+SKU是独有属性的集合。 SKU定义了商品,是在SPU的基础上描述了其独有的属性,SKU是库存量的最小存货单位,也是用户能够选择的最小单位是实际购买的商品。
+
+# 5.视图
+
+## 1.创建视图:
+
+```mysql
+create or replace view employee_vu(姓名,员工号,部门号)as
+
+select last_name,employee_id,department_id from employees;
+```
+
+## 2.修改视图:
+
+
+
+**alter view 视图名 as select 基本表的字段名 from 基本表 where 字段 in (需要修改的东西)**
+
+还有就是作业里面的:
+
+
+
+
+
+## 3.修改视图中的数据会使原数据发生变化的:
+
+update 视图名 set 视图字段=‘修改后的值’ where 视图字段=‘所查找的’
+
+就比如说:
+
+把视图表view2中叫做李楠的初级工程师改成高级工程师
+
+update view2 set pos='高级工程师' where name='李楠';
+
+这个跟表修改数据是一样的方法,同理insert into 。。。values。。。这个也是跟表一样的
+
+语法1:查看视图的结构
+
+```mysql
+DESC 视图名称;
+```
+
+语法2:查看视图的属性信息
+
+```mysql
+# 查看视图信息(显示数据表的存储引擎、版本、数据行数和数据大小等)
+SHOW TABLE STATUS LIKE '视图名称'
+```
+
+执行结果显示,注释Comment为VIEW,说明该表为视图,其他的信息为NULL,说明这是一个虚表。 语法4:查看视图的详细定义信息
+
+```mysql
+SHOW CREATE VIEW 视图名称;
+```
+
+
+
+# 6.很多很多单行函数(容易记混)
+
+1.length()返回字符串的长度
+
+2.substring(s,index,len) 返回从字符串s的index位置截取len个字符
+
+3.trim(s) 去掉字符串s开始与结尾的空格
+
+### 1) 基本函数
+
+| 函数 | 用法 |
+| ------------------- | ------------------------------------------------------------ |
+| ABS(x) | 返回x的绝对值 |
+| SIGN(X) | 单元格 |
+| PI() | 返回圆周率的值 |
+| CEIL(x),CEILING(x) | 返回大于或等于某个值的最小整数 |
+| FLOOR(x) | 返回小于或等于某个值的最大整数 |
+| LEAST(e1,e2,e3…) | 返回列表中的最小值 |
+| GREATEST(e1,e2,e3…) | 返回列表中的最大值 |
+| MOD(x,y) | 返回X除以Y后的余数 |
+| RAND() | 返回0~1的随机值 |
+| RAND(x) | 返回0~1的随机值,其中x的值用作种子值,相同的X值会产生相同的随机 数 |
+| ROUND(x) | 返回一个对x的值进行四舍五入后,最接近于X的整数 |
+| ROUND(x,y) | 返回一个对x的值进行四舍五入后最接近X的值,并保留到小数点后面Y位 |
+| TRUNCATE(x,y) | 返回数字x截断为y位小数的结果 |
+| SQRT(x) | 返回x的平方根。当X的值为负数时,返回NULL |
+
+## 2. 字符串函数
+
+| 函数 | 用法 |
+| ------------------------------------------------- | ------------------------------------------------------------ |
+| ASCII(S) | 返回字符串S中的第一个字符的ASCII码值 |
+| CHAR_LENGTH(s) | 返回字符串s的字符数。作用与CHARACTER_LENGTH(s)相同 |
+| LENGTH(s) | 返回字符串s的字节数,和字符集有关 utf8 一个汉字=3个字节 |
+| CONCAT(s1,s2,......,sn) | 连接s1,s2,......,sn为一个字符串 |
+| CONCAT_WS(x, s1,s2,......,sn) | 同CONCAT(s1,s2,...)函数,但是每个字符串之间要加上x |
+| INSERT(str, idx, len, replacestr) | 将字符串str从第idx位置开始,len个字符长的子串替换为字符串replacestr |
+| REPLACE(str, a, b) | 用字符串b替换字符串str中所有出现的字符串a |
+| UPPER(s) 或 UCASE(s) | 将字符串s的所有字母转成大写字母 |
+| LOWER(s) 或LCASE(s) | 将字符串s的所有字母转成小写字母 |
+| LEFT(str,n) | 返回字符串str最左边的n个字符 |
+| RIGHT(str,n) | 返回字符串str最右边的n个字符 |
+| LPAD(str, len, pad) | 用字符串pad对str最左边进行填充,直到str的长度为len个字符 |
+| RPAD(str ,len, pad) | 用字符串pad对str最右边进行填充,直到str的长度为len个字符 |
+| LTRIM(s) | 去掉字符串s左侧的空格 |
+| RTRIM(s) | 去掉字符串s右侧的空格 |
+| TRIM(s) | 去掉字符串s开始与结尾的空格 |
+| TRIM(s1 FROM s) | 去掉字符串s开始与结尾的s1 |
+| TRIM(LEADING s1 FROM s) | 去掉字符串s开始处的s1 |
+| TRIM(TRAILING s1 FROM s) | 去掉字符串s结尾处的s1 |
+| REPEAT(str, n) | 返回str重复n次的结果 |
+| SPACE(n) | 返回n个空格 |
+| STRCMP(s1,s2) | 比较字符串s1,s2的ASCII码值的大小 |
+| SUBSTR(s,index,len) | 返回从字符串s的index位置其len个字符,作用与SUBSTRING(s,n,len)、 MID(s,n,len)相同 |
+| LOCATE(substr,str) | 返回字符串substr在字符串str中首次出现的位置,作用于POSITION(substr IN str)、INSTR(str,substr)相同。未找到,返回0 |
+| ELT(m,s1,s2,…,sn) | 返回指定位置的字符串,如果m=1,则返回s1,如果m=2,则返回s2,如果m=n,则返回sn |
+| FIELD(s,s1,s2,…,sn) | 返回字符串s在字符串列表中第一次出现的位置 |
+| FIND_IN_SET(s1,s2) | 返回字符串s1在字符串s2中出现的位置。其中,字符串s2是一个以逗号分隔的字符串 |
+| REVERSE(s) | 返回s反转后的字符串 |
+| NULLIF(value1,value2) | 比较两个字符串,如果value1与value2相等,则返回NULL,否则返回 value1 |
+
+> 注意:
+>
+> 1.MySQL中,字符串的位置是从1开始的。
+>
+> 2.TRIM()函数可以去掉字符串两端的空格,但是不能去掉字符串中间的空格。如果我们要去掉字符串中间的空格,可以使用REPLACE()函数。
+>
+> 3.使用length()函数时需要注意,1个中文输出的字节长度是3。
+
+# 7.存储过程与函数
+
+## 1. 存储过程概述
+
+### 1) 理解
+
+**含义:**存储过程的英文是 Stored Procedure 。它的思想很简单,就是一组经过 预先编译的 SQL 语句 的封装。
+
+执行过程:存储过程**预先存储**在 MySQL 服务器上,**需要执行的时候**,客户端只需要向服务器端**发出调用存储过程的命令**,服务器端就可以把预先存储好的这一系列 **SQL 语句全部执行**。
+
+**好处:**
+
+* 1、简化操作,提高了sql语句的重用性,减少了开发程序员的压力。
+* 2、减少操作过程中的失误,提高效率。
+* 3、减少网络传输量(客户端不需要把所有的 SQL 语句通过网络发给服务器)。
+* 4、减少了 SQL 语句暴露在 网上的风险,也提高了数据查询的安全性。
+
+**和视图、函数的对比:**
+
+它和视图有着同样的优点,清晰、安全,还可以减少网络传输量。**不过它和视图不同,视图是虚拟表** ,通常不对底层数据表直接操作,而存储过程是程序化的 SQL,可以 直接操作底层数据表 ,相比于面向集合的操作方式,能够实现一些更复杂的数据处理。
+
+一旦存储过程被创建出来,使用它就像使用函数一样简单,我们直接通过调用存储过程名即可。相较于函数,存储过程是 没有返回值 的。
+
+### 2) 分类
+
+存储过程的参数类型可以是IN、OUT和INOUT。根据这点分类如下:
+
+1、没有参数(无参数无返回)
+
+2、仅仅带 IN 类型(有参数无返回)
+
+3、仅仅带 OUT 类型(无参数有返回)
+
+4、既带 IN 又带 OUT(有参数有返回)
+
+5、带 INOUT(有参数有返回)
+
+注意:IN、OUT、INOUT 都可以在一个存储过程中带多个。
+
+1. ```mysql
+ 1. BEGIN…END:BEGIN…END 中间包含了多个语句,每个语句都以(;)号为结束符。
+ 2. DECLARE:DECLARE 用来声明变量,使用的位置在于 BEGIN…END 语句中间,而且需要在其他语句使用之前进
+ 行变量的声明。
+ 3. SET:赋值语句,用于对变量进行赋值。
+ 4. SELECT… INTO:把从数据表中查询的结果存放到变量中,也就是为变量赋值。
+ ```
+
+ 示例:
+
+ ```mysql
+ DELIMITER //
+ CREATE PROCEDURE 存储过程名(IN|OUT|INOUT 参数名 参数类型,...)
+ [characteristics ...]
+ BEGIN
+ sql语句1;
+ sql语句2;
+ END $
+ ```
+
+ ### 2) 代码举例(复习看着个举例好嘛)那个// 是结束这个存储过程的结束符
+
+ 举例1:创建存储过程select_all_data(),查看 emps 表的所有数据
+
+ ```mysql
+ DELIMITER //
+ CREATE PROCEDURE select_all_data()
+ BEGIN
+ SELECT * FROM emps;
+ END //
+ DELIMITER ;
+ ```
+
+ ## 3.调用存储过程
+
+ **格式:**
+
+ 1、调用in模式的参数:
+
+ ```mysql
+ CALL sp1('值');
+ ```
+
+ 2、调用out模式的参数:
+
+ ```mysql
+ SET @name;
+ CALL sp1(@name);
+ SELECT @name;
+ ```
+
+ 3、调用inout模式的参数:
+
+ ```mysql
+ SET @name=值;
+ CALL sp1(@name);
+ SELECT @name;
+ ```
+
+ ### 2) 代码举例
+
+ **举例1:**
+
+ ```mysql
+ DELIMITER //
+ CREATE PROCEDURE CountProc(IN sid INT,OUT num INT)
+ BEGIN
+ SELECT COUNT(*) INTO num FROM fruits
+ WHERE s_id = sid;
+ END //
+ DELIMITER ;
+ ```
+
+ 调用存储过程:
+
+ ```mysql
+ CALL CountProc (101, @num);
+ ```
+
+ 查看返回结果:
+
+ ```mysql
+ SELECT @num;
+ ```
+
+ # 8. 流程控制
+
+ 解决复杂问题不可能通过一个 SQL 语句完成,我们需要执行多个 SQL 操作。流程控制语句的作用就是控 制存储过程中 SQL 语句的执行顺序,是我们完成复杂操作必不可少的一部分。只要是执行的程序,流程就分为三大类:
+
+ * 顺序结构 :程序从上往下依次执行
+ * 分支结构 :程序按条件进行选择执行,从两条或多条路径中选择一条执行
+ * 循环结构 :程序满足一定条件下,重复执行一组语句
+
+ 针对于MySQL 的流程控制语句主要有 3 类。注意:只能用于存储程序。
+
+ * 条件判断语句 :IF 语句和 CASE 语句
+ * 循环语句 :LOOP、WHILE 和 REPEAT 语句
+ * 跳转语句 :ITERATE 和 LEAVE 语句
+
+ ## 1) 分支结构之 IF
+
+ * IF 语句的语法结构是:
+
+ ```mysql
+ IF 表达式1 THEN 操作1 sql语句
+ [ELSEIF 表达式2 THEN 操作2]……
+ [ELSE 操作N]
+ END IF
+ ```
+
+ 根据表达式的结果为TRUE或FALSE执行相应的语句。这里“[]”中的内容是可选的。
+
+ * 特点:① 不同的表达式对应不同的操作 ② 使用在begin end中
+
+ * 举例1:
+
+ ```mysql
+ IF val IS NULL
+ THEN SELECT 'val is null';
+ ELSE SELECT 'val is not null';
+ END IF;
+ ```
+
+ * 举例2:声明存储过程“update_salary_by_eid1”,定义IN参数emp_id,输入员工编号。判断该员工薪资如果低于8000元并且入职时间超过5年,就涨薪500元;否则就不变。
+
+ ```mysql
+ DELIMITER //
+ CREATE PROCEDURE update_salary_by_eid1(IN emp_id INT)
+ BEGIN
+ DECLARE emp_salary DOUBLE;
+ DECLARE hire_year DOUBLE;
+ SELECT salary INTO emp_salary FROM employees WHERE employee_id = emp_id;
+ SELECT DATEDIFF(CURDATE(),hire_date)/365 INTO hire_year
+ FROM employees WHERE employee_id = emp_id;
+ IF emp_salary < 8000 AND hire_year > 5
+ THEN UPDATE employees SET salary = salary + 500 WHERE employee_id = emp_id;
+ END IF;
+ END //
+ DELIMITER ;
+ ```
+
+ ## 2) 分支结构之 CASE
+
+ * CASE 语句的语法结构1:
+
+ ```mysql
+ #情况一:类似于switch
+ CASE 表达式
+ WHEN 值1 THEN 结果1或语句1(如果是语句,需要加分号)
+ WHEN 值2 THEN 结果2或语句2(如果是语句,需要加分号)
+ ...
+ ELSE 结果n或语句n(如果是语句,需要加分号)
+ END [case](如果是放在begin end中需要加上case,如果放在select后面不需要)
+ ```
+
+ * CASE 语句的语法结构2:
+
+ ```mysql
+ #情况二:类似于多重if
+ CASE
+ WHEN 条件1 THEN 结果1或语句1(如果是语句,需要加分号)
+ WHEN 条件2 THEN 结果2或语句2(如果是语句,需要加分号)
+ ...
+ ELSE 结果n或语句n(如果是语句,需要加分号)
+ END [case](如果是放在begin end中需要加上case,如果放在select后面不需要)
+ ```
+
+ * 举例1:使用CASE流程控制语句的第1种格式,判断val值等于1、等于2,或者两者都不等。
+
+ ```mysql
+ CASE val
+ WHEN 1 THEN SELECT 'val is 1';
+ WHEN 2 THEN SELECT 'val is 2';
+ ELSE SELECT 'val is not 1 or 2';
+ END CASE;
+ ```
+
+ * 举例2:声明存储过程“update_salary_by_eid4”,定义IN参数emp_id,输入员工编号。判断该员工 薪资如果低于9000元,就更新薪资为9000元;薪资大于等于9000元且低于10000的,但是奖金比例 为NULL的,就更新奖金比例为0.01;其他的涨薪100元。
+
+ ```mysql
+ DELIMITER //
+ CREATE PROCEDURE update_salary_by_eid4(IN emp_id INT)
+ BEGIN
+ DECLARE emp_sal DOUBLE;
+ DECLARE bonus DECIMAL(3,2);
+ SELECT salary INTO emp_sal FROM employees WHERE employee_id = emp_id;
+ SELECT commission_pct INTO bonus FROM employees WHERE employee_id = emp_id;
+ CASE
+ WHEN emp_sal<9000
+ THEN UPDATE employees SET salary=9000 WHERE employee_id = emp_id;
+ WHEN emp_sal<10000 AND bonus IS NULL
+ THEN UPDATE employees SET commission_pct=0.01 WHERE employee_id = emp_id;
+ ELSE
+ UPDATE employees SET salary=salary+100 WHERE employee_id = emp_id;
+ END CASE;
+ END //
+ DELIMITER ;
+ ```
+
+ * 举例3:声明存储过程update_salary_by_eid5,定义IN参数emp_id,输入员工编号。判断该员工的 入职年限,如果是0年,薪资涨50;如果是1年,薪资涨100;如果是2年,薪资涨200;如果是3年, 薪资涨300;如果是4年,薪资涨400;其他的涨薪500。
+
+ ```mysql
+ DELIMITER //
+ CREATE PROCEDURE update_salary_by_eid5(IN emp_id INT)
+ BEGIN
+ DECLARE emp_sal DOUBLE;
+ DECLARE hire_year DOUBLE;
+ SELECT salary INTO emp_sal FROM employees WHERE employee_id = emp_id;
+ SELECT ROUND(DATEDIFF(CURDATE(),hire_date)/365) INTO hire_year FROM employees
+ WHERE employee_id = emp_id;
+ CASE hire_year
+ WHEN 0 THEN UPDATE employees SET salary=salary+50 WHERE employee_id = emp_id;
+ WHEN 1 THEN UPDATE employees SET salary=salary+100 WHERE employee_id = emp_id;
+ WHEN 2 THEN UPDATE employees SET salary=salary+200 WHERE employee_id = emp_id;
+ WHEN 3 THEN UPDATE employees SET salary=salary+300 WHERE employee_id = emp_id;
+ WHEN 4 THEN UPDATE employees SET salary=salary+400 WHERE employee_id = emp_id;
+ ELSE UPDATE employees SET salary=salary+500 WHERE employee_id = emp_id;
+ END CASE;
+ END //
+ DELIMITER ;
+ ```
+
+ ## 3) 循环结构之LOOP
+
+ LOOP循环语句用来重复执行某些语句。LOOP内的语句一直重复执行直到循环被退出(使用LEAVE子 句),跳出循环过程。
+
+ LOOP语句的基本格式如下:
+
+ ```mysql
+ [loop_label:] LOOP
+ 循环执行的语句
+ END LOOP [loop_label]
+ ```
+
+ 其中,loop_label表示LOOP语句的标注名称,该参数可以省略。
+
+ 举例1:使用LOOP语句进行循环操作,id值小于10时将重复执行循环过程。
+
+ ```mysql
+ DECLARE id INT DEFAULT 0;
+ add_loop:LOOP
+ SET id = id +1;
+ IF id >= 10 THEN LEAVE add_loop;
+ END IF;
+ END LOOP add_loop;
+ ```
+
+ 举例2:当市场环境变好时,公司为了奖励大家,决定给大家涨工资。声明存储过程 “update_salary_loop()”,声明OUT参数num,输出循环次数。存储过程中实现循环给大家涨薪,薪资涨为 原来的1.1倍。直到全公司的平均薪资达到12000结束。并统计循环次数。
+
+ ```mysql
+ DELIMITER //
+ CREATE PROCEDURE update_salary_loop(OUT num INT)
+ BEGIN
+ DECLARE avg_salary DOUBLE;
+ DECLARE loop_count INT DEFAULT 0;
+ SELECT AVG(salary) INTO avg_salary FROM employees;
+ label_loop:LOOP
+ IF avg_salary >= 12000 THEN LEAVE label_loop;
+ END IF;
+ UPDATE employees SET salary = salary * 1.1;
+ SET loop_count = loop_count + 1;
+ SELECT AVG(salary) INTO avg_salary FROM employees;
+ END LOOP label_loop;
+ SET num = loop_count;
+ END //
+ DELIMITER ;
+ ```
+
+ ## 4) 循环结构之WHILE
+
+ WHILE语句创建一个带条件判断的循环过程。WHILE在执行语句执行时,先对指定的表达式进行判断,如 果为真,就执行循环内的语句,否则退出循环。WHILE语句的基本格式如下:
+
+ ```mysql
+ [while_label:] WHILE 循环条件 DO
+ 循环体
+ END WHILE [while_label];
+ ```
+
+ while_label为WHILE语句的标注名称;如果循环条件结果为真,WHILE语句内的语句或语句群被执行,直 至循环条件为假,退出循环。
+
+ * 举例1:WHILE语句示例,i值小于10时,将重复执行循环过程,代码如下:
+
+ ```mysql
+ DELIMITER //
+ CREATE PROCEDURE test_while()
+ BEGIN
+ DECLARE i INT DEFAULT 0;
+ WHILE i < 10 DO
+ SET i = i + 1;
+ END WHILE;
+ SELECT i;
+ END //
+ DELIMITER ;
+ #调用
+ CALL test_while();
+ ```
+
+ * 举例2:市场环境不好时,公司为了渡过难关,决定暂时降低大家的薪资。声明存储过程 “update_salary_while()”,声明OUT参数num,输出循环次数。存储过程中实现循环给大家降薪,薪资降 为原来的90%。直到全公司的平均薪资达到5000结束。并统计循环次数。
+
+ ```mysql
+ DELIMITER //
+ CREATE PROCEDURE update_salary_while(OUT num INT)
+ BEGIN
+ DECLARE avg_sal DOUBLE ;
+ DECLARE while_count INT DEFAULT 0;
+ SELECT AVG(salary) INTO avg_sal FROM employees;
+ WHILE avg_sal > 5000 DO
+ UPDATE employees SET salary = salary * 0.9;
+ SET while_count = while_count + 1;
+ SELECT AVG(salary) INTO avg_sal FROM employees;
+ END WHILE;
+ SET num = while_count;
+ END //
+ DELIMITER ;
+ ```
+
+ ## 5) 循环结构之REPEAT
+
+ REPEAT语句创建一个带条件判断的循环过程。与WHILE循环不同的是,REPEAT 循环首先会执行一次循环,然后在 UNTIL 中进行表达式的判断,如果满足条件就退出,即 END REPEAT;如果条件不满足,则会就继续执行循环,直到满足退出条件为止。
+
+ REPEAT语句的基本格式如下:
+
+ ```mysql
+ [repeat_label:] REPEAT
+ 循环体的语句
+ UNTIL 结束循环的条件表达式
+ END REPEAT [repeat_label]
+ ```
+
+ repeat_label为REPEAT语句的标注名称,该参数可以省略;REPEAT语句内的语句或语句群被重复,直至 expr_condition为真。
+
+ 举例1:
+
+ ```mysql
+ DELIMITER //
+ CREATE PROCEDURE test_repeat()
+ BEGIN
+ DECLARE i INT DEFAULT 0;
+ REPEAT
+ SET i = i + 1;
+ UNTIL i >= 10
+ END REPEAT;
+ SELECT i;
+ END //
+ DELIMITER ;
+ ```
+
+ 举例2:当市场环境变好时,公司为了奖励大家,决定给大家涨工资。声明存储过程 “update_salary_repeat()”,声明OUT参数num,输出循环次数。存储过程中实现循环给大家涨薪,薪资涨 为原来的1.15倍。直到全公司的平均薪资达到13000结束。并统计循环次数。
+
+ ```mysql
+ DELIMITER //
+ CREATE PROCEDURE update_salary_repeat(OUT num INT)
+ BEGIN
+ DECLARE avg_sal DOUBLE ;
+ DECLARE repeat_count INT DEFAULT 0;
+ SELECT AVG(salary) INTO avg_sal FROM employees;
+ REPEAT
+ UPDATE employees SET salary = salary * 1.15;
+ SET repeat_count = repeat_count + 1;
+ SELECT AVG(salary) INTO avg_sal FROM employees;
+ UNTIL avg_sal >= 13000
+ END REPEAT;
+ SET num = repeat_count;
+ END //
+ DELIMITER ;
+ ```
+
+ **对比三种循环结构:**
+
+ 1. 这三种循环都可以省略名称,但如果循环中添加了循环控制语句(LEAVE或ITERATE)则必须添加名称。
+
+ 2. LOOP:一般用于实现简单的"死"循环 WHILE:先判断后执行
+
+ 3. REPEAT:先执行后判断,无条件至少执行一次
+
+ ## 6) 跳转语句之LEAVE语句
+
+ LEAVE语句:可以用在循环语句内,或者以 BEGIN 和 END 包裹起来的程序体内,表示跳出循环或者跳出 程序体的操作。如果你有面向过程的编程语言的使用经验,你可以把 LEAVE 理解为 break。
+
+ 基本格式如下:
+
+ ```mysql
+ LEAVE 标记名
+ ```
+
+ 其中,label参数表示循环的标志。LEAVE和BEGIN ... END或循环一起被使用。
+
+ 举例1:创建存储过程 “leave_begin()”,声明INT类型的IN参数num。给BEGIN...END加标记名,并在 BEGIN...END中使用IF语句判断num参数的值。
+
+ 如果num<=0,则使用LEAVE语句退出BEGIN...END; 如果num=1,则查询“employees”表的平均薪资; 如果num=2,则查询“employees”表的最低薪资; 如果num>2,则查询“employees”表的最高薪资。
+
+ IF语句结束后查询“employees”表的总人数。
+
+ ```mysql
+ DELIMITER //
+ CREATE PROCEDURE leave_begin(IN num INT)
+ begin_label: BEGIN
+ IF num<=0
+ THEN LEAVE begin_label;
+ ELSEIF num=1
+ THEN SELECT AVG(salary) FROM employees;
+ ELSEIF num=2
+ THEN SELECT MIN(salary) FROM employees;
+ ELSE
+ SELECT MAX(salary) FROM employees;
+ END IF;
+ SELECT COUNT(*) FROM employees;
+ END //
+ DELIMITER ;
+ ```
+
+ 举例2: 当市场环境不好时,公司为了渡过难关,决定暂时降低大家的薪资。声明存储过程“leave_while()”,声明 OUT参数num,输出循环次数,存储过程中使用WHILE循环给大家降低薪资为原来薪资的90%,直到全公司的平均薪资小于等于10000,并统计循环次数。
+
+ ```mysql
+ DELIMITER //
+ CREATE PROCEDURE leave_while(OUT num INT)
+ BEGIN
+ DECLARE avg_sal DOUBLE;#记录平均工资
+ DECLARE while_count INT DEFAULT 0; #记录循环次数
+ SELECT AVG(salary) INTO avg_sal FROM employees; #① 初始化条件
+ while_label:WHILE TRUE DO #② 循环条件
+ #③ 循环体
+ IF avg_sal <= 10000 THEN
+ LEAVE while_label;
+ END IF;
+ UPDATE employees SET salary = salary * 0.9;
+ SET while_count = while_count + 1;
+ #④ 迭代条件
+ SELECT AVG(salary) INTO avg_sal FROM employees;
+ END WHILE;
+ #赋值
+ SET num = while_count;
+ END //
+ DELIMITER ;
+ ```
+
+ ## 7) 跳转语句之ITERATE语句
+
+ ITERATE语句:只能用在循环语句(LOOP、REPEAT和WHILE语句)内,表示重新开始循环,将执行顺序转到语句段开头处。如果你有面向过程的编程语言的使用经验,你可以把 ITERATE 理解为 continue,意思为“再次循环”。
+
+ 语句基本格式如下:
+
+ ```mysql
+ ITERATE label
+ ```
+
+ label参数表示循环的标志。ITERATE语句必须跟在循环标志前面。
+
+ 举例: 定义局部变量num,初始值为0。循环结构中执行num + 1操作。
+
+ * 如果num < 10,则继续执行循环;
+ * 如果num > 15,则退出循环结构;
+
+ ```mysql
+ DELIMITER //
+ CREATE PROCEDURE test_iterate()
+ BEGIN
+ DECLARE num INT DEFAULT 0;
+ my_loop:LOOP
+ SET num = num + 1;
+ IF num < 10
+ THEN ITERATE my_loop;
+ ELSEIF num > 15
+ THEN LEAVE my_loop;
+ END IF;
+ SELECT 'MySQL';
+ END LOOP my_loop;
+ END //
+ DELIMITER ;
+ ```
+
+ # 9. 游标
+
+ ## 1) 什么是游标(或光标)
+
+ 虽然我们也可以通过筛选条件 WHERE 和 HAVING,或者是限定返回记录的关键字 LIMIT 返回一条记录, 但是,却无法在结果集中像指针一样,向前定位一条记录、向后定位一条记录,或者是随意定位到某一 条记录 ,并对记录的数据进行处理。
+
+ 这个时候,就可以用到游标。游标,提供了一种灵活的操作方式,让我们能够对结果集中的每一条记录进行定位,并对指向的记录中的数据进行操作的数据结构。游标让 SQL 这种面向集合的语言有了面向过程开发的能力。
+
+ 在 SQL 中,游标是一种临时的数据库对象,可以指向存储在数据库表中的数据行指针。这里游标 充当了 指针的作用 ,我们可以通过操作游标来对数据行进行操作。
+
+ MySQL中游标可以在存储过程和函数中使用。
+
+ ## 2) 使用游标步骤
+
+ 游标必须在声明处理程序之前被声明,并且变量和条件还必须在声明游标或处理程序之前被声明。
+
+ 如果我们想要使用游标,一般需要经历四个步骤。不同的 DBMS 中,使用游标的语法可能略有不同。
+
+ **第一步,声明游标**
+
+ 在MySQL中,使用DECLARE关键字来声明游标,其语法的基本形式如下:
+
+ ```mysql
+ DECLARE cursor_name CURSOR FOR select_statement;
+ ```
+
+ 这个语法适用于 MySQL,SQL Server,DB2 和 MariaDB。如果是用 Oracle 或者 PostgreSQL,需要写成:
+
+ ```mysql
+ DECLARE cursor_name CURSOR IS select_statement;
+ ```
+
+ 要使用 SELECT 语句来获取数据结果集,而此时还没有开始遍历数据,这里 select_statement 代表的是 SELECT 语句,返回一个用于创建游标的结果集。
+
+ 比如:
+
+ ```mysql
+ DECLARE cur_emp CURSOR FOR
+ SELECT employee_id,salary FROM employees;
+ ```
+
+ **第二步,打开游标**
+
+ 打开游标的语法如下:
+
+ ```mysql
+ OPEN cursor_name
+ ```
+
+ 当我们定义好游标之后,如果想要使用游标,必须先打开游标。打开游标的时候 SELECT 语句的查询结果集就会送到游标工作区,为后面游标的 逐条读取 结果集中的记录做准备。
+
+ ```mysql
+ OPEN cur_emp;
+ ```
+
+ **第三步,使用游标(从游标中取得数据)**
+
+ 语法如下:
+
+ ```mysql
+ FETCH cursor_name INTO var_name [, var_name] ...
+ ```
+
+ 这句的作用是使用 cursor_name 这个游标来读取当前行,并且将数据保存到 var_name 这个变量中,游标指针指到下一行。如果游标读取的数据行有多个列名,则在 INTO 关键字后面赋值给多个变量名即可。
+
+ 注意:var_name必须在声明游标之前就定义好。
+
+ ```mysql
+ FETCH cur_emp INTO emp_id, emp_sal ;
+ ```
+
+ 注意:**游标的查询结果集中的字段数,必须跟 INTO 后面的变量数一致**,否则,在存储过程执行的时 候,MySQL 会提示错误。
+
+ **第四步,关闭游标**
+
+ ```mysql
+ CLOSE cursor_name
+ ```
+
+ 有 OPEN 就会有 CLOSE,也就是打开和关闭游标。当我们使用完游标后需要关闭掉该游标。因为游标会 占用系统资源 ,如果不及时关闭,游标会一直保持到存储过程结束,影响系统运行的效率。而关闭游标 的操作,会释放游标占用的系统资源。
+
+ 关闭游标之后,我们就不能再检索查询结果中的数据行,如果需要检索只能再次打开游标。
+
+ ```mysql
+ CLOSE cur_emp;
+ ```
+
+ ## 3) 举例
+
+ 创建存储过程“get_count_by_limit_total_salary()”,声明IN参数 limit_total_salary,DOUBLE类型;声明 OUT参数total_count,INT类型。函数的功能可以实现累加薪资最高的几个员工的薪资值,直到薪资总和达到limit_total_salary参数的值,返回累加的人数给total_count。
+
+ ```mysql
+ DELIMITER //
+ CREATE PROCEDURE get_count_by_limit_total_salary(IN limit_total_salary DOUBLE, OUT total_count INT)
+ BEGIN
+ DECLARE sum_salary DOUBLE DEFAULT 0; # 记录累加的总工资
+ DECLARE cursor_salary DOUBLE DEFAULT 0; # 记录某一个工资值
+ DECLARE emp_count INT DEFAULT 0; # 记录循环个数
+ # 定义游标
+ DECLARE emp_cursor CURSOR FOR SELECT salary FROM employees ORDER BY salary DESC;
+ # 打开游标
+ OPEN emp_cursor;
+
+ REPEAT
+ # 使用游标(从游标中获取数据)
+ FETCH emp_cursor INTO cursor_salary;
+ SET sum_salary = sum_salary + cursor_salary;
+ SET emp_count = emp_count + 1;
+ UNTIL sum_salary >= limit_total_salary
+ END REPEAT;
+ set total_count = emp_count;
+ # 关闭游标
+ CLOSE emp_cursor;
+ END //
+ DELIMITER;
+ ```
+
+ ## 4) 小结
+
+ 游标是 MySQL 的一个重要的功能,为 逐条读取 结果集中的数据,提供了完美的解决方案。跟在应用层面实现相同的功能相比,游标可以在存储程序中使用,效率高,程序也更加简洁。
+
+ 但同时也会带来一些性能问题,比如在使用游标的过程中,会对数据行进行 加锁 ,这样在业务并发量大 的时候,不仅会影响业务之间的效率,还会 消耗系统资源 ,造成内存不足,这是因为游标是在内存中进行的处理。
+
+ 建议:养成用完之后就关闭的习惯,这样才能提高系统的整体效率。
+
+
+
+# 10.触发器和窗口函数
+
+#### 序号函数
+
+row_number()、rank()、dense_rank()
+
+#### 窗口函数
+
+窗口函数名称(参数) over(partition by ... order by... 窗口大小)
+
+#### 前后函数
+
+返回当前行的前某一行的值,或者后某一行的值
+
+lag(列名,前第n行)
+
+lead(列名,后第n行)
+
+#### 头尾函数
+
+返回第一个或最后一个列的值
+
+first_value(列名)
+
+last_value(列名)
+
+#### 分布函数
+
+##### cume_dist()
+
+分组内 <= 或 >= 当前值的行数占比(包含当前值本身)
+
+```mysql
+# 查询各部门员工小于等于当前薪资的比例
+
+select ename,deptno,sal,
+cume_dist() over(partition by deptno order by sal) '占比'
+from emp;
+
+-- order by 控制计算的列
+-- asc 小于等于
+-- desc 大于等于
+```
+
+-------------------------------------------
+
+```mysql
+# percent_rank() 百分比排序(小数形式)
+```
+
+-----------------------------------------------------------------------------------
+
+-- rows 启用窗口大小
+-- between ... and ... 范围区间
+-- unbounded preceding 起始行
+-- unbounded following 最后行
+-- current row 当前行 #当前行 # 最后一位员工
+select salary,sum(salary) over (order by salary rows between current row and unbounded following)from employee;
+
+---------------------------------
+
+```mysql
+# EXTRACT() 函数用于返回日期/时间的单独部分,比如年、月、日、小时、分钟等等。
+select dname,ename,birth,EXTRACT(YEAR from birth)-lag(EXTRACT(YEAR from birth)) over (partition by dname order by birth) from employee;
+```
+
+#### 创建触发器: trigger 和 after insert on emp for each row(例子)
+
+```mysql
+CREATE TRIGGER 触发器名称
+{BEFORE|AFTER} {INSERT|UPDATE|DELETE} ON 表名 FOR EACH ROW
+触发器执行的语句块
+```
+
+创建名称为before_insert的触发器,向test_trigger数据表插入数据之前,向 test_trigger_log数据表中插入before_insert的日志信息。
+
+```mysql
+DELIMITER //
+CREATE TRIGGER before_insert
+BEFORE INSERT ON test_trigger FOR EACH ROW
+BEGIN
+ INSERT INTO test_trigger_log (t_log)
+ VALUES('before_insert');
+END //
+DELIMITER ;
+```
+
+3. 向test_trigger数据表中插入数据
+
+```mysql
+INSERT INTO test_trigger (t_note) VALUES ('测试 BEFORE INSERT 触发器');
+```
+
+4. 查看test_trigger_log数据表中的数据
+
+# 1.2卡手但是能搞懂的易忘题
+
+-- case when
+
+```mysql
+# case
+# when 条件表达式1 then 值1
+# when 条件表达式2 then 值2
+# ...
+# else 值n
+# end
+### 前后函数
+# 返回当前行的前某一行的值,或者后某一行的值
+# lag(列名,前第n行)
+```
+
+
+
+```mysql
+按员工工资进行排序,比较相邻两个员工的工资,输出比较高的工资
+
+# 这个查询语句使用了窗口函数LAG()来比较当前行的工资和上一行的工资。它将根据工资的升序排序,然后对每一行计算出上一行的工资。
+
+# CASE语句用于判断上一行的工资是否大于当前行的工资。如果是,它会返回上一行的工资作为"higher_salary"列的值;否则,它会返回当前行的工资
+
+select
+case when lag(salary) over (order by salary)>salary
+then lag(salary) over (order by salary)
+else salary end 逐行比较工资较高的工资
+from employee;
+```
+
+```mysql
+按员工工资进行排序,查询当前员工至最后一位员工的工资总和
+-- rows 启用窗口大小
+-- between ... and ... 范围区间
+-- unbounded preceding 起始行
+-- unbounded following 最后行
+-- current row 当前行 #当前行 # 最后一位员工
+select salary,sum(salary) over (order by salary rows between current row and unbounded following)from employee;
+```
+
+```mysql
+每个部门按年龄进行排序,求当前员工与前一位员工的年龄差
+# ### 前后函数
+# 返回当前行的前某一行的值,或者后某一行的值
+# lag(列名,前第n行)
+# EXTRACT() 函数用于返回日期/时间的单独部分,比如年、月、日、小时、分钟等等。
+select dname,ename,birth,EXTRACT(YEAR from birth)-lag(EXTRACT(YEAR from birth)) over (partition by dname order by birth) from employee;
+
+```
+
+# 11.窗口函数(亲,这边建议直接去看窗口函数的那个文档和练习,结合起来更易进食)
+
+比较忘得明明白白的:
+
+开窗聚合函数
+
+sum()|avg()|min()|max()|count()| over (partition by ... order by...)
+
+rows 启用窗口大小
+
+between ... and ... 范围区间
+
+unbounded preceding 起始行
+
+current row 当前行
+
+# 12.索引
+
+索引:
+
+## 创建普通索引
+
+create index 索引名 on 表名(列名)
+
+**alter** **table** 表名 **add** **index** 索引名(列名)
+
+创建表时直接创索引
+
+create table tab(
+ id int primary key,
+ name varchar(20),
+ index 索引名 (列名) primary key(列名)
+);
+
+
+
+## 创建唯一索引
+
+比普通索引多了unique关键字
+
+create unique index 索引名 on 表名(列名);
+alter table 表名 add unique 索引名 (列名)
+create table tab(
+ id int primary key,
+ name varchar(20),
+ unique [INDEX] 索引名 (列名)
+);
+
+# 13.事务:
+
+特点:
+
+1.原子性:事务已经是最小单位了,不可能会比事务更小
+
+事务是将多条sql语句捆绑一起执行的要么一起成功要么一起失败
+
+2.一致性:数据从a到b一定要一致,同时状态也要一致
+
+3.隔离性:两个事务之间,事务a与事务b之间有一个隔离墙
+
+4.持久性:事务一旦提交,对数据库的更改时永久性的
+
+事务的操作:
+
+事务的操作:
+
+事务一开始为隐式事务,是自动提交的,所以我们要手动打开它,代码如下:
+
+```mysql
+set autocommit=0;-- 手动提交事务
+set autocommit=off;
+```
+
+提交事务的代码如下:
+
+```mysql
+start transaction; -- 开启事务
+create table test1(id int);-- 建表语句
+set autocommit=0;-- 手动提交事务
+insert into test1 values(1);-- 插入一条数据的sql语句
+commit;-- 提交事务!!(提交之后将关闭事务)
+```
+
+将事务提交后悔时可以使用回滚事务,代码如下:
+
+```mysql
+start transaction; -- 开启事务
+create table test1(id int);-- 建表语句
+set autocommit=0;-- 手动提交事务
+insert into test1 values(1);-- 插入一条数据的sql语句
+rollback;-- 回滚数据将事务内这条插入语句回滚回刚开始的数据(回滚后也会关闭事务)
+```
+
+savepoint关键字的作用是当我们只想回滚部分数据是可以用它来实现,它就相当于一个存档,通过回滚指令来读档,代码如下:
+
+```mysql
+start transaction; -- 开启事务
+create table test1(id int);-- 建表语句
+set autocommit=0;-- 手动提交事务
+insert into test1 values(1);-- 插入一条数据的sql语句
+savepoint a1;-- 在此处建立一个存档a1
+insert into test1 values(2);-- 插入第二条数据的sql语句
+savepoint a2; -- 在此处建立一个存档a2
+-- 当我们只想回滚到a2的操作时就可以用到这个存档了
+rollback to a2;
+```
+
+对于事务中的一些问题
+
+### 脏读:我写了错误答案,同桌b抄了我的错误答案上交了,而我在上交前把错误答案修改成正确答案
+
+### 读已提交:同桌b可以看到所有已提交的答案进行操作
+
+(这种情况发生 在一个事务内多次读同一数据。A事务查询某条数据,**该事务未结束时**,**B事务也访问同一数据并进行了修改**。那么在A事务中的两 次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。)
+
+### 可重复读
+
+一个事务操作中对于一个读取操作不管多少次,读取到的结果都是一样的。
+
+### 幻读
+
+脏读、不可重复读、可重复读、幻读,其中最难理解的是幻读。
+
+全部结合就是它
+
--
Gitee