SQL学习总结

SQL注释:

-- 单行注释,-- 后一定有空格;#单行注释

/*

多行注释

.....

*/

数据库管理系统

  • 关系型数据库(RDBMS)
    • Oracle数据库
    • MySQL数据库
    • SQL Server数据库
    • PostgreSQL
    • SQLite(嵌入式数据库)
  • 非关系型数据库(NoSQL)
    • Redis(最好的缓存数据库)
    • MongoDB(最好的文档数据库)
    • Elasticsearch(最好的搜索服务)
    • Cassandra
    • HBase(优秀的分布式、列式数据库)

基本操作

使用SQL时刻注意的思想:

  1. 空值不能和任何值比大小(无论结果如何都返回NULL),可以将空值转换为0比较
  2. 查询语句执行顺序:from指定表——>where筛选——>group by分组——>having分组结果筛选——>select选择字段——>order by排序——>limit指定显示行数
  3. 使用group by分组后,select后面只能选择分组字段和分组聚合的结果(不能选择未分组字段)
DDL 数据定义语言

​ 定义数据库对象(数据库,表,字段)

  • 对数据库的常用操作
功能 SQL
查看所有数据库 show databases
创建数据库 create database [if not exists] mydb [charset=utf8];
选择数据库 use mydb;
删除数据库 drop database [if exists] mydb;
修改数据库编码 alter table mydb character set utf8;
  • 对表结构的常用操作
功能 SQL
创建表 create table [if not exists] tableName(字段1 类型[(宽度)] [约束条件] [comment '字段说明'],字段2 类型[(宽度)] [约束条件] [comment '字段说明'])charset=utf8;创建临时表create temporary table tableName as select …
查看当前数据库所有表名称 show tables;
查看指定表的创建语句 show create table tableName;
查看表结构 desc tableName;
删除表 drop table tableName;
修改表结构 alter table tableName add 列名 类型(长度) [约束];
alter table tableName modify 列名 新数据类型(长度) [约束];
修改列名称和类型 alter table tableName change 旧列名 新列名 类型(长度) [约束];
删除表字段 alter table tableName drop 删除列名;
修改表名 rename table 表名 to 新表名;
-- 创建表
create table [if not exists] tableName(
	字段1 类型[(宽度)] [约束条件] [comment '字段说明'],
    字段2 类型[(宽度)] [约束条件] [comment '字段说明'],
	)charset=utf8;

数据类型

1)整数类型:tinyint,smallint,mediumint,int,bigint 。默认有符号,可在数值类型后面加入unsigned指定无符号

2)浮点数:float,double,decimal(m,n)-m个有效位小数保留n位

3)日期类型:date(年月日),datetime(年月日时分秒),year,time,timestamp(自动填充当前时间)

4)字符串类型:char(m),varchar(m),text(文本数据),longtext,blob(二进制数据)

MySQL约束

约束是作用于表中字段的规则,用于限制存储在表中的数据,作用是保证数据库中数据的正确、有效性和完整性。

  • 主键约束(primary key):一个列或者多个列的组合,值能唯一的标识表中的每一行。特点唯一+非空
-- 创建表定义字段时指定主键
create table tableName (
	<字段名> <数据类型> primary key,
	<字段名> <数据类型>
	....)charset=utf8;
	
-- 创建表定义字段后指定主键
create table tableName (
	<字段名> <数据类型>,
	<字段名> <数据类型>
	....
    [constraint <约束名>] primary key (字段1,字段2,...) ]
)charset=utf8;

-- 修改表结构时添加主键
alter table tableName add primary key (字段名,字段2,...);

-- 删除主键
alter table tableName drop primary key;
  • 自增长约束(auto_increment):给主键列添加自增长约束,用户不输入数据自动赋值

delete再插入数据自增长字段从断点开始;truncate自增长字段值从1开始

-- 创建表添加自增长约束
create table tableName (
	<字段名> <数据类型> primary key auto_increment,
	<字段名> <数据类型>
	....)charset=utf8;
	
-- 创建表时添加自增长约束并指定自增长开始值
create table tableName (
	<字段名> <数据类型> primary key auto_increment,
	<字段名> <数据类型>
	....)auto_increment=100;
	
-- 创建表后修改自增长字段开始值
alter table tableName auto_increment=100;
  • 非空约束(not null):指定字段值非空
-- 创建表时指定
create table tableName (
	<字段名> <数据类型> primary key auto_increment,
	<字段名> <数据类型> not null
	....)charset=utf8;
	
-- 修改表结构指定
alter table tableName modify 字段名 类型 not null;
-- 删除非空约束
alter table tableName drop 字段名 类型;
  • 唯一约束(unique):说明字段取值唯一性,可以为NULL(NULL和任何值包括自己不相同)
-- 创建表时指定
create table tableName (
	<字段名> <数据类型> primary key auto_increment,
	<字段名> <数据类型> unique
	....)charset=utf8;
	
-- 修改表结构指定
alter table tableName add constraint 约束名 unique(列名);
-- 删除唯一约束
alter table tableName drop index 唯一约束名;
  • 默认约束(default):指定某列的默认值
-- 创建表时指定
create table tableName (
	<字段名> <数据类型> primary key auto_increment,
	<字段名> <数据类型> default <默认值>
	....)charset=utf8;
	
-- 修改表结构添加默认值
alter table tableName modify 列名 类型 default <默认值>;
-- 删除默认约束
alter table tableName modify 列名 类型 default NULL;
  • 零填充约束(zerofill):插入数据时数值类型字段值小于定义的长度会在值前面补上0,默认长度int(10)
-- 创建表时指定
create table tableName (
	<字段名> <数据类型> zerofill,
	....)charset=utf8;
	
-- 删除零填充约束
alter table tableName modify 列名 类型;
  • 外键约束(foreign key):建立主表与从表的关联关系(主表主键列控制从表外键列,主表主键没有的数据从表添加不了),主表数据被从表依赖时不可随便删除,从表可随便删除,保证数据一致性和完整性。
-- 创建表时指定
create table tableName (
	<字段名> <数据类型>,
	<字段名> <数据类型>,
	....
    [constraint <约束名>] foreign key (字段[,字段2,...]) references <主表名> (主键列[,主键列2,...])
)charset=utf8;
	
-- 修改表结构添加外键约束(多对多关系要创建中间表作为从表,其他两张表都是主表)
alter table tableName add constraint <约束名> foreign key (字段[,字段2,...]) references <主表名> (主键列[,主键列2,...]);
-- 删除外键约束
alter table tableName drop foreign key 外键约束名;

父表删除/更新行为:

行为 说明
NO ACTION 当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除/更新。 (与 RESTRICT 一致) 默认行为
RESTRICT 当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除/更新。 (与 NO ACTION 一致) 默认行为
CASCADE 当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有,则也删除/更新外键在子表中的记录。
SET NULL 当在父表中删除对应记录时,首先检查该记录是否有对应外键,如果有则设置子表中该外键值为null(这就要求该外键允许取null)。
SET DEFAULT 父表有变更时,子表将外键列设置成一个默认的值 (Innodb不支持)
-- 语法(更新和删除添加cascade行为)
ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段) REFERENCES 主表名 (主表字段名) ON UPDATE CASCADE ON DELETE CASCADE;
  • 检查约束(check):保证字段值输入按照表建立者设定的规则。mysql 8.0.16版本及以上
create table tableName (
	<字段名> <数据类型> check(字段名 >0 && 字段名 < 100),
	<字段名> <数据类型>,
	....
)charset=utf8;

DML 数据操作语言(增删改)
  • 数据插入
insert into tableName (1,2,...) values (1,2,...);

insert into tableName values (1,2,...),(3,4,...),(5,6,...);
  • 数据修改
update tableName set 字段名1=1,字段名2=2,...where 条件;
  • 数据删除
--删除表数据(所有数据),只删除内容,保留表结构再插入数据自增长字段从断点开始
delete from tableName [where 条件];
--清空表数据,保留表结构,自增长字段从1开始
truncate table tableName;  |   truncate tableName;
-- 删除数据和表结构
drop table tableName;
DQL 数据查询语言
-- 基本语法
select [distinct] --distinct *去除重复行;distinct 字段名 去除重复列
	字段名1 [as 别名1],
	字段名2 别名2...
from <表名或视图名> [别名],<表名或视图名> [别名]...
[where where_contition] -- 分组前过滤,不能对聚合函数进行判断
[group by <分组字段>]-- 分组字段列表,可以对聚合函数进行判断
[having where_contiton] -- 分组后过滤条件
[order by <排序字段1>[desc],<排序字段2>,... [desc]] -- 排序字段列表,默认升序,desc降序
[limit m,n] -- 查询结果指定记录数,从第m+1条查询n条数据

执行顺序: from指定表——>where筛选——>group by分组——>having分组结果筛选——>select选择字段(有分组只能选择分组字段和字段聚合结果)——>order by排序——>limit指定显示行数

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

where查询条件运算符:

  • 比较运算符:

    比较运算符 说明
    = 等于
    <>,!= 不等于
    < 小于
    <= 小于等于
    > 大于
    >= 大于等于
    least 有两个或多个参数返回最小值 ,其中有值为NULL返回NULL
    greatest 有两个或多个参数返回最大值 ,其中有值为NULL返回NULL
    [not] between…and… 判断值是否处在两个值之间
    is [not] null 判断值是否非空
    in(a,b,c…) 判断值是否在一个列表内
    [not] like… 字符串通配符匹配(_代表一个字符;%代表任意字符)
    regexp 字符是否匹配正则表达式,匹配返回0或1
select * from where 字段 regexp '正则表达式';

  • 逻辑运算符:

    逻辑运算符 说明
    not 或 !,| 逻辑非
    and 或 && 逻辑与
    or 或 || 逻辑或
    xor 逻辑异或 #不同为真,相同为假
  • 位运算符(二进制运算)

    位运算符 说明
    | 按位或
    & 按位与
    ^ 按位异或
    << 按位左移
    >> 按位右移
    ~ 按位取反

将查询结果导入到另一张表

-- 要求table2 必须存在
insert into table2 select * from table1 where...group by...having...
-- 要求table2 不存在
select * into table2 from table1 where...group by...having...
多表操作

**MySQL多表关系:**一对一(用于单表的拆分),一对多,多对多

多表之间根据外键约束添加联系

  • 一对一关系实现:在任意一方加入外键,关联另外一方的主键,并且设置外键为唯一的(UNIQUE)
  • 一对多关系实现:在多的一方建立外键,指向一的一方的主键
  • 多对多关系实现:建立第三张中间表,中间表至少包含两个外键,分别关联两方主键

多表查询

多表查询:

​	1、交叉连接查询(得到两张表的乘积,笛卡尔积,会产生冗余数据):select * from A,B,...;2、内连接查询:

​		隐式内连接:select * from A,B where 条件;

​		显示内连接:select * from A inner join B on 条件;  -- on中相同的key匹配上时会产生笛卡尔积3、外连接查询:outer join

​		左外连接:select * from A left [outer] join B on 条件;

​		右外连接:select * from A right [outer] join B on 条件;

​	    满外连接查询:select * from A full outer join B on 条件;4、子查询:一条select语句结果(值或者表)作为另一条select语句的输入 
		子查询位置:where之后,from之后,select之后(select后接子查询相当于两个表隐式内连接)
		    select d.id, d.name , ( select count(*) from emp e where e.dept_id = d.id )               '人数' from dept d;
		子查询关键字:ALL:与子查询返回的所有值比较所有为true返回true where 字段名>all(select子查询)
					ANY:与子查询返回的所有值比较一个为true返回true where 字段名>any(select子查询)
					SOME:等价于ANY where 字段名>some(select子查询)
					IN:判断值是否在返回结果的集合中 where 字段名 in (select子查询)
					EXISTS:子查询结果返回至少一行数据EXISTS()返回true,外层查询执行 
							where exists(select子查询)
			select * from table1 a where exists(select * from table1 where a.字段名>100);
			标量子查询:子查询结果是单行单列(一个值)
				常用操作符:= <> > >= < <=            where =(select 子查询)
			列子查询:子查询结果是多行单列
				常用操作符:IN,NOT IN,ANY,SOME,ALL    where in (select子查询)
			行子查询:子查询结果是单行多列
				常用操作符:=,<>,IN,NOT IN            where (字段1,2,3) = (子查询)
			表子查询:子查询结果是多行多列
				常用操作符:IN,not in,exists                 where (字段1,2,3) in (子查询)
				select * from (子查询结果表)tmp join table2 on5、自关联查询:
-- 先添加自己表和自己表的外键约束
alter table tableName add constraint <约束名> foreign key (字段[,字段2,...]) references tableName (主键列[,主键列2,...]);
-- 自关联查询
select * from tableName t1 left join tableName t2 on t1.字段1=t2.字段2;
                                      
-- 联合查询:将两个select查询结果统一展示。
SELECT 字段列表 FROM 表A ...
UNION [ ALL ]
SELECT 字段列表 FROM 表B ....;
/*
注意:

* 对于联合查询的多张表的列数必须保持一致,字段类型也需要保持一致
* 使用`union`关键字把两个查询结果合并展示,去重;`union all`将两个查询结果上下拼接,不去重
*/

DCL 数据控制语言

创建数据库用户,控制数据库的访问权限

-- 查询用户
select * from mysql.user;
-- 创建用户
CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';
-- 创建用户itcast, 只能够在当前主机localhost访问, 密码123456;
create user 'itcast'@'localhost' identified by '123456';
-- 创建用户heima, 可以在任意主机访问该数据库, 密码123456;
create user 'heima'@'%' identified by '123456';
-- 修改用户密码
ALTER USER '用户名'@'主机名' IDENTIFIED WITH mysql_native_password BY '新密码';
-- 修改用户heima的访问密码为1234;
alter user 'heima'@'%' identified with mysql_native_password by '1234';
-- 删除用户
DROP USER '用户名'@'主机名';
-- 删除 itcast@localhost 用户
drop user 'itcast'@'localhost';

-- 权限控制
-- 查询权限
SHOW GRANTS FOR '用户名'@'主机名' ;
-- 查询 'heima'@'%' 用户的权限
show grants for 'heima'@'%';
-- 授予权限。多个权限之间,使用逗号分隔;授权时, 数据库名和表名可以使用 * 进行通配,代表所有。
GRANT 权限列表 ON 数据库名.表名 TO '用户名'@'主机名';
-- 授予 'heima'@'%' 用户itcast数据库所有表的所有操作权限
grant all on itcast.* to 'heima'@'%';
-- 撤销权限
REVOKE 权限列表 ON 数据库名.表名 FROM '用户名'@'主机名';
-- 撤销 'heima'@'%' 用户的itcast数据库的所有权限
revoke all on itcast.* from 'heima'@'%';

权限列表说明

权限 说明
ALL, ALL PRIVILEGES 所有权限
SELECT 查询数据
INSERT 插入数据
UPDATE 修改数据
DELETE 删除数据
ALTER 修改表
DROP 删除数据库/表/视图
CREATE 创建数据库/表

MySQL内置函数

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

聚合函数

  • count() 计数 #count值为null的行
  • sum() 求和
  • min() 最小值
  • max() 最大值
  • avg() 平均值
  • group_concat() 同一分组的值连接起来返回一个字符串结果

select group_concat([distinct] 字段名 [order by 组内排序字段 asc/desc] [separatoe '分隔符']) from tableName group by 分组字段;

数学函数

  • round(3,141592,3) 保留几位小数,默认返回四舍五入整数

  • truncate(3.141592,3) 截取几位小数(不四舍五入)

  • rand() 返回0-1的随机数

    select lpad(round(rand()*1000000,0),6,"0") – 生成6位数随机验证码

  • abs() 返回绝对值

  • ceil() 向上取整

  • floor() 向下取整

  • greatest() 取列表最大值

  • least() 取列表最小值

  • max() 最大值

  • min() 最小值

  • mod(m,n) m/n后的余数

  • pi() 返回圆周率

  • power(x,y) 返回x的y次方

字符串函数

  • concat(字符串a,字符串b,字符串c) 字符串直接合并

  • concat_ws(‘分隔符’,字符串a,字符串b,字符串c) #字符串连接函数。concat_ws(‘-’,year,month,day)

  • substr(字符串,start,len) #将字符串从start开始截取len长度的子字符串——等价于substring()

  • char_length(字符串) 返回字符串的字符数

  • field(字符串,字符串列表) 返回字符串在列表中的位置

  • ltrim() 去除字符串左边空格

  • rtrim() 去除字符串右边空格

  • trim() 去除字符串两边空格

  • mid(字符串,m,n) 截取字符串从第m个共n个字符

  • position(a in b) 返回字符串a在字符串b中的位置

  • replace(字符串,子串1,子串2) 将字符串中子串1替换为子串2

  • reverse() 字符串反转

  • right(字符串,n) 返回字符串后n个字符

  • strcmp() 字符串比较

  • upper() 全部字符串小写转换为大写——等价于ucase()

  • lower() 全部字符串大写转换为小写——等价于lcase()

  • lpad(str,n,pad) 左填充,用字符串pad对str的左边进行填充,达到n个字符串长度

    update tableName set id=lpad(id,8,0);

  • rpad(str,n,pad) 右填充,用字符串pad对str的右边进行填充,达到n个字符串长度

  • locate(str,字段名) > 0,表示sub字符串包含str字符串;Locate(str,字段名) = 0,表示字符串不包含str字符串

  • instr(字段名,str)函数:返回str子字符串在字符串的第一次出现位置

日期函数

  • date_format(字符串日期,格式) 格式化日期 select date_format(‘2022-1-1 0:0:0’,‘%Y-%m-%d %H:%i:%s’)
  • str_to_date() 字符串转换为日期
  • date(日期时间) 返回日期时间中的日期值
  • year(日期) #返回年份
  • month(日期)
  • day(日期)
  • quarter() 获取季度
  • date_add(日期,n,day/month/year) #在日期基础上加2天 select date_add(‘2022-02-02’,interval 2 day)
  • date_sub(日期,n,day/month/year) #在日期基础减2月 select date_sub(‘2022-02-02’,interval 2 month)
  • datediff(日期1,日期2) 返回日期之间的差值
  • timediff(时间1,时间2) 返回时间之间的差值
  • unix_timestamp() 返回1970-01-01 00:00:00到当前的毫秒值,转换为时间戳
  • from_unixtime() 时间戳转换为指定日期格式
  • curdate() 返回当前日期(年月日)——等价于current_date()
  • current_time() 返回当前时分秒——等价于curtime()
  • now() 返回当前日期和时间
  • current_timestmap() 获取当前年月日时分秒
  • extract(year from ‘2022-02-02’) 日期中获取年
  • last_day(日期) 获取给定日期所在月的最后一天 last_day(‘2022-02-02’)
  • makedate(‘2022’,53) 返回2022年第53天
  • monthname() 获取月份英文
  • dayname()获取周几
  • dayofmonth(),dayofweek()dayofyear() 获取月,周,年的第几天

控制流函数

  • IF逻辑判断语句

    • if(逻辑表达式,值1,值2) 逻辑表达式成立取值1,否则取值2
    • ifnull(字段,默认值0) 字段取值不为NULL取值本身,为NULL取值为默认值0
    • isnull(字段) 判断字段取值是否为NULL
  • nullif(字段1,字段2) 字段1和字段2取值相同返回NULL,否则返回字段1的值

  • case when语句

    select
    	case 字段名
    		when...then...
    		when...then...
    		else...
    	end as 别名
    
    

行转列:select 分组字段,concat_ws(‘|’,collect_set(聚合字段)) as 别名 from 表名 group by 分组字段;

窗口函数

  • 序号函数:主要用于分组排序(或只排序排名)

rank()|dense_rank()|row_number() over (partition by 分组字段 order by 排序字段 desc|esc) as 别名

排序的窗口函数区别:

ROW_NUMBER() 这个函数赋予唯一的连续位次。

例如,有3条排在第1位时,排序为:1,2,3,4······

RANK() 在计算排序时,若存在相同位次,会跳过之后的位次。

例如,有3条排在第1位时,排序为:1,1,1,4······

DENSE_RANK() 在计算排序时,若存在相同位次,不会跳过之后的位次。

例如,有3条排在第1位时,排序为:1,1,1,2······

分组排序TopN:

select * from (select *,rank() over (partition by 分组字段 order by 排序字段 desc) as rank_1) t where t.rank_1<=N;

  • 开窗聚合函数

sum()|max()|min()|avg()|count() over (partition by 分组字段 order by 排序字段 desc|esc) as 别名

排序的窗口函数区别:

累加求和:sum(求和字段) over(partition by 分组字段 order by 排序字段 asc)

每一组的总和:sum(求和字段) over(partition by 分组字段)

#从开头累加到当前行

select *,sum(求和字段) over(partition by 分组字段 order by 排序字段 rows between unbounded preceding and current row) as 别名 from 表名;

#从前3行累加到当前行(共4行:-3,-2,-1,0)

select *,sum(求和字段) over(partition by 分组字段 order by 排序字段 rows between 3 preceding and current row) as 别名 from 表名;

#从前三行累加到后一行(共5行:-3,-2,-1,0,1)

select *,sum(求和字段) over(partition by 分组字段 order by 排序字段 rows between 3 preceding and 1 following) as 别名 from 表名;

#从当前行累加到最后一行

select *,sum(求和字段) over(partition by 分组字段 order by 排序字段 rows between current row and unbounded following) as 别名 from 表名;

  • 分布函数

    • cume_dist() 分组内小于、等于当前rank值的行数/分组内总行数

    cume_dist() over(partition by 分组字段 order by 排序字段)

    • percent_rank() 分组内(rank-1)/(分组总行数-1)
  • 前后函数

    • lag(日期字段,n,'2020-02-02') over(partition by 分组字段 order by 排序字段) 返回前n行的日期值,没有返回默认值
    • lead(日期字段,n,'2020-02-02') over(partition by 分组字段 order by 排序字段) 返回后n行的日期值,没有返回默认值
  • 头尾函数:返回组内最大、最小值

    • first_value(字段名) over(partition by 分组字段 order by 排序字段) 截止当前组内排序后第一个
    • last_value(字段名) over(partition by 分组字段 order by 排序字段) 截止当前组内排序后最后一个

事务

事务是一组操作的集合,是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求。

事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行

事务的四大特性:

  • 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
  • 一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态。
  • 隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
  • 持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。
-- 查看事务状态(结果为1默认自动提交)
select @@autocommit
-- 关闭事务自动提交
set autocommit=0 -- 禁止自动提交 
set autocommit=1 -- 开启自动提交 (默认自动提交)

-- 开启事务
begin; 或 start transaction;
-- update等SQL语句
-- 提交事务,关闭自动提交后只有提交事务才会生效
commit;
-- 回滚事务,失败的结束,将所有的DML语句操作历史记录全部清空
rollback;

-- 查看隔离级别 
SELECT @@TRANSACTION_ISOLATION;
show variables like '%isolation%’; 

-- 设置隔离级别
/*
set session transaction isolation level 级别字符串
级别字符串:read uncommitted、read committed、repeatable read(默认)、serializable,隔离级别越来越强,性能越来越低
*/
-- 设置read uncommitted,会引起脏读,A事务会读取到B事务未提交的数据
set session transaction isolation level read uncommitted;
 
-- 设置read committed,会引起不可重复读,A事务提交前后B事务读取数据是不同的
set session transaction isolation level read committed;
 
-- 设置repeatable read,会引起幻读,A事务提交前后看到的数据不同,查询时没有对应行,去插入发现存在
set session transaction isolation level repeatable read;
 
-- 设置serializable,A事务提交后B事务才可执行操作
set session transaction isolation level serializable;

MySQL存储引擎

存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式 。存储引擎是基于表的,而不是
基于库的,所以存储引擎也可被称为表类型。

  • InnoDB是一种兼顾高可靠性和高性能的通用存储引擎。innoDB引擎每张表都对应一个表空间文件xxx.ibd。ibd2sdi指令可以从ibd文件中提取sdi信息。
    • DML操作遵循ACID模型,支持事务;
    • 行级锁,提高并发访问性能;
    • 支持外键FOREIGN KEY约束,保证数据的完整性和正确性;
  • MyISAM是MySQL早期的默认存储引擎。xxx.sdi:存储表结构信息。xxx.MYD: 存储数据,xxx.MYI: 存储索引
    • 不支持事务,不支持外键
    • 支持表锁,不支持行锁
    • 访问速度快
  • Memory引擎的表数据时存储在内存中的,由于受到硬件问题、或断电问题的影响,只能将这些表作为
    临时表或缓存使用。
    • 内存存放
    • hash索引(默认)
-- 查看MySQL所有执行引擎,默认innoDB
show engines

-- 创建新表时指定存储引擎:
create table(...) engine=INNODB ;
 
-- 修改数据库引擎
alter table student engine = INNODB;
alter table student engine = MyISAM;


存储引擎的选择:

  • InnoDB: 是Mysql的默认存储引擎,支持事务、外键。如果应用对事务的完整性有比较高的要
    求,在并发条件下要求数据的一致性,数据操作除了插入和查询之外,还包含很多的更新、删除操
    作,那么InnoDB存储引擎是比较合适的选择。
  • MyISAM : 如果应用是以读操作和插入操作为主,只有很少的更新和删除操作,并且对事务的完
    整性、并发性要求不是很高,那么选择这个存储引擎是非常合适的。——日志存储等,被NoSQL数据库MongoDB替代
  • MEMORY:将所有数据保存在内存中,访问速度快,通常用于临时表及缓存。MEMORY的缺陷就是
    对表的大小有限制,太大的表无法缓存在内存中,而且无法保障数据的安全性。——被NoSQL数据库Redis取代。

※索引

  • 定义:索引(index)是帮助MySQL高效获取数据的有序数据结构。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据, 这样可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。(通过某种算法,构建出一个数据模型,用于快速找出在某个列中有一特定值的行,提升查找速度。(无索引是要全表扫描))
  • 索引结构:按照实现方式:B+Tree索引(默认)和Hash索引
  • 索引特点:
    • 优势:
      1. 提高数据检索的效率,降低数据库的IO成本
      2. 通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗
    • 劣势:
      1. 索引列也是要占用空间
      2. 索引大大提高了查询效率,同时却也降低更新表的速度,如对表进行INSERT、UPDATE、DELETE时,效率降低
-- 创建索引(index_name一般规范为idx_表名_字段名)
CREATE [ UNIQUE | FULLTEXT ] INDEX index_name ON table_name (index_col_name,... ) ;
-- 查看索引
SHOW INDEX FROM table_name;
-- 删除索引
DROP INDEX index_name ON table_name;

--索引在使用时可以在SQL语句中加入一些人为的提示来达到优化操作的目的。在from 表名之后加入
-- use index : 建议MySQL使用哪一个索引完成此次查询(仅仅是建议,mysql内部还会再次进行评估)。
explain select * from tb_user use index(idx_user_pro) where profession = '软件工程';
-- ignore index : 忽略指定的索引
explain select * from tb_user ignore index(idx_user_pro) where profession = '软件工程';
-- force index : 强制使用索引
explain select * from tb_user force index(idx_user_pro) where profession = '软件工程';

索引分类

  • 单列索引

    • 普通索引
    -- 方式1-创建表的时候直接指定
    create  table student(
        sid int primary key,
        card_id varchar(20),
        name varchar(20),
        gender varchar(20),
        age int,
        birth date, 
        phone_num varchar(20),
        score double,
        index index_name(name) -- 给name列创建索引
    );
    
    -- 方式2-直接创建
    create index indexname on tablename(columnname); 
    
    -- 方式3-修改表结构(添加索引)
    alter table tablename add index indexname(columnname);
    
    -- 查看数据库所有索引 
    select * from mysql.`innodb_index_stats` a where a.`database_name` = '数据库名’; 
    -- 查看表中所有索引 
    select * from mysql.`innodb_index_stats` a where a.`database_name` = '数据库名' and a.table_name like '%表名%’; 
    -- 查看表中所有索引 
    show index from table_name; 
    
    -- 删除索引
    drop index 索引名 on 表名 
    -- 或 
    alter table 表名 drop index 索引名 
    
    
    • 唯一索引:值唯一但是允许有空值
    -- 方式1-创建表的时候直接指定
    create  table student2(
        sid int primary key,
        card_id varchar(20),
        name varchar(20),
        gender varchar(20),
        age int,
        birth date, 
        phone_num varchar(20),
        score double,
        unique index_card_id(card_id) -- 给card_id列创建索引
    );
    
    -- 方式2-直接创建
    create unique index 索引名 on 表名(列名) 
    
    -- 方式3-修改表结构(添加索引)
    alter table 表名 add unique [索引名] (列名)
    
    
    • 主键索引:唯一不能为空
  • 组合索引(联合索引)顺序:从左到右

    如果存在多个查询条件,考虑针对于查询字段建立索引时,建议建立联合索引,尽量减少回表查询。

    -- 创建索引的基本语法 
    create [unique] index indexname on table_name(column1(length),column2(length)); 
    
    
    
  • 全文索引:主要用来查找文本中的关键字

    -- 创建表的时候添加全文索引(不推荐)
    create table t_article (
         id int primary key auto_increment ,
         title varchar(255) ,
         content varchar(1000) ,
         writing_date date -- , 
         -- fulltext (content) -- 创建全文检索
    );
    -- 修改表结构添加全文索引
    alter table t_article add fulltext index_content(content)
     
    -- 直接添加全文索引
    create fulltext index index_content on t_article(content);
    
    -- 索引使用
    match (col1,col2,...)  against(expr [search_modifier])
    select * from t_article where match(content) against('you'); 
    -- 查看搜索参数
    show variables like '%ft%';
    
    
    
  • 空间索引

    create table shop_info (
      id  int  primary key auto_increment comment 'id',
      shop_name varchar(64) not null comment '门店名称',
      geom_point geometry not null comment '经纬度’,
      spatial key geom_index(geom_point)
    );
    
    
    
  • 前缀索引

    /*
    当字段类型为字符串(varchar,text,longtext等)时,有时候需要索引很长的字符串,这会让
    索引变得很大,查询时,浪费大量的磁盘IO, 影响查询效率。此时可以只将字符串的一部分前缀,建
    立索引,这样可以大大节约索引空间,从而提高索引效率。
    */
    create index idx_xxxx on table_name(column(n)) -- n为索引长度
    -- 索引长度可以根据索引的选择性来决定,而选择性是指不重复的索引值(基数)和数据表的记录总数的比值,索引选择性越高则查询效率越高, 唯一索引的选择性是1是最好的索引选择性,性能也是最好的。
    select count(distinct email) / count(*) from tb_user; --不重复值所占比例
    select count(distinct substring(email,1,5)) / count(*) from tb_user;
    
    

索引设计原则:

  • 针对于数据量较大,且查询比较频繁的表建立索引。
  • 针对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索引。
  • 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。
  • 如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引。
  • 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率。
  • 要控制索引的数量,索引越多,维护索引结构的代价也就越大,会影响增删改的效率。
  • 如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它。当优化器知道每列是否包含NULL值时,它可以更好地确定哪个索引最有效地用于查询。

索引使用的原则:

  • 最左前缀法则。如果索引了多列(联合索引),要遵守最左前缀法则。最左侧索引必须存在,不要跳过中间索引。
  • 联合索引中,出现范围查询(>,<),范围查询右侧的列索引失效。在业务允许的情况下,尽可能的使用类似于 >= 或 <= 这类的范围查询。
  • 不要在索引列上进行运算操作(字符串类型进行substr操作等), 索引将失效
  • 字符串类型字段使用时,不加引号,索引将失效
  • 如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效。规避前面加’%'的模糊匹配
  • 用or连接条件,前后列必须都有索引,索引才能真正生效
  • 尽量减少select *,直接查询使用的索引列

MySQL性能分析

  1. 首先通过以下命令查看SQL执行频率。查看当前数据库的INSERT、UPDATE、DELETE、SELECT的访问频次。如果是以增删改为主,我们可以考虑不对其进行索引的优化。 如果是以查询为主,那么就要考虑对数据库的索引进行优化。

    show [session|global] status
    -- session 是查看当前会话 ;
    -- global 是查询全局数据 ;
    SHOW GLOBAL STATUS LIKE 'Com_______';
    
    
  2. 慢查询日志。慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认10秒)的所有SQL语句的日志。

    -- MySQL的慢查询日志默认没有开启,查看是否开启
    show variables like 'slow_query_log'
    
    

    接下来需要在MySQL的配置文件(/etc/my.cnf)中配置如下信息

    slow_query_log=1 #开启慢查询日志开关

    long_query_time=2 #设置慢日志的时间为2秒,SQL语句执行时间超过2秒,就会视为慢查询,记录慢查询日志,记录位置/var/lib/mysql/localhost-slow.log

    最后,重启sql服务。systemctl restart mysqld

  3. profile详情。可以知道每条sql语句执行多长时间。

    -- 查看当前MySQL是否支持profile操作
    SELECT @@have_profiling;
    -- 查看开关是否开启(默认关闭为0)
    select @@profiling;
    -- 开启profiling
    SET [session|global] profiling = 1;
    
    -- 查看每一条SQL的耗时基本情况
    show profiles;
    -- 查看指定query_id的SQL语句各个阶段的耗时情况
    show profile for query query_id;
    -- 查看指定query_id的SQL语句CPU的使用情况
    show profile cpu for query query_id;
    
    
  4. explain执行计划。查看令 MySQL 如何执行 SELECT 语句的信息,包括在 SELECT 语句执行过程中表如何连接和连接的顺序。

    -- 直接在select语句之前加上关键字 explain / desc
    EXPLAIN SELECT 字段列表 FROM 表名 WHERE 条件;
    
    

    Explain执行计划各个字段的含义:

    字段 含义
    id select查询的序列号,表示查询中执行select子句或者是操作表的顺序(id相同,执行顺序从上到下;id不同,值越大,越先执行)
    select_type 表示 SELECT 的类型,常见的取值有 SIMPLE(简单表,即不使用表连接或者子查询)、PRIMARY(主查询,即外层的查询)、UNION(UNION 中的第二个或者后面的查询语句)、SUBQUERY(SELECT/WHERE之后包含了子查询)等
    type 表示连接类型,性能由好到差的连接类型为NULL、system、const(主键或唯一索引查询)、eq_ref、ref(非唯一索引查询)、range、 index、all
    possible_key 显示可能应用在这张表上的索引,一个或多个
    key 实际使用的索引,如果为NULL,则没有使用索引
    key_len 表示索引中使用的字节数, 该值为索引字段最大可能长度,并非实际使用长度,在不损失精确性的前提下, 长度越短越好
    rows MySQL认为必须要执行查询的行数,在innodb引擎的表中,是一个估计值,可能并不总是准确的。
    filtered 表示返回结果的行数占需读取行数的百分比, filtered 的值越大越好
    Extra 其他备注信息。Using where; Using Index说明查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据
MySQL优化
-- 一、性能分析
--下面的命令显示了当前 session 中所有统计参数的值
show session status like 'Com_______';  -- 查看当前会话统计结果
show global  status  like 'Com_______';  -- 查看自数据库上次启动至今统计结果
 
show status like 'Innodb_rows_%’;       -- 查看针对Innodb引擎的统计结果

-- 定位运行效率低的SQL
-- 1、查看慢日志配置信息 
show variables like '%slow_query_log%; 
-- 开启慢日志查询 
set global slow_query_log=1; 
-- 查看慢日志记录SQL的最低阈值时间 
show variables like 'long_query_time%’; 
-- 修改慢日志记录SQL的最低阈值时间 
set global long_query_time=4;

-- 2、线程执行状态信息,低效率定位
show processlist; 

-- explain分析执行计划  explain selct SQL语句
explain select * from user where uid = 1;
-- type结果值从好到坏:system->const->eq_ref->ref->range->index->ALL
-- eq_ref左表有主键列,且左表的每一行与右表每一行刚好匹配
-- ref左表是普通索引,且和右表匹配时可能匹配多行
-- range 范围查询
-- index 把索引列全部数据扫描 select 字段 from
-- ALL 把表中所有数据扫描 select * from

-- show profiles 能够在做SQL优化时帮助我们了解时间都耗费到哪里去了
select @@have_profiling; 
set profiling=1; -- 开启profiling 开关; 
-- 通过show  profile for  query  query_id 语句可以查看到该SQL执行过程中每个线程的状态和消耗的时间
show profiles [cpu] for query 20;

-- 二、SQL优化
-- ①插入数据
-- 批量插入
insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry');
-- 手动控制事务
start transaction;
insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry');
insert into tb_test values(4,'Tom'),(5,'Cat'),(6,'Jerry');
insert into tb_test values(7,'Tom'),(8,'Cat'),(9,'Jerry');
commit;
-- 主键顺序插入

-- 大批量插入数据时使用load命令,不再使用insert
---- 客户端连接服务端时,加上参数 -–local-infile
mysql –-local-infile -u root -p
-- 检查一个全局系统变量 'local_infile' 的状态, 如果得到如下显示 Value=OFF,则说明这是不可用的
show global variables like 'local_infile';
-- 修改local_infile值为on,开启local_infile
set global local_infile=1; 
-- 加载数据 
-- 关闭唯一性校验。在导入数据前执行 SET UNIQUE_CHECKS=0,关闭唯一性校验,在导入结束后执行SET UNIQUE_CHECKS=1,恢复唯一性校验,可以提高导入的效率。
SET UNIQUE_CHECKS=0;
--导入本地数据
load data local infile 'D:\\sql_data\\sql1.log' into table tb_user fields terminated by ',' lines terminated by '\n';
load data local infile '/root/sql1.log' into table tb_user fields terminated by ',' lines terminated by '\n' ;

-- 查询时使用索引,减少回表查询
--索引使用原则(防止索引失效)
--1、条件and连接从左到右生效,中间不能是非索引;or连接条件索引不会用到
--2、范围查询右边的列不能使用索引,不要在索引列进行运算
--3、索引列查询效率高,(不使用*)
--4、用%开头的进行模糊匹配,索引失效
--5、尽量使用复合索引
--6、多表查询优于子查询

-- update更新根据索引字段更新:InnoDB的行锁是针对索引加的锁,不是针对记录加的锁 ,并且该索引不能失效,否则会从行锁升级为表锁

MySQL视图

视图view是一个虚拟表,本质是根据SQL语句获取的动态数据集。数据库只记录了视图的定义。视图只保存了查询的SQL逻辑,不保存查询结果

视图的作用:

  • 简单。被经常使用的查询可以被定义为视图,从而使得用户不必为以后的操作每次指定全部的条件(简化多表联查操作)
  • 安全。通过视图用户只能查询和修改他们所能见到的数据
  • 数据独立。视图可帮助用户屏蔽真实表结构变化带来的影响
-- 视图创建
create [or replace]
view view_name
as
select * from

-- 查看表和视图
show full tables;
show create view view_name;

-- 视图使用
select * from view_name;

-- 视图插入数据,数据存进基表。定义视图时,如果指定了where条件,然后在插入、修改、删除数据时,可以做到必须满足条件才能操作
create [or replace]
view view_name
as
select * from where ... with local check option;

-- 修改视图
alter view view_name
as
select * from

-- 重命名视图
rename table view_name to new_name;

--删除视图
drop view [if exists] view_name;

/*
视图的更新
要使视图可更新,视图中的行与基础表中的行必须存在一对一的关系。如果视图包含以下任何一项,则该视图不可更新:
A. 聚合函数或窗口函数(SUM()、 MIN()、 MAX()、 COUNT()等)
B. DISTINCT
C. GROUP BY
D. HAVING
E. UNION 或者 UNION ALL
*/

MySQL存储过程

存储过程是事先经过编译并存储在数据库中的一段 SQL 语句的集合,就是数据库SQL语言层面代码的封装与重用。可以接受参数,也可以返回数据,减少网络交互提升效率。

-- 存储过程格式
delimiter 自定义结束符号($$ 或者 \\)
-- 创建存储过程
create procedure 存储名称 ([in,out,inout] 参数名 数据类型,参数名1 数据类型...)
begin
	-- 自定义局部变量
	declare 局部变量名 varchar(20) default 'abc';
	set 局部变量名 = 'cba'; -- 变量赋值   用户变量(在整个会话都能使用)set @变量 = 'cba';
	-- 用户变量(在整个会话都能使用)set @变量 = 'cba';
	-- 全局变量(系统默认)@@全局变量名   show global variables; -- 查看全局变量
	select 字段名 [into out_参数名] from tableName where...[字段1=in_参数名];
end 自定义结束符号
delimiter;

-- 存储过程调用
call 存储名称([参数])

-- 查看
-- 查询指定数据库的存储过程及状态信息
SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = '指定数据库名称'; 
-- 查询某个存储过程的定义语句
SHOW CREATE PROCEDURE 存储过程名称; 

-- 删除
DROP PROCEDURE [ IF EXISTS ] 存储过程名称;

############实例##################
-- 实例_1_in
delimiter $$

create procedure proc(in in_name_1 varchar(20),in in_name_2 int)
begin
	select concat_ws('_',deptno,ename) from emp where emp.ename=in_name_1 and emp.deptno=in_name_2;
end $$

delimiter;

set @in_name_1 = '关羽'; -- 定义用户变量
set @in_name_2 = 3000; -- 定义用户变量
call proc(@in_name_1,@in_name_2); -- 调用存储过程,必须传入参数

-- 实例_2_out
delimiter $$

create procedure proc(in in_name varchar(20),out out_name int)
begin
	select deptno into out_name from emp where emp.ename=in_name;
end $$

delimiter;

set @in_name = '关羽'; -- 定义用户变量
call proc(@in_name); -- 调用存储过程,必须传入参数
select @out_name

-- 实例_3_inout
delimiter $$

create procedure proc(inout inout_name_1 varchar(20),inout inout_name_2 int)
begin
	select concat_ws('_',deptno,ename) into inout_name_1 from emp where emp.ename=inout_name_1;
	set inout_name_2 = inout_name_2 * 12
end $$

delimiter;

set @inout_name_1 = '关羽'; -- 定义用户变量
set @inout_name_2 = 3000; -- 定义用户变量
call proc(@inout_name_1,@inout_name_2); -- 调用存储过程,必须传入参数
select @inout_name_1;
select @inout_name_2;

-- 实例4_流程判断if
delimiter $$
create procedure proc(in score int)
begin
	if score < 60
		then
			-- select '不及格';
			set result := '不及格'
	elseif score < 80
		then
			-- select '及格';
			set result := '及格'
	elseif score < 100
		then
			-- select '优秀';
			set result := '优秀'
	else
		-- select '成绩错误';
		set result := '成绩错误'
	end if;
	select result
end $$
delimiter ;

set @score = 85;
call proc(100);
call proc(@score);

-- 实例5_流程分支case
delimiter $$
create procedure proc(in pay_type int)
begin
	case pay_type
		when 1 then select '微信支付';
		when 2 then selct '支付宝支付';
		when 3 then select '银行卡支付';
	end case;
end $$
delimiter ;

call proc(2);

-- 实例6_流程循环while——向表中插入指定条数据
delimiter $$
create procedure proc(in insertCount int)
begin
	declare i int default 1;
	label:while i <= insertCount do
		insert into user(uid,username,password) values(i,concat('user-',i),'123456');
		if i =5 then
			leave label
		end if;
		set i = i + 1;
	end while label;
end $$
delimiter ;

call proc(10);

-- 实例7_loop_iterable跳出当前循环,循环插入数据,跳过一条
delimiter $$
create procedure proc(in insertCount int)
begin
	declare i int default 1;
	label:while i <= insertCount do
		set i = i + 1;
		if i =5 then
			iterate label
		end if;
		insert into user(uid,username,password) values(i,concat('user-',i),'123456');
	end while label;
	select '循环结束';
end $$
delimiter ;

call proc(10);

-- 计算1到n的偶数累加值
create procedure proc(in n int)
	begin
		declare total int default 0;
		sum:loop
			if n<=0 then
				leave sum;
			end if;
			if n%2 = 1 then
				set n := n - 1;
				iterate sum;
			end if;
			set total := total + n;
			set n := n - 1;
		end loop sum;
		
		select total;
end;

call proc(100)

-- 实例8_loop_leave跳出当前循环,循环插入数据
delimiter $$
create procedure proc(in insertCount int)
begin
	declare i int default 1;
	label:loop
		insert into user(uid,username,password) values(i,concat('user-',i),'123456');
		set i = i + 1;
		if i > insertCount then
			leave label;
		end if;
	end loop label;
	select '循环结束';
end $$
delimiter ;

call proc(10);

-- 实例9_repeate计算累加值,当满足until声明的条件的时候,则退出循环
create procedure proc(in n int)
begin
	declare total int default 0;
	
	repeat
		set total := total + n;
		set n := n - 1;
	until n <= 0
	end repeat;
select total;

-- cursor游标用来存储查询结果集的数据类型,Handler条件处理程序
-- 根据传入参数将查询结果插入到所建的一张新表
create procedure proc(in uage int)
	begin
		declare uname varchar(100);
		declare upro varchar(100);
		-- 声明游标
		declare u_cursor cursor for select name,profession from tb_user where age <=uage;
		-- 声明条件处理程序 : 当SQL语句执行抛出的状态码为02000时,将关闭游标u_cursor,并退出
		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(100),
            profession varchar(100)
        );
		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 proc(30);
##############################


-- 存储函数.存储函数是有返回值的存储过程,存储函数的参数只能是IN类型的
CREATE FUNCTION 存储函数名称 ([ 参数列表 ])
RETURNS type [characteristic ...]
BEGIN
	-- SQL语句
	RETURN ...;
END ;
/*
characteristic说明:
	1、DETERMINISTIC:相同的输入参数总是产生相同的结果
	2、NO SQL :不包含 SQL 语句。
	3、READS SQL DATA:包含读取数据的语句,但不包含写入数据的语句。
*/

变量

MySQL中变量分为:系统变量、用户定义变量、局部变量。

  • 系统变量:MySQL服务器提供,不是用户定义的。分为全局变量(GLOBAL)、会话变量(SESSION)

    -- 查看系统变量
    SHOW [ SESSION | GLOBAL ] VARIABLES ; -- 查看所有系统变量
    SHOW [ SESSION | GLOBAL ] VARIABLES LIKE '......'; -- 可以通过LIKE模糊匹配方式查找变量
    SELECT @@[SESSION | GLOBAL].系统变量名; -- 查看指定变量的值
    
    -- 设置系统变量
    SET [ SESSION | GLOBAL ] 系统变量名 =;
    SET @@[SESSION | GLOBAL].系统变量名 =;
    
    
  • 用户自定义变量:用户根据需要自己定义的变量,用户变量不用提前声明,使用时直接用 “@变量名” 就可以。作用范围为当前连接(会话)

    -- 变量赋值
    -- 方法一:
    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 ;
    
    
  • 局部变量:根据需要定义的在局部生效的变量,访问之前,需要DECLARE声明。范围是在其内声明的BEGIN… END块

    -- 声明变量。变量类型就是数据库字段类型:INT、BIGINT、CHAR、VARCHAR、DATE、TIME等
    DECLARE 变量名 变量类型 [DEFAULT ... ] ;
    
    -- 变量赋值
    SET 变量名 = 值 ;
    SET 变量名 := 值 ;
    SELECT 字段名 INTO 变量名 FROM 表名 ... ;
    
    

触发器

在MySQL,只有执行insert、delete、update操作时才能触发触发器的执行,是一种特殊的存储过程,无需手动调用。协助应用在数据库端确保数据的完整性, 日志记录 , 数据校验等操作。

--查看触发器
show triggers;

drop trigger if exists 触发器名;
-- 格式
delimiter $$
create trigger 触发器名 before|after  触发事件 [insert|delete|update]
on 表名 for each row -- 行级触发器
begin
     执行语句列表   (NEW.字段名 OLD.字段名 获取执行(前、后)表的数据)
end;
delimiter ;

-- 案例
-- 1、插入数据
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, ', phone=', NEW.phone, ', email=', NEW.email, ',
profession=', NEW.profession));
end;
-- 更新数据
create trigger tb_user_update_trigger
	after update on tb_user for each row
begin
	insert into user_logs(id, operation, operate_time, operate_id, operate_params)
VALUES
	(null, 'update', now(), new.id,concat('更新之前的数据: id=',old.id,',name=',old.name, ', phone=',old.phone, ', email=', old.email, ', profession=', old.profession,
' | 更新之后的数据: id=',new.id,',name=',new.name, ', phone=',
NEW.phone, ', email=', NEW.email, ', profession=', NEW.profession));
end;
-- 删除数据
create trigger tb_user_delete_trigger
	after delete on tb_user for each row
begin
	insert into user_logs(id, operation, operate_time, operate_id, operate_params)
VALUES
	(null, 'delete', now(), old.id,concat('删除之前的数据: id=',old.id,',name=',old.name, ', phone=',old.phone, ', email=', old.email, ', profession=', old.profession));
end;

锁机制

保证数据并发访问的一致性。

-- 加读锁,只能自己只读,其他都不能读和修改
lock table table_name read; 
-- 加写锁
lock table table_name write
-- 解除锁
unlock tables;

-- 全局锁
/*
全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的DML的写语句,DDL语句都将被阻塞。其典型的使用场景是做全库的逻辑备份
*/
-- 加全局锁
flush tables with read lock ;
-- 数据备份
mysqldump [--single-transaction] -uroot –p1234 itcast > itcast.sql --dos命令行中执行
-- 释放锁
unlock tables;
-- 行锁
共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE 
排他锁(X) :SELECT * FROM table_name WHERE ... FOR UPDATE


日志
-- 查看错误日志文件位置
show variables like 'log_error%';

-- 二进制日志(BINLOG)记录了所有的 DDL(数据定义语言)语句和 DML(数据操纵语言)语句,对于灾难时的数据恢复起着极其重要的作用
-- 查看MySQL是否开启了binlog日志
show variables like 'log_bin';
-- 查看binlog日志的格式
show variables like 'binlog_format';
-- 查看所有日志
show binlog events; 
-- 查看最新的日志
show master status;】 
-- 查询指定的binlog日志
show binlog events in 'binlog.000010';
-- 从指定的位置开始,查看指定的Binlog日志
show binlog events in 'binlog.000010' from 156;
-- 从指定的位置开始,查看指定的Binlog日志,限制查询的条数
show binlog events in 'binlog.000010' from 156 limit 2;
--从指定的位置开始,带有偏移,查看指定的Binlog日志,限制查询的条数
show binlog events in 'binlog.000010' from 666 limit 1, 2;
-- 清空所有的 binlog 日志文件
reset master

#配置开启binlog日志,进入my.ini文件
log_bin=mysqlbin

#配置二进制日志的格式
binlog_format=STATEMENT; 或row,mixed

-- 查看MySQL是否开启了查询日志
show variables like 'general_log';
-- 开启查询日志
set global  general_log=1;


JDBC操作

JDBC是Java访问数据库的标准规范,可以为不同的关系型数据库提供统一访问,它由一组用Java语言编写的接口和类组成。

public class JdbcDemo1 {
    public static void main(String[] args) throws Exception {
        // 注意:使用JDBC规范,采用都是 java.sql包下的内容
        //1 注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        //2 获得连接
        String url = "jdbc:mysql://localhost:3306/mydb16_jdbc";
        Connection conn = DriverManager.getConnection(url, "root", "123456");
        //3获得执行sql语句的对象
        Statement stmt = conn.createStatement();
        //4执行SQL语句
        ResultSet rs = stmt.executeQuery("select * from student");
         
        //5处理结果集
        while(rs.next()){
            // 获得一行数据
            Integer cid = rs.getInt("sid");
            String cname = rs.getString("sname");
            Integer age = rs.getInt("age");
            System.out.println(cid + " , " + cname);
        }
        //6释放资源
        rs.close();
        stmt.close();
        conn.close();
 
 
    }


pymysql操作
import pymysql
 
#获取MySQL连接
conn = pymysql.connect(host='localhost', port=3306, user='root',password='123456',database='mydb17_pymysql', charset='utf8')
# 获取游标
cursor = conn.cursor()
 
sql = "select * from student;"
 
row_count = cursor.execute(sql)
print("SQL语句执行影响的行数%d" % row_count)
 
# 取出结果集中一行  返回的结果是一行
# print(cursor.fetchone())
 
# 取出结果集中的所有数据  返回一行数据
for line in cursor.fetchall():
    print(line)
# 关闭游标
cursor.close()
# 关闭连接
conn.close()

######插入数据
import pymysql
 
#获取MySQL连接
conn = pymysql.connect(host='localhost', port=3306, user='root',password='123456',database='mydb17_pymysql', charset='utf8')
# 获取游标
cursor = conn.cursor()
 
 
##########插入数据
# sql = "insert into student values(%s,%s,%s)"
# data = (4, '晁盖', 34)
# cursor.execute(sql, data)  
data = [(1,'宋江',32),(2,'吴用',30)]
cursor.executemany(sql,data)  #一次性插入多行
 
# 修改数据
# sql = "update student set sname=%s where sid=%s"
# data = ('李逵', 4)
# cursor.execute(sql, data)

 
############ 删除数据
sql = "delete from student where sid=%s"
data = (4)
cursor.execute(sql, data)
 
 
conn.commit()   # 提交,不然无法保存插入或者修改的数据
# 关闭游标
cursor.close()
# 关闭连接
conn.close()


你可能感兴趣的:(Study,数据库,mysql,sql)