笨蛋学习MySQL1.0

笨蛋学习MySQL1.0

SQL基础

SQL通用语法

1、SQL语句可以单行或多行书写,以分号结尾

2、SQL语句可以使用空格/缩进来增强语句的可读性

3、MySQL数据库的SQL语句不区分大小写,关键字建议使用大写

4、注释:单行注释:-- 注释内容 或# 注释内容(MySQL特有)

多行注释:/注释内容/

SQL分类

SQL数据类型

数值类型

tinyint unsigned 表示无符号范围

double(4,1) 4:表示数值的整体长度,1:表示小数点后的长度

img

字符串类型

char:性能好

varchar:性能较差

img

日期时间类型

img


DDL 数据定义语言,用来定义数据库对象(数据库、表、字段、索引)

DDL-数据库操作

#查询所有数据库

show databases;

#查询当前数据库

select database();

#创建

create database [IF NOT EXISTS] 数据库名 [DEFAULT CHARSET 字符集] [COLLATE 排序规则];

  • IF NOT EXISTS:如果不存在就执行,如果存在不执行任何操作
  • IF EXISTS:如果存在就执行,如果不存在就不执行任何操作

#删除

drop database[IF EXISTS] 数据库名;

#使用

use 数据库名;

DDL-表操作

DDL-表操作-创建
create table 表名(
字段1 字段1类型[COMMENT 字段1注释],
字段2 字段1类型[COMMENT 字段1注释],
..........
字段n 字段1类型[COMMENT 字段1注释] #没有逗号
)[COMMENT 表注释];
create table emp(
	id int,
	empid varchar(10) comment '工号',
	empname varchar(10) comment '姓名',
  gender char(1) comment '性别',
	age int unsigned comment '年龄',
	shenfenid char(18) comment '身份证号',
	worktime date comment '入职时间'
) comment '员工表';

DDL-表操作-修改

#添加字段

alter table 表名 add 字段名 类型(长度) [comment 注释] [约束];

例:alter table emp add nickname varchar(20) comment ‘昵称’;

#修改字段名和字段类型

alter table 表名 change 旧字段名 新字段名 类型(长度) [comment 注释] [约束];

例:alter table emp change nickname username varchar(30) comment ‘用户名’;

#删除字段

alter table 表名 drop 字段名;

例:alter table emp drop username;

#修改表名

alter table 表名 rename to 新表名;

例:alter table emp rename to emper;


DDL-表操作-删除

#删除表

drop table[IF EXISTS] 表名;

  • IF EXISTS:如果存在就执行,如果不存在就不执行任何操作

#删除指定表,并重新创建该表

truncate table 表名; #删除表时,表中的全部数据也会被删除


DDL-表操作-查找

#查询当前数据库所有表

show tables;

#查询表结构

desc 表名;

#查询指定表的建表语句

show create table 表名;


DML 数据操作语言,用来对数据库表中的数据进行增删改
添加数据(INSERT)

#给指定字段添加数据

insert into 表名(字段名1,字段名2,.....) values(值1,值2,.....);

#给全部字段添加数据

insert into 表名 values(值1,值2......);

#批量添加数据

insert into 表名(字段名1,字段名2,......) values (值1,值2....),(值1,值2....),(值1,值2....);

insert into 表名 values(值1,值2....),(值1,值2....),(值1,值2....);

注意:

  • 插入数据时,指定的字段顺序需要与值的顺序时一一对应的

  • 字符串和日期数据应该包含在引号中

  • 插入的数据大小,应该在字段的规定范围内

修改数据(UPDATE)

update 表名 set 字段名1=值1,字段名2=值2,…[where 条件];

#修改id为1的数据,将name修改为itheima
update emper set name='itheima' where id=1;
#修改id为1的数据,将name修改为小昭,gender修改为女
update emper set name='小昭',gender='女' where id=1;
#修改所有员工的入职时间为2008-01-01
update emper set worktime= '2008-01-01';

注意:

修改语句的条件可以有,也可以没有,如果没有条件,则会修改整张表的所有数据。

删除数据(DELETE)

delete from 表名 [where 条件]

删除gender为女的员工
delete from emper where gender='女';
删除所有员工
delete from emper;

注意:

delete语句的条件可以有,也可以没有,如果没有条件,则会删除整张表的所有数据

delete语句不能删除某一字段的值(可以使用update)

DQL 数据查询语言,用来查询数据库中表的记录
DQL-语法
select
  	字段列表
from
    表名列表
where
  	条件列表
group by
  	分组字段列表
having
  	分组后条件列表
order by
  	排序字段列表
limit
  	分页参数
from
    表名列表
where
  	条件列表
group by
  	分组字段列表
having
  	分组后条件列表
select
  	字段列表
order by
  	排序字段列表
limit
  	分页参数
查询年龄大于15的员工姓名、年龄,并根据年龄进行升序排序
select name,age from emper where age>15 order by age asc;
select e.name,e.age from emper e where e.age>15 order by age asc;
#报错select e.name ename,e.age eage from emper e where eage>15 order by age asc;
select e.name ename,e.age eage from emper e where e.age>15 order by eage asc;
基本查询

1、查询多个字段

select 字段1,字段2,字段3… from 表名

select * from 表名;

2、设置别名

select 字段1[as 别名1],字段2[as 别名2] … from 表名;

例:select workaddress as ‘工作地址’ from emper; #工作地址就作为workaddress的表别名(as 可省略)

3、去除重复记录

select distinct 字段列表 from 表名;

例:select distinct workaddress ‘工作地址’ from emper;#去除工作地址相同的地址

条件查询(where)

1、语法

select 字段列表 from 表名 where 条件列表;

2、条件

img

查询年龄等于88的员工
select * from emper where age=88;
查询没有身份证号的员工
select * from emper where shenfenid is null;
查询有身份证号的员工
select * from emper where shenfenid is not null;
查询年龄不等于88的员工
select * from emper where age != 88;
select * from emper where age <> 88;
查询年龄在15(包含)到20(包含)之间的员工信息
select * from emper where age>=15 && age<=20;
select * from emper where age>=15 and age<=20;
#between后面为最小值,and后面为最大值
select * from emper where age betweeen 15 and 20;
查询性别为女且年龄小于25的员工信息
select * from emper where gender = '女' and age<25;
查询年龄等于18或20或40的员工信息
select * from emper where age=18 or age=20 or age=40;
select * from emper where age in(18,20,40);
查询姓名为两个字的员工信息
select * from emper where empname like '__';
查询身份证号最后一位是X的员工信息
select * from emper where shenfenid like '%x';
select * from emper where shenfenid like '________________x';
聚合函数(count,max,min,avg,sum)

1、介绍

将一列数据作为一个整体,进行纵向计算。

2、常见聚合函数

img

3、语法

select 聚合函数(字段列表) from 表名;

统计该企业员工数量
select count(*) from emper;
select count(id) from emper;
统计该企业员工的平均年龄
select avg(age) from emper;

注意:

null值不参与所有的聚合函数运算

分组查询(GROUP BY)

1、语法

select 字段列表 表名 [where 条件] group by 分组字段名 [HAVING 分组后过滤条件];

2、where和having区别

**执行时机不同:**where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组之后对结果进行过滤

**判断条件不同:**where不能对聚合函数进行判断,而having可以

根据性别分组,统计男性员工和女性员工的数量
select gender,count(*) from emper group by gender;
根据性别分组,统计男性员工和女性员工的平均年龄
select gender,avg(age) 平均年龄 from emper group by gender;
查询年龄小于45的员工,并根据工作地址分组,
获取员工数量大于等于3的工作地址
select empname,address,count(*) 人数 from emper where age<=45 group by address having count(id)>=3;
select empname,address,count(*) 人数 from emper where age<=45 group by address having 人数>=3;

注意:

执行顺序:where>聚合函数>having

分组之后,查询的字段一般为聚合函数和分组字段,查询其他字段无任何意义

排序查询(ORDER BY)

1、语法

select 字段列表 from 表名 order by 字段1 排序方式1,字段2 排序方式2;

2、排序方式

ASC:升序(默认值)

DESC:降序

根据年龄对公司的员工进行升序排序
select * from emper order by age asc;
根据入职时间,对员工进行降序排序
select * from emper order by worktime desc;
select * from emper order by worktime;
根据年龄对公司的员工进行排序,年龄相同,再按照入职时间进行降序排序
select * from emper order by age asc,worktime desc;
select * from emper order by age asc,worktime;
select * from emper order by age asc,worktime asc;

注意:

如果是多字段排序,当第一个字段值相同时,才会根据第二个字段进行排序

分页查询(LIMIT)

1、语法

select 字段列表 from 表名 limit 起始索引,查询记录数;

查询第1页员工数据,每页展示10条记录
select * from emper limit 0,10;
select * from emper limit 10;
查询第2页员工数据,每页展示10条记录
select * from emper limit 10,10;

注意:

起始索引从0开始,起始索引=(查询页码-1) * 每页显示记录数

分页查询是数据库的语言,不同的数据库有不同的发现,MySQL中是limit

如果查询的是第一页数据,起始索引可以省略,直接简写为limit 10

查询年龄为20,21,22,23岁的女性员工信息
select * from emper where gender='女' and age in(20,21,22,23);
查询性别为男,并且年龄在20-40岁(含)以内的姓名为三个字的员工
select * from emper where gender='男' and age between 20 and 40 and empname='___';
统计员工表中,年龄小于60岁的,男性员工和女性员工的人数
select gender,count(*) from emper where age<60 group by gender;
查询所有年龄小于等于35岁员工的姓名和年龄,并对查询结果按年龄升序排序,如果年龄相同按入职时间降序排序
select empname,age from emper where age<=35 order by age asc,worktime desc;
查询性别为男,且年龄在20-40岁(含)以内的前5个员工信息,对查询的结果按年龄升序排序,年龄相同按入职时间升序排序
select * from emper where gender='男' and age between 20 and 40 order by age asc,worktime asc limit 0,5;
select * from emper where age between 20 and 40 group by gender='男' order by age asc,worktime asc limit 5;
DCL 数据控制语言,用来创建数据库用户、控制数据库的访问权限
DCL-管理用户

1、查询用户

use mysql;

select * from user;

2、创建用户

create user ‘用户名’@‘主机名’ identified by ‘密码’;

3、修改用户密码

alter user ‘用户名’@‘主机名’ identified with mysql_native_password by ‘新密码’;

4、删除用户

drop user ‘用户名’@‘主机名’;

创建用户itcast,只能在当前主机localhost访问,密码123456
create user 'itcast'@'localhost' identified by '123456';

cmd命令
mysql -u itcast -p
123456

创建用户heima,可以在任意主机访问该数据库,密码123456
create user 'heima'@'%' identified by '123456';
修改用户heima的访问密码为1234
alter user 'heima'@'%' identified with mysql_native_password by '1234';
删除itcast@localhost用户
drop user 'itcast'@'localhost';

注意:

主机名可以使用%通配

此类SQL开发人员操作的比较少,主要是DBA(数据库管理人员)使用

DCL-权限控制

img

1、查询权限

show grants for ‘用户名’@‘主机名’;

2、授予权限

grant 权限列表 on 数据库名.表名 to ‘用户名’@‘主机名’;

3、撤销权限

revoke 权限列表 on 数据库名.表名 from ‘用户名’@‘主机名’;

查询
show grants for 'heima'@'%';
授予
grant all on itcast.* to 'heima'@'%';
撤销
revoke all on itcast.* from 'heima'@'%';

函数

函数是指一段可以直接被另一段程序调用的程序或代码

字符串函数

img

select concat('hello','mysql');

select lower('Hello');

select upper('Hello');

select lpad('01',5,'-');

select rpad('01',5,'-');

select trim(' hello world ');

select substring('hello mysql',1,5);#索引从1开始

将工号1改为00001
update emper set empid=lpad(empid,5,'0');

数值函数

img

select ceil(1.5);

select floor(1.9);

select mod(3,4);

select rand();

select round(2.345,2);

随机生成一个六位数
select lpad(round(rand()*1000000,0),6,'0');
select rpad(round(rand()*1000000,0),6,'0');

日期函数

img

select curdate();

select curtime();

select now();

select year(now());

select month(curdate());

select day(now());

select date_add(now(),interval 70 day);

select datediff('2019-09-01',now());

查询所有员工的入职天数,并根据入职天数倒序排序
select empname,(now()-worktime) 入职天数 from emper where order by 入职天数 desc;
select empname,datediff(curdate(),worktime) 入职天数 from emper where order by 入职天数 desc;

流程函数

img

select if(true,'ok','error');

select ifnull('ok','default');
select ifnull('','default');
select ifnull(null,'default');

#case when then else end
查询emper表的员工姓名和工作地址,
将地址为北京、上海->一线城市
其他城市->二线城市
select 
	empname,
	(case workaddress when '北京' then '一线城市'
  else '二线城市' end) as '工作地址'
from emper;


统计班级学员成绩
>=85,展示优秀
>=60,展示及格
否则,展示不及格
select
	id,
  name,
	(case math when >=85 then '优秀' when math >=60 then '及格' else '不及格' end) '数学',
	(case chinese when >=85 then '优秀' when chinese >=60 then '及格' else '不及格' end) '语文',
	(case english when >=85 then '优秀' when english >=60 then '及格' else '不及格' end) '英语',
from score;

约束

1、概念:约束是作用于表中字段上的规则,用于限制存储在表中的数据

2、目的:保证数据库中数据的正确性、有效性和完整性

3、分类:

img

注意:

约束是作用于表中字段上的,可以在创建表/修改表的时候添加约束

约束的演示

img

create table user(
	id int primary key auto_increment comment '主键',
  name varchar(10) not null unique comment '姓名',
	age int check(age>0 && age<=120) comment '年龄',
	status char(1) default '1' comment '状态',
	gender char(1) comment '性别'
)comment '用户表';

外键约束

概念:

外键用来让两张表的数据之间建立连接,从而保证数据的一致性和完整性

语法:

添加外键
create table 表名(
字段名 数据类型
....
[constraint] [外键名称] foreign key(外键字段名) references 主表(主表列名)
);
修改外键
alter table 表名 add constraint 外键名称 foreign key(外键字段名) references 主表(主表列名)
删除外键
alter table 表名 drop foreign key 外键名称

注意:

在数据库层面,并未建立外键关系,所以是无法保证数据的一致性和完整性的

删除/更新行为

img

alter table 表名 add constraint 外键名称 foreign key(外键字段) references 主表名(主表字段名) on update on delete cascade;

alter table 表名 add constraint 外键名称 foreign key(外键字段) references 主表名(主表字段名) on set null on delete set null;

多表查询

多表关系

各个表接口之间存在着各种联系,基本上分为三种:

一对多(多对一)

案例:部门与员工的关系

关系:一个部门对应多个员工,一个员工对一个一个部门

实现:在多的一方建立外键,指向一的一方的主键

多对多

案例:学生与课程的关系

关系:一个学生可以选修多门课程,一门课程也可以供多个学生选择

实现:建立第三张中间表,中间表至少包含两个外键,分别关联两方主键

一对一

案例:用户与用户详情的关系

关系:一对一关系,多用于单表拆分,将一张表的基础字段放在一张表中,其他详情字段在另一张表中,以提升操作效率

实现:在任意一方加入外键,关联另外一方的主键,并且设置外键为唯一的(UNIQUE)

多表查询概述

概述:从多表中进行查询数据

(在多表查询时,需要消除无效的笛卡尔积)

select * from S,C where S.name=C.name;

连接查询

内连接:相当于查询A、B交集部分数据

外连接:

左外连接:查询左表所有数据,以及两张表交集部分数据

右外连接:查询右表所有数据,以及两张表交集部分数据

自连接:当前表与自身的连接查询,自连接必须使用表别名

内连接

内连接查询语法:查询的是两张表交集的部分

隐式内连接

select 字段列表 from 表1,表2 where 条件…;

显示内连接

select 字段列表 from 表1 [inner] join 表2 on 连接条件…;

查询每一个员工的姓名,及关联的部门的名称(隐式内连接)
表结构:emp,dept
连接条件:emp.dept_id =dept.id

select emp.name,dept.name from emp,dept where emp.dept_id=dept.id;
#若给表取了别名,则不能再次使用表名需要使用别名
select e.name,d.name from emp e,dept d where e.dept_id=d.id;

查询每一个员工的姓名,及关联的部门的名称(显示内连接)
select e.name,d.name from emp e inner join dept d on e.dept_id=d.id;
select e.name,d.name from emp e join dept d on e.dept_id=d.id;

外连接

外连接查询语法:

左外连接

select 字段列表 from 表1 left [outer] join 表2 on 条件…;

相当于查询表1(左表)的所有数据包含表1和表2交集部分的数据

右外连接

select 字段列表 from 表1 right [outer] join 表2 on 条件…;

相当于查询表2(右表)的所有数据包含表1和表2交集部分的数据

查询emp表的所有数据,和对应的部门信息(左外连接)
表结构:emp,dept
连接条件:emp.dept_id =dept.id
select e.*,d.name from emp e left join dept d on e.dept_id =d.id;
select e.*,d.name from emp e left outer join dept d on e.dept_id =d.id;

查询emp表的所有数据,和对应的部门信息(右外连接)
select d.*,e.* from emp e rignt join dept d on e.dept_id =d.id;
select d.*,e.* from emp e rignt outer join dept d on e.dept_id =d.id;

自连接

自连接查询语法:

select 字段列表 from 表A 别名A join 表A 别名B on 条件…;

自连接查询,可以是内连接查询,也可以是外连接查询

查询员工及其所属领导的名字
表结构:emp
select a.name,b.name from emp a join emp b on a.managerid=b.id;

查询所有员工emp及其领导的名字emp,如果员工没有领导,也需要查询出来

select a.name '员工',b.name '员工' from emp a left join emp b on a.managerid=b.id;

联合查询

对于union查询,就是把多次查询的结果合并起来,形成一个新的查询结果集

select 字段列表 from 表A …

union [all]

select 字段列表 from 表B …;

查询薪资低于5000的员工和年龄大于50岁的员工
select * from emp where salary<5000 
union all #all合并查询的结果 不加all则表示对查询的结果去重
select * from emp where age>50;

注意:

对于联合查询的多张表的列数必须保持一致,字段类型也需要保持一致

union all合并查询的全部数据 union则表示对合并查询的结果去重

子查询

标量子查询:子查询返回的结果是单个值(数字、字符串、日期)等最简单的形式

常用的操作符:= <> > >= < <=

查询销售部的所有员工信息
1.查询销售部部门id
select id from dept where name='销售部';
2.根据销售部部门id,查询员工信息
select * from emp where dept_id=4;
-------------------------------------
select * from emp 
where dept_id=(
select id from dept where name='销售部');


查询在方东白入职之后的员工信息
1.查询方东白的入职时间
select worktime from emp where empname='方东白';
2.查询入职时间大于方东白的员工
select * from emp where worktime>'2009-02-12';
---------------------------------------
select * from emp where worktime>(
select worktime from emp where empname='方东白');
列子查询:子查询返回的结果是一列(可以是多行)

常用的操作符:IN、NOT IN、ANY、SOME、ALL

img

查询销售部和市场部的所有员工信息
1.查询销售部和市场部的部门id
selec id from dept where name='市场部' 
or name='销售部';
2.根据部门id,查询员工信息
select * from emp where in(2,4);
-----------------------------------
select * from emp where in(
select id from dept where name='市场部' 
or name='销售部'); 
查询比财务部所有人工资都高的员工信息
1.查询财务部员工的所有工资
select salary from emp where dept_id=(
select id from dept where name='财务部');
2.查询大于财务部工资最高员工的信息
select * from emp where salary >all(
select salary from emp where dept_id=(
select id from dept where name='财务部')
);

查询比研发部其中任意一人工资高的员工信息
1.查询研发部员工的工资
select id from dept where name='研发部';
select salary form emp where dept_id=(
select id from dept where name='研发部');
2.查询大于研发部任意一个员工工资的信息
select * from emp where salary>any(
select salary form emp where dept_id=(
select id from dept where name='研发部'));
行子查询:子查询返回的结果是一行(可以是多列)

常用的操作符:=、<>、IN、NOT IN

查询与张无忌的薪资及其直属领导相同的员工信息
1.查询张无忌的薪资和直属领导managerid
select salary from emp where empname='张无忌';
select managerid from emp where empname='张无忌';
------------------------------------------------
select salary,managerid from emp where empname='张无忌';
2.查询直属领导下其他员工信息
select * from emp where salary = 12500 and managerid=1;
select * from emp where (salary,managerid)=(12500,1);
------------------------------------------------
select * from emp where (salary,managerid)=(
select salary,managerid from emp where empname='张无忌';
);
表子查询:子查询返回的结果是多行多列

常用的操作符:IN

查询与鹿杖客,宋远桥的职位和薪资相同的员工信息
1.查询两个人的职位和薪资
select job,salary from emp where name='鹿杖客' or name='宋远桥';
2.再查询与信息相等的员工
select * from emp where (job,salary)in(
select job,salary from emp where name='鹿杖客' or name='宋远桥'
);
查询入职日期是2006-01-01之后的员工信息及部门信息
1.查询入职日期大于2006-01-01的员工
select * from emp where worktime>'2006-01-01';
2.再查询入职日期大于2006-01-01的员工信息和部门信息
select e.*,d.*
from (select * from emp where worktime>'2006-01-01') e
where left join dept d on e.dept_id=d.id;

多表查询案例

distinct :去重

查询员工的姓名、年龄、职位、部门信息(隐式内连接)
select name,age,job,d.name from emp e,dept d
where e.dept_id=d.id;

查询年龄小于30岁的员工姓名、年龄、职位、部门信息(显示外连接)
select name,age,job,d.name 
from emp e inner join dept d on e.dept_id=d.id
where e.age<30;

查询拥有员工的部门ID、部门名称
select distinct dept_id,d.name 
from emp e join d.dept on e.dept_id=d.id; 

查询所有年龄大于40岁的员工,及其归属的部门名称;
如果员工没有分配部门,也需要展示出来
select e.*,d.name from emp e left join dept d 
on e.dept_id=d.id
where e.age>40;

1.查询年龄大于40的员工id
select id from emp where age>40;
2.根据id查找归属部门
select e.*d.name from emp e,dept d
where d.id=(select id from emp where age>40);

查询所有员工的工资等级
表:emp,salgrade
连接条件:emp.salary>=salgrade.losal and emp.salary<=salgrade.hisal
select e.*,s.grade  from emp e,salgrade s
where e.salary>=s.losal and e.salary<=s.hisal;
----------------------------------------------
where e.salary between s.losal and s.hisal;


查询研发部所有员工的信息及工资等级
select e.*,s.grade from emp e,dept d,salgrade s
e.dept_id=d.id 
and(e.salary between s.hisal and s.hisal)
and d.name='研发部';

查询研发部员工的平均工资
select avg(salary) from emp e,dept d
where e.dept_id=d.id and d.name='研发部';

查询工资比灭绝高的员工信息
select id from emp where emp.name='灭绝';

select * from emp where emp.salary>(
select salary from emp where emp.name='灭绝');

查询比平均薪资高的员工信息
select avg(salary) from emp;
select * from emp where emp.salary(
select avg(salary) from emp);

查询低于本部门平均工资的员工信息
select avg(e.salary) from emp e1
where e.dept_id=1;

select * from emp e2
where e2.salary<(
select avg(e1.salary) from emp e1
where e.dept_id=e2.dept_id);

查询所有的部门信息,并统计部门的员工人数
select id,name from dept;

select count(*) from emp where dept_id=1;

select d.id,d.name,
(select count(*) from emp where e.dept_id=d.id)
from dept d;
查询所有学生的选课情况,展示出学生名称、学号、课程名称
表结构:student,course,student_course
连接条件:student.id=student_course.studentid,
          course.id=student_course.courseid
select s.name,s.id,c.name
from student s,course c,student_course sc
where s.id=sc.studentid and c.id=c.courseid;

事务

事务简介

事务是一组操作的集合,是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。

默认MySQL的事务是自动提交的,也就是说,当执行一条DML语句,MySQL会立即隐式的提交事务

事务操作

查看/设置事务提交方式

select @@autocommit;

set @@autocommit=0; #设置为手动提交

提交事务

commit;

回滚事务

rollback;

恢复数据
update account set money=2000 where name='张三' or name ='李四';

select @@autocommit;

set @@autocommit=0; #设置为手动提交

--转账操作
--1.查询张三账户余额
select * from account where name='张三';

--2.将张三账户余额-1000
update account set money =money-1000 where name='张三';

--3.将李四账户余额+1000
update account set money =money+1000 where name='李四';


--提交事务 执行成功就提交事务
commit;

--回滚事务 出现错误就回滚事务
rollback;
恢复数据
update account set money=2000 where name='张三' or name ='李四';

select @@autocommit;

set @@autocommit=0; #设置为手动提交

--转账操作
--1.查询张三账户余额
select * from account where name='张三';

--2.将张三账户余额-1000
update account set money =money-1000 where name='张三';

程序执行报错.....
--3.将李四账户余额+1000
update account set money =money+1000 where name='李四';


--提交事务 执行成功就提交事务
commit;

--回滚事务 出现错误就回滚事务
rollback;

开启事务

start transaction 或 begin;

提交事务

commit;

回滚事务

rollback;

恢复数据
update account set money=2000 where name='张三' or name ='李四';

select @@autocommit;

set @@autocommit=1; #设置为默认提交

--转账操作
start transaction;
--1.查询张三账户余额
select * from account where name='张三';

--2.将张三账户余额-1000
update account set money =money-1000 where name='张三';

程序执行报错.....
--3.将李四账户余额+1000
update account set money =money+1000 where name='李四';


--提交事务 执行成功就提交事务
commit;

--回滚事务 出现错误就回滚事务
rollback;

事务四大特性(ACID)

原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败

一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态

隔离性(Isolation):数据库系统提供的隔离机制,保证事务再不受外部并发操作影响的独立环境下运行

持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的

并发事务问题:多个事务并发执行操作时出现脏读、不可重复读、幻读

img

脏读:A事务提取到了B事务未提交的数据

不可重复读:A事务两次读取同一条记录,且两次重复读到的数据不同

幻读:A事务在查询数据时,无数据,但是在插入数据时,又显示有查询对应的数据

事务隔离级别

img

**数据性能:**Read uncommitted>Read committed>Repeatable Read(默认)>Serializable

**数据安全性:**Serializable>Repeatable Read(默认)>Read committed>Read uncommitted

查看事务隔离级别

select @@transaction_isolation;

设置事务隔离级别

set [session | global] transaction isolation level {Read uncommitted | Read committed | Repeatable Read(默认) | Serializable}

注意:

事务隔离级别越高,数据越安全,但是性能越低

SQL进阶

存储引擎

MySQL体系结构

img

存储引擎简介

存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式。

存储引擎时基于表的,不是基于库的,所以存储引擎也被称为表类型。

1.创建表时,指定存储引擎

create table 表名(

字段1 字段1类型 [comment 字段1注释],

字段n 字段n类型 [comment 字段n注释],

)engine=innodb [comment 表注释];

2.查询数据库支持的存储引擎

show engines;

查询建表语句
show create table 表名;


创建表my_myisam,并指定MyISAM存储引擎
create table my_myisam(
	id int,
	name varchar(10)
)engine=MyISAM;

创建表my_memory,并指定Memory存储引擎
create table my_myisam(
	id int,
	name varchar(10)
)engine=Memory;

存储引擎特点

InnoDB:

Innodb是一种兼顾高可靠性和高性能的通用存储引擎

在MySQL5.5之后,InnoDB是默认的MySQL存储引擎

特点:

DML操作遵循ACID模型,支持事务

行级锁,提高并发访问性能;

支持外键FOREIGN KEY约束,保证数据的完整性和正确性;

文件:

xxx.ibd:xxx代表的是表名,innoDB引擎的每张表都会对应这样一个表空间文件

存储该表的表结构(frm、sdi)、数据和索引

参数:innodb_file_per_table

img

MyISAM:

介绍

MyISAM是MySQL早期的默认存储引擎

特点
不支持事务,不支持外键

支持表锁,不支持行锁

访问速度快

文件

xxx.sdi:存储表结构信息

xxx.MYD:存储数据

xxx.MYI:存储索引

Memory:

介绍

Memory引擎的表数据时存储在内存中的,由于受到硬件问题、或断电问题的影响,只能将这些作为临时表或缓存使用

特点
内存存放

hash索引(默认)

文件
xxx.sdi:存储表结构信息

img

存储引擎选择

在选择存储引擎时,应该根据应用系统的特点选择合适的存储引擎。

对于复杂的应用系统,还可以根据实际情况选择多种存储引擎进行组合。

img

索引

索引概述

介绍

索引是帮助MySQL高效获取数据的数据结构(有序),方便在这些数据结构上实现高级查找算法

img

索引结构

索引分类

索引语法

SQL性能分析

索引使用

索引设计原则

SQL优化

视图/存储过程/触发器

视图

介绍

视图是一种虚拟存在的表。视图中的数据并不在数据库中实际存在,

行和列数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的

通俗的讲,视图只保存了查询的SQL逻辑,不保存查询结果

所以在创建视图的时候,主要的工作就在于创建SQL查询语句上

视图相关操作

创建

create [or replace] view 视图名称[(列名列表)] as select语句 [with[cascaded | local ] check option]

查询

查看创建视图语句:show create view 视图名称;

查看视图数据:select * from 视图名称 …;

修改

方式一:create [or replace] view 视图名称[(列名列表)] as select语句 [with [cascaded | Local] check option]

方式二:alter view 视图名称[(列名列表)] as select语句 [with [cascaded | Local] check option]

删除

drop view [if exists] 视图名称 [,视图名称]…

创建视图
create or replace view stu_v_1
as select id,name from student where id<=10;
--------------------------------------------
create view stu_v_1 as select id,name from student where id<=10;
查询视图
select * from stu_v_1;
show create view stu_v_1;
修改视图
create or replace view stu_v_1
as select id,name,age from student where id<=10;
-------------------------------------------------
alter view stu_v_1 as select id,name from student where id<=10;

删除视图
drop view if exists stu_v_1;
视图的检查选项

当使用with check option子句创建视图时,MySQL会通过视图检查正在更改的每个行,

MySQL允许基于另一个视图创建视图,还会检查依赖视图中的规则保持一致性,

并提供了两个选项:cascaded 和 local,默认值为cascaded

cascaded:相当于并,需要同时满足两个cascaded,如果没有则生成。

当使用cascaded作为视图的检查选项后,在对数据进行增删改时,它会检查是否满足创建视图时定义的条件。如果满足,则执行操作成功;如果不满足,则执行操作失败。同时,若此时的视图是基于另一个视图创建的,会默认将cascaded作为另一个视图的检查选项,并同时检查是否满足另一个视图的创建条件,需要同时满足,才可执行成功。

img

local:相当于或,只满足当前的local就行,如果没有,则不用管。

当使用local作为视图的检查选项后,在对数据进行增删改时,它会检查是否满足创建视图时定义的条件。如果满足,则执行操作成功;如果不满足,则执行操作失败。同时,若此时的视图是基于另一个视图创建的,不会将local作为另一个视图的检查选项,但需要检查是否满足另一个视图的创建条件,只需要满足local的检查选项,才可执行成功。

img

视图的更新

要使视图可更新,视图中的行与基础表的行之间必须存在一对一的关系

如果视图包含以下任何一项,则该视图不可更新:

1.聚合函数窗口函数(SUM()、MIN()、MAX()、COUNT()等)

2.DISTINCT

3.GROUP BY

4.HAVING

5.UNION 或者 UNION ALL

视图的作用

简单

视图不仅可以简化用户对数据的理解,也可以简化操作

经常使用的查询可以被定义为视图,从而使得用户不用每次指定全部的条件

安全

数据可以授权,但不能授权到数据库特定行和特定列上

通过视图用户只能查询和修改他们所能见到的数据

数据独立

视图可以帮助用户屏蔽真实表结构变化带来的影响

为了保证数据库表的安全性,开发人员在操作tb_user表时,
只能看到的用户的基本字段,屏蔽手机号和邮箱两个字段
create view view_tb_user as select id,name,age from tb_user 


查询每个学生所选修的课程(三张表联查),为了简化操作,定义一个视图
create view student_view 
as 
select s.name student_name ,s.id student_id,sc.name course_name
from student s,course c,student_course sc 
where s.id=sc.studentid and sc.courseid=c.id;

存储过程

介绍

存储过程是事先经过编译并存储在数据库中的一段SQL语句集合,

调用存储过程可以简化应用开发人员的很多工作,

减少数据在数据库和应用服务器之间的传输,对于提高数据处理的效率是有好处的

存储过程思想上很简单,就是数据库SQL语言层面的代码封装与重用

特点

封装,复用

可以接受参数,也可以返回数据

减少网络交互,效率提升

创建

create procedure 存储过程名([参数列表])

begin

–SQL语句

end;

调用

call 存储过程名([参数]);

查看

查询指定数据库的存储过程及状态信息

select * from information_schema,routines routine_schema=‘xxx’;

查询某个存储过程的定义

show create procedure 存储过程名

删除

drop procedure [if exists] 存储过程名;

创建
create procedure p1()
begin
	student count(*) from student;
end;
调用
call p1();
查看
select * from information_schema.routines where routine_schema='itcast';
show create procedure p1;
删除
drop procedure if exists p1;

变量

系统变量

系统变量是MySQL服务器提供,不是用户定义的,属于服务器层面。

分为全局变量(GLOBAL)会话变量(SESSION)

查看所有系统变量 默认是session

show [session | global] variables;

可以通过like模糊匹配方式查找变量

show [session | global ] variables like ‘…’;

查看指定变量的值

select @@[session | global] 系统变量名;

设置系统变量

set [session global] 系统变量名=值;

set @@[session global] 系统变量名=值;

查看系统变量
show variables; 
查看会话变量
show session variables like 'auto%';
查看全局变量
show global variables like 'auto%';

select @@autocommit;
select @@session.autocommit;
select @@global.autocommit;

设置系统变量
set session autocommit=0;
select @@session.autocomit;

注意:

如果没有指定session/global,默认是session,会话变量

mysql服务重新启动后,所设置的全局参数会失效,要想不失效,

可以在/etc/my.cnf中配置

用户变量

用户变量是用户根据需要自己定义的变量,用户变量不用提前声明,在用的时候直接用"@变量名"使用就可以。其作用域为当前连接

赋值

set @var_name=expr [@var_name=expr] …;

set @var_name :=expr [@var_name :=expr] …;

select @var_name :=expr [@var_name :=expr] …;

select 字段名 into @var_name from 表名;

使用

select @var_name;

赋值
set @myname='itcast';
set @myage='40';

set @mygender :='男',@myhobb :='java';

select @mycolor :='red';
select count(*) into @mycount from tb_user;


使用
select @myname,@myage,@mygender,@myhobby; 

select @mycolor,@mycount;

局部变量是根据需要定义的在局部生效的变量,访问之前,需要declare声明,可以用作存储过程内的局部变量和输入参数,局部变量的作用域在其内声明的begin…end块

声明

declare 变量名 变量类型[default…];

变量类型就是数据库字段类型:

INT、BIGINT、CHAR、VARCHAR、DATE、TIME等

赋值

set 变量名=值;

set 变量名 :=值;

select 字段名 into 变量名 from 表名…;

create procedure p2()
begin
	declare stu_count int default 0;
	set stu_count :=100;
	select count(*) into stu_count from student;
	select stu_count;
end;

call p2();
IF

语法:

if 条件1 then

elseif 条件2 then

else

end if;

create procedure p3()
begin
	declare score int default 50;
	declare result varchar(10);
  if score>=85 then
    set result :='优秀';
  elseif score>=60 && score<85 then
    set result :='及格';
  else 
    set result :='不及格';
  end if;
	select result;
end;

call p3();
参数

img

用法

create procedure 存储过程名 ([in/out/inout 参数名 参数类型])

begin

--SQL语句

end;
create procedure p4(in score int,out result varchar(10))
return 
begin
	if score>=85 then 
  	set result :='优秀';
	elseif score>=60 && score<85 then
  	set result :='及格';
	else score<60 then
  	set result :='不及格';
	end if;
end;
#@result是用户自定义变量
call p4(61,@result);
#查看变量@result
select @result;



create procedure p5(inout score double)
begin
	set score :=score*0.5;
end;
set @@score :=50;
call p5(@score);
select @@score;
CASE

语法一

case case_value

when when_value1 then statement_list1

[when when_value1 then statement_list2]…

[else statement_list]

end case;

语法二

case

when search_condition1 then statement_list1

[when search_condition2 then statement_list2]…

[else statement_list]

end case;

create procedure p6(in month int,out result varchar(10))
begin
	case
		when month>=1 || month<=3 then 
    	set result :='第一季度';
  	when month>=4 || month<=6 then
    	set result :='第二季度';
    when month>=7 || month<=9 then
			set result :='第三季度';
  	when month>=10 || month<=12 then
  	  set result :='第四季度';
  	else 
    	set result :='非法参数';
  end case;
	
end;

call p6(1,@result);
select @result ;
----------------------------------------------------
create procedure p6(in month int)
begin
	declare result varchar(10);
	case
		when month>=1 || month<=3 then 
    	set result :='第一季度';
  	when month>=4 || month<=6 then
    	set result :='第二季度';
    when month>=7 || month<=9 then
			set result :='第三季度';
  	when month>=10 || month<=12 then
  	  set result :='第四季度';
  	else 
    	set result :='非法参数';
  end case;
	select concat('当前月份为:',month,',所属季度为:',result);
end;

call p6(1);
循环
WHILE

while循环时有条件的循环控制语句。满足条件后,再执行循环体中的SQL语句。具体的语法为:

#先判定条件,如果条件为true,则执行逻辑,否则,不执行逻辑

while 条件 do

SQL 逻辑…

end while;

create procedure p7(in num int)
begin
	declare temp int 0;
	while num>0 do
  	set temp := temp+num;
  	set num :=num-1;
	end while;
	select temp;
end;

call p7(5);
------------------------------------------------
create procedure p7(inout num int)
begin
	declare temp int 2;
	declare nums int 1;
	while temp<=num do
		set nums := nums+temp;
  	set temp := temp+1;
	end while;
	select nums;
end;

set @num=10;
call p7(@num);
select @num;
REPEAT

repeat是有条件的循环控制语句,当满足条件的时候退出循环。具体语法为:

#先执行一次逻辑,然后判定逻辑是否满足,如果满足,则退出。如果不满足,则继续下一次循环

repeat

SQL逻辑

UNTIL 条件

end repeat;

create procedure p8(in num int)
begin
	declare temp int default 0;
	repeat
   	set temp :=temp+num;
  	set num :=num-1;
  	until num<=0
	end repeat;
	select temp;
end;
call p8(10);
LOOP

loop 实现简单的循环,如果不在SQL逻辑中增加退出循环的条件,可以用其来实现简单的死循环。loop可以配合以下两个语句使用:

leave:配合循环使用,退出循环

iterate:必须用在循环中,作用是跳过当前循环剩下的语句,直接进入下一次循环

[begin_label:] loop

SQL逻辑

end loop [end_label];

leave label; –退出指定标记的循环体

iterate label; –直接进入下一次循环

create procedure p9(in num int)
begin
	declare temp int default 0;
#sum作为此时loop循环的label
	sum:loop
  	if num<=0 then
    	leave sum;
  	end if;
  	set temp := temp+num;
  	set num := num-1;
	end loop sum;
	select temp;
end;
call p9(10);



create procedure p10(in num int)
begin 
	declare temp int default 0;
	sum:loop
  	if num<=0 then
    	leave sum;
  	end if;
  	if num%2==0 then
    	set temp := temp+num;
    	set num := num-1;
  	else
    	iterate sum;
  	end if;
	end loop sum;
end;
游标

游标是用来存储查询结果集的数据类型,在存储过程和函数中可以使用游标对结果集进行循环的处理。

游标的使用包括游标的声明、open、fetch、close,其语法分别如下:

声明游标

#游标的声明必须放在局部变量的声明后面

declare 游标名称 cursor for 查询语句;

打开游标

open 游标名称;

获取游标记录

fetch 游标记录 into 变量 [变量];

关闭游标

close 游标名称;

create procedure p11(in uage int)
begin 
	
	declare uname varchar(20);
	declare upro varchar(2);

	declare u_cursor cursor for 
	select name,profession from tb_user 
	where age<=uage;


	drop table if exists tb_user_pro;
  create table if not exists tb_user_pro(
    id int primary key auto_increment,
  	name varchar(20),
  	profession varchar(20)
	);

	open u_cursor;

	while true do #会报错,但是结果能出来
  	fetch u_cursor into uname,upro;
  	insert into tb_user_pro values(null,uname,upro);
	end while;
	close u_cursor;
end;

call p11(40);

条件处理程序

条件处理程序可以用来定义在流程控制结构执行过程中遇到问题时相应的处理步骤。具体语法为:

img

create procedure p11(in uage int)
begin 
	
	declare uname varchar(20);
	declare upro varchar(20);

	declare u_cursor cursor for 
	select name,profession from tb_user 
	where age<=uage;
#当满足sqlstate '02000'时触发这条语句,触发后关闭游标
	declare exit handler for sqlstate '02000' close u_cursor;

	drop table if exists tb_user_pro;
  create table if not exists tb_user_pro(
    id int primary key auto_increment,
  	name varchar(20),
  	profession varchar(20)
	);

	open u_cursor;

	while true do #会报错,但是结果能出来
  	fetch u_cursor into uname,upro;
  	insert into tb_user_pro values(null,uname,upro);
	end while;
	close u_cursor;
end;

call p11(40);

--------------------------------------------------------------
create procedure p12(in uage int)
begin 
	
	declare uname varchar(20);
	declare upro varchar(20);

	declare u_cursor cursor for 
	select name,profession from tb_user 
	where age<=uage;
#当满足sqlstate '02000'时触发这条语句,触发后关闭游标
	declare exit handler for not found close u_cursor;

	drop table if exists tb_user_pro;
  create table if not exists tb_user_pro(
    id int primary key auto_increment,
  	name varchar(20),
  	profession varchar(20)
	);

	open u_cursor;

	while true do #会报错,但是结果能出来
  	fetch u_cursor into uname,upro;
  	insert into tb_user_pro values(null,uname,upro);
	end while;
	close u_cursor;
end;

call p12(40);

--------------------------------------------------------------

存储函数

存储函数是有返回值的存储过程,存储函数的参数只能是in类型的。具体语法如下:

img

create function fun1(in num int)
returns int deterministic
begin
	declare temp int default 0;

	while num>0 do
  	set temp := temp+num;
  	set num := num-1;
	end while;

	return temp;
end;

set @score=10;
call fun1(@score);
select @score;
------------------------
select fun1(10);

触发器

介绍

触发器是与表有关的数据库对象,指在insert/update/delete之前或之后,触发并执行触发器中定义的SQL语句集合

触发器的这种特性可以协助应用在数据库端确保数据的完整性,日志记录,数据校验等操作。

使用别名OLD 和 NEW 来引用触发器中发生变化的记录内容,这与其他的数据库是相似的。目前触发器只支持行级触发,不支持语句级触发。

img

语法

创建

create trigger 触发器名称

before/after insert/update/delete

on 表名 for each row --行级触发器

begin

触发器的逻辑实现;

end;

查看

show triggers;

删除

如果没有指定schema_name,默认为当前数据库

drop trigger [schema_name.]触发器名称;

img

插入数据触发器
create trigger tb_user_insert_trigger
	after insert on tb_user for each row
begin
	insert into user_logs(id,operation,operate_time,operate_id,operate_params)values
	(null,'insert',now(),new.id,concat('插入的数据内容:id=',new.id,"name=",new.name,"profession=",new.profession))
end;
查看
show triggers;
删除
drop trigger tb_user_insert_trigger;
插入数据触发器
create trigger tb_user_uppdate_trigger
	after uppdate on tb_user for each row
begin
	insert into user_logs(id,operation,operate_time,operate_id,operate_params)values
	(null,'uppdate',now(),new.id,
	concat('更新之前的数据:id=',old.id,"name=",old.name,"profession=",old.profession,
	'更新之后的数据:id=',new.id,"name=",new.name,"profession=",new.profession)
end;
查看
show triggers;
删除
drop trigger tb_user_uppdate_trigger;
插入数据触发器
create trigger tb_user_delete_trigger
	after delete on tb_user for each row
begin
	concat('删除之前的数据:id=',old.id,"name=",old.name,"profession=",old.profession)
end;
查看
show triggers;
删除
drop trigger tb_user_delete_trigger;

概述

锁是计算机协调多个进程或线程并发访问某一资源的机制

保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题

全局锁:锁定数据库中的所有表

介绍
对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的DML语句,DDL语句,以及更新操作的事务提交语句都将被阻塞

**使用场景:**全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性

img

特点

数据库中加全局锁,是一个比较重的操作,存在以下问题:

1.如果在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆

2.如果在从库上备份,那么在备份期间从库不能执行主库同步过来的二进制日志,会导致主从延迟。

在InnoDB引擎中,我们可以在备份时加上参数

–single-transaction参数来完成不加锁的一致性数据备份

mysqldump --single-transaction -uroot -p123456 itcast>itcast.sql

表级锁:每次操作锁住整张表

介绍

**表级锁,每次操作锁住整张表。锁定粒度大,发生锁冲突的概率最高,并发度最低。**应用在MyISAM、InnoDB、BDB等存储引擎中

对于表级锁,主要分以下三类:

1.表锁

表锁又可分为:

1、表共享读锁(read lock)

2、表独占写锁(write lock)

读锁不会阻塞其他客户端的读,但是会阻塞写。

写锁既会阻塞其他客户端的读,又会阻塞其他客户端的写。

语法:

1、加锁:lock tables 表名… read/write

2、释放锁:unlock tables / 客户端断开连接

2.元数据锁(meta data lock,MDL)

MDL加锁过程是系统自动控制,无需显示使用,在访问一张表的时候自动加上。

MDL锁主要作用是维护表元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入操作

为了避免DML与DDL冲突,保证读写的正确性

在MySQL5.5中引入了MDL,当对一张表进行增删改查的时候,加MDL读锁(共享);当对表结构进行变更操作的时候,加MDL写锁(排他)

img

当锁类型为SHARED_READ和SHARED_WRITE时,我们的锁类型时可以兼容的。

当所类型为EXCLUSIVE和SHARED_READ或SHARED_WRITE时,我们的所类型不能兼容。

查看元数据锁

select object_type,object_schema,object_name,lock_type,lock_duration from performance_schema.metadata_locks;

3.意向锁

为了避免DML在执行时,所加的行锁与表锁的冲突。

在InnoDB中引入了意向锁,使得表锁不用检查每行数据是否加锁,使用意向锁来减少表锁的检查。

1、**意向共享锁(IS):**由语句select … lock in share mode添加

与表锁共享锁(read)兼容,与表锁排它锁(write)互斥

2、**意向排他锁(IX):**由insert、update、dalete、select … for update 添加

与表锁共享锁(read)及排它锁(write)都互斥。意向锁之间不会互斥。

查看意向锁及行锁的加锁情况

select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from performance_schema.metadata_locks;

行级锁:每次操作锁住对应的行数据

介绍

行级锁,每次操作锁住对应的行数据。锁定粒度最小,发生锁冲突的概率最低,并发度最高。应用在InnoDB存储引擎中。

InnoDB的数据是基于索引组织的,行锁是通过对索引上的索引项加锁来实现的,而不是对记录加的锁。

对于行级锁,主要分为以下三类:

1、行锁(Record Lock):锁定单个行记录的锁,防止其他事务对此行进行update和delete。在RC、RR隔离级别下都支持。

InnoDB实现了以下两种类型的行锁

1、共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁

img

2、排他锁(X):允许获取排他锁的事务更新数据,阻止其他事务获得相同数据集的共享锁和排他锁

img

行锁-演示

默认情况下,InnoDB在repeatable read事务隔离级别运行,InnoDB使用next-key锁进行搜索和索引扫描,以防止幻读。

1、针对唯一索引进行检索时,对已存在的记录进行等值匹配时,将会自动优化为行锁。

2、InnoDB的行锁是针对索引加的锁,不通过索引条件检索数据,那么InnoDB将对表中的所有记录加锁,此时就会升级为表锁

查看意向锁及行锁的加锁情况

select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from performance_schema.data_locks;

2、间隙锁(Gap Lock):锁定索引记录间隙(不含该记录),确保索引记录间隙不变,防止其他事务在这个间隙进行insert,产生幻读。在RR隔离级别下都支持。(锁住间隙,不包含对应的数据对象)
3、临建锁(Next-key Lock):行锁和间隙锁组合,同时锁住数据,并锁住数据前面的间隙Gap。在RR隔离级别下支持。(不止锁住间隙,还包含对应的数据对象)

默认情况下,InnoDB在repeatable read事务隔离级别运行,InnoDB使用next-key锁进行搜索和索引扫描,以防止幻读。

1、索引上的等值查询(唯一索引),给不存在的记录加锁时,优化为间隙锁

2、索引上的等值查询(普通索引),向右遍历时最后一个值不满足查询需求时,next-key lock(临建锁) 退化为间隙锁

3、索引上的范围查询(唯一索引)–会访问到不满足条件的第一个值为止

注意:

间隙锁唯一目的是防止其他事务插入间隙。间隙锁可以共存,一个事务采用的间隙锁不会组织另一个事务在同意间隙上采用间隙锁


  • 19
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值