MySQL概述(3306端口)

什么是数据库

数据库类型

数据库管理系统

什么是SQL

数据库表的概述


nameagegender
张三20
李四22

MySQL数据类型

MySQL 的数据类型可以分为整数类型、浮点数类型、定点数类型、日期和时间类型、字符串类型、二进制类型等。

整数类型

浮点数类型

定点数类型

日期和时间类型

字符串类型

二进制类型

BLOB类型:二进制大对象,可以存储图片、声音、视频等文件。

MySQL命令行基本命令

在MySQL当中,如何统计一个SQL语句的执行时长?

DDT(Data Definition Language数据定义语言)

普通操作:

/*
DOS中登录数据库
mysql -uroot -p
DOS中查看MySQL版本信息
mysql --version
*/

#数据库中查看MySQL版本
select version();
#退出MySQL
1. exit
2. quit
#终止错误的SQL语句
1.\c
2.ctrl+c
#注意:
#SQL语句可以单行或多行书写,注意以分号结尾。
#单行注释在前面加-- 或者#
#多行注释用/**/

工作后的操作:

#先将要执行的SQL指令全部写入.sql脚本文件中
#再通过source命令执行该脚本文件
source 脚本文件的位置(一般直接拖拽入DOS命令窗口)
#相较于MySQL客户端工具优点:可执行内存大的脚本文件

操作数据库:

#查看当前数据库管理系统有哪些数据库
show databases;
#创建一个数据库
create database [if not exists] 数据库名 [character set字符集] [collate 排序规则];
#删除一个数据库
drop database [if exists] 数据库名;
#查询当前处于哪一个数据库里面
select database();
#切换数据库
use 数据库名;
#修改数据库的字符集和排序规则:
alter database 数据库名 [character set字符集] [collate 排序规则];

#注意数据库一般没有改名方法

操作表:

#查看当前数据库有哪些表
show tables [from 数据库名];
#创建一张表:多个约束用空格隔开
create table [if not exists] 表名(
字段名1 数据类型 [列级约束] [comment'注释内容'],
字段名2 数据类型 [列级约束] [comment'注释内容'],
......
字段名3 数据类型 [列级约束] [comment'注释内容'],
表级约束(没有时前面这个逗号不写)
) [约束] [comment'注释内容'];
#删除一张表:
drop table [if exists] 表名;
#查看表的结构:
desc 表名;=========describe 表名;
#查看表的建表语句:
show create table 表名;
#修改表名:
alter table 表名 rename to 新表名;

操作字段:

#添加表的字段:
alter table 表名 add 字段名 数据类型 [约束] [comment '注释内容'];
#删除表的字段:
alter table 表名 drop 字段名;
#修改某个字段的数据类型:
alter table 表名 modify 字段名 新数据类型;
#修改某个字段的字段名:
alter table 表名 change 旧字段名 新字段名 数据类型 [comment ‘注释内容’];

#注意modify只能修改数据类型,不能修改字段名;而change都可以修改,且change后面必须跟新字段名和数据类型两者,少一个都不行

DMT(Data Manipulation Language数据操作语言)

#给指定的字段添加数据:
insert into 表名 (字段名1,字段名2,字段名3,……,字段名n) values (字段1的值1,字段2的值1,字段三的值1,……,字段n的值1),(字段1的值2,字段2的值2,字段三的值2,……,字段n的值2),……,(字段1的值n,字段2的值n,字段三的值n,……,字段n的值n);
#注意:表名后面的小括号当中的字段名如果省略掉,表示自动将所有字段都列出来了,并且字段的顺序和建表时的顺序一致。

#删除符合条件的一行数据记录:
delete from 表名 [where 条件];
#注意:不带条件则默认删除整张表的数据;delete无法删除某一字段的值,应该采用update 置null来操作。以上的删除属于DML的方式删除,这种删除的数据是可以通过事务回滚的方式重新恢复的,但是删除的效率较低。(这种删除是支持事务的。)

#注意:另外还有一种删除表中数据的方式,但是这种方式不支持事务,不可以回滚,删了之后数据是永远也找不回来了。这种删除叫做:表被截断。这个语句删除效率非常高,巨大的表,瞬间干掉所有数据,但不可恢复。该删除如下:
#清空一张表:
truncate table 表名;

#修改符合条件的数据:
update 表名 set 字段名1=新值,字段名2=新值,……,字段n=新值 [where 条件];
#注意:不带条件则默认修改整张表的数据。

DQT(Date Query Language数据查询语言)

基本查询语句

#查询整张表的数据:以后java中编写SQL语句不建议这样写,效率低,可读性差
select * from 表名;
#查询制定字段的数据:查询时可以做计算
select 字段名1 [as '别名'],字段名2 [as '别名'],…… from 表名;
#注意:as可以省略,将别名紧跟原名空格写出也是可以的;而如果别名中没有空格或没有中文的话,可以去掉引号

#字段的去重查询:distinct只能出现在所有字段的最前面,当distinct出现后,后面多个字段一定是联合去重的
select distinct 字段列表 from 表名;

条件查询语句

条件说明
=等于
<>或!=不等于
>=大于等于
<=小于等于
>大于
<小于
between...and...等同于 >= and <=,在使用时一定是左小右大
is null为空
is not null不为空
<=>安全等于(可读性差,很少使用了)。
and 或 &&并且
or 或 ||或者
in()在指定的值当中,等同于采用=和or连接
not in()不在指定的值当中,等同于采用<>和and连接
like模糊查询

and和or同时出现时,and优先级较高,会先执行,如果希望or先执行,这个时候需要给or条件添加小括号。另外,以后遇到不确定的优先级时,可以通过添加小括号的方式来解决。

==判断某个数据是否为null,不能使用等号,只能使用 is null== ==判断某个数据是否不为null,不能使用不等号,只能使用 is not null== 在数据库中null不是一个值,不能用等号和不等号衡量,null代表什么也没有,没有数据,没有值

in后面有一个小括号,小括号当中有多个值,值和值之间采用逗号隔开;not in同理 ==in是自动忽略NULL的。==因为等同于=和or连接,而有NULL表明=NULL一定为false,再通过or连接会忽略NULL,只进行其他条件判断 ==not in是不会自动忽略NULL的。==因为等同于<>和and连接,而有NULL表明<>NULL一定为false,再通过and连接表明结果一定为false,查不到任何结果

==如果in和or所在列有索引或者主键的话,or和in没啥差别;如果in和or所在列没有索引的话,in的效率越高==

==在模糊查询中,通配符主要包括两个:一个是%,一个是下划线_。其中%代表任意多个字符。下划线_代表任意一个字符。==想让这个下划线变成一个普通的下划线字符,就要使用转义字符了,在mysql当中转义字符是“\”,这个和java语言中的转义字符是一样的。

#查询符合条件的数据:
select 字段列表 from 表名 where 过滤条件;
#    第一步:先执行from
#    第二步:再通过where条件过滤
#    第三步:最后执行select,查询并将结果展示到控制台

排序查询语句

#排序方法有:ASC(升序=>默认值);DESC(降序)
#如果是多字段排序,当第一个字段值相同时,才会根据第二个字段进行排序 ;
select 字段列表 from 表名 order by 字段名1 排序方法,字段名2 排序方法;

分组查询语句

常用聚合函数:

#统计个数:count(字段名)
#求该字段中的最大值:max(字段名)
#求该字段中的最小值:min(字段名)
#求该字段中的平均值:avg(字段名)
#求该字段的和:sum(字段名)

#注意:聚合函数是作用于字段的,也就是表中的一列数据,注意null不参与聚合函数的计算,即所有的聚合函数都是自动忽略NULL的。

select count(distinct job) from emp;#统计岗位数量
select count(ename) from emp;#统计的是这个ename字段中不为NULL个数总和。
#count(*)和count(1)的效果一样,统计该组中总记录行数。
select count(*) from emp;
select count(1) from emp;
select 字段列表 from 表名 [where 过滤条件] group by 分组字段名 [having 分组后的过滤条件]
#注意:当select语句中有group by的话,select后面只能跟聚合函数或参加分组的字段
#where和having的区别:
#1、执行时机不同:where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组之后对结果进行过滤
#2、判断条件不同:where不能对聚合函数进行判断,而having可以
#使用原则:尽量在where中过滤,实在不行,再使用having。越早过滤效率越高。

分页查询语句

select 字段列表 from 表名 limit 起始索引,查询记录数;
#计算:先有要查询的页码和每页要显示几条记录,则起始索引=(查询页码-1)*每页显示记录数,注意起始索引从0开始
#如果下标是从0开始,可以省略起始索引,简写为:
select 字段列表 from 表名 limit 查询记录数;

总结

#编写顺序:
select 字段列表 from 表名 where 条件 group by 要分组的字段 having 条件 order by 排序字段及规律 limit 分页参数;
#执行顺序:
From 	>	where	>	group by	>	having	>	select	>	order by	>	limit 

连接查询

连接查询:从两张或更多张表中联合查询数据称为多表查询,又叫做连接查询。一般过滤条件要用到多张表的数据,注意与union和union all的区别。

内连接:满足条件的记录查询出来。也就是两张表的交集。

#内连接:
#包括:
#1、等值连接:连接时,条件为等量关系。
#2、非等值连接:连接时,条件是非等量关系。
#3、自链接:连接时,一张表看做两张表,自己和自己进行连接。
select 字段列表 from 主表名 主表别名 [inner] join 副表名 副表别名 on 过滤条件;

外连接:是除了满足条件的记录查询出来,再将其中一张表的记录全部查询出来,另一张表如果没有与之匹配的记录,自动模拟出NULL与其匹配。

左外连接:

右外连接:

#左外连接:
select 字段列表 from 主表名 主表别名 left [outer] join 副表名 副表别名 on 过滤条件;
#右外连接:
select 字段列表 from 主表名 主表别名 right [outer] join 副表名 副表别名 on 过滤条件;

全连接:两张表数据全部查询出来,没有匹配的记录,各自为对方模拟出NULL进行匹配。

==MySQL不支持full join。oracle数据库支持。==

select 字段列表 from 主表名 主表别名 full join  副表名 副表别名 on 过滤条件;

union和union all查询

不管是union还是union all都可以将两个查询结果集进行合并。过滤条件一般各用各的数据,不同于连接查询的过滤条件一般要互相利用。

#如:
select name,salary from firsttable where job='MANAGER'
union all
select name,salary from firsttable where job='SALESMAN';

子查询

子查询:select语句中嵌套select语句就叫做子查询。

select语句可以嵌套在哪里?===>where后面、from后面、select后面都是可以的。

技巧:将里面的select看作一张临时表,通过小括号括起来使用


exists、not exists

在 MySQL 数据库中,EXISTS(存在)用于检查子查询的查询结果行数是否大于0。如果子查询的查询结果行数大于0,则 EXISTS 条件为真。(即存在查询结果则是true。)

NOT EXISTS 用于检查一个子查询是否返回任何行,如果没有行返回,那么 NOT EXISTS 将返回 true。

#如:t_customer表示顾客表,t_order表示订单表
select * from t_customer c where exists(select * from t_order o where o.customer_id=c.customer_id);

IN 和 EXISTS 都是用于关系型数据库查询的操作符。不同之处在于:

  1. IN 操作符是根据指定列表中的值来判断是否满足条件,而 EXISTS 操作符则是根据子查询的结果是否有返回记录集来判断。
  2. EXISTS 操作符通常比 IN 操作符更快,尤其是在子查询返回记录数很大的情况下。因为 EXISTS 只需要判断是否存在符合条件的记录,而 IN 操作符需要比对整个列表,因此执行效率相对较低。
  3. IN 操作符可同时匹配多个值,而 EXISTS 只能匹配一组条件。

DCT(Date Control Language数据控制语言)

对用户的操作

#查询用户数:select * from mysql.user;

#创建用户:create user '用户名'@'主机名' identified by '密码';
#删除用户:drop user '用户名'@'主机名';

#修改用户密码:alter user '用户名'@'主机名' identified with mysql_native_password by '新密码';
#MySQL8版本以后:alter user '用户名'@'主机名' identified by '密码';

#修改用户名:rename user '原始用户名'@'主机名' to '新用户名'@'主机名';

#注意:当前主机名:localhost 所有主机名:%
#删除用户后、修改密码后、修改用户名后,都需要刷新权限才能生效:flush privileges

对权限的操作

#查询某人的权限:show grants for '用户名'@'主机名';
#授予某人权限:grant 权限1,权限2...,权限n on 数据库名.表名 to '用户名'@'主机名';
#撤销某人权限:revoke 权限1,权限2...,权限n on 数据库名.表名 from '用户名'@'主机名';
#注意:撤销权限时 “数据库名.表名” 不能随便写,要求和授权语句时的 “数据库名.表名” 一致。

#所有权限:all privileges;库名可以使用 * ,它代表所有数据库;表名可以采用 * ,它代表所有表
#其他权限:select、insert、delete、update、alter、create、drop、index(索引)、usage(登录权限)......
#授权和撤权后必须刷新权限,才能生效:flush privileges

# with grant option的作用是:java2用户也可以给其他用户授权了。
grant select,insert,delete,update on *.* to 'java2'@'%' with grant option;

数据备份

导出数据

注意:请在登录mysql数据库之前进行

# 导出powernode这个数据库中所有的表
mysqldump powernode > e:/powernode.sql -uroot -p1234 --default-character-set=utf8

# 导出powernode中emp表的数据
mysqldump powernode emp > e:/powernode.sql -uroot -p1234 --default-character-set=utf8

导入数据

第一种方式:(请在登录mysql之前进行)

# 现在登录mysql状态下新建一个数据库
create database powernode;
# 在登录mysql之前执行以下命令
mysql powernode < e:/powernode.sql -uroot -p1234 --default-character-set=utf8

第二种方式:(请在登录mysql之后操作)

create  database powernode;
use powernode;
source d:/powernode.sql

函数

函数的执行方法:select+空格+函数;

如:select now();

字符串函数

#拼接字符串:concat(s1,s2,s3,……)
#注意:在mysql8之前,双竖线||也是可以完成字符串拼接的。但在mysql8之后,||只作为逻辑运算符,不能再进行字符串拼接了。mysql中可以使用+进行字符串的拼接吗?不可以,在mysql中+只作加法运算,在进行加法运算时,会将加号两边的数据尽最大的努力转换成数字再求和,如果无法转换成数字,最终运算结果通通是0

#将str字符串转成小写:lower(str)或lcase(str)
#将str字符串转成大写写:upper(str)或ucase(str)

#用pad字符串对str字符串的左侧进行填充,达到n个字符串长度:lpad(str,n,pad)
#用pad字符串对str字符串的右侧进行填充,达到n个字符串长度:rpad(str,n,pad)

#去掉str字符串头部和尾部空格:trim(str)
#也可以去除指定前缀:如去除前缀0:select trim(leading '0' from '000111000');
#也可以去除指定后缀:如去除后缀0:select trim(trailing '0' from '000111000');
#去除指定前后缀:如去除前后缀0:select trim(both '0' from '000111000');

#返回字符串的长度:length(str),注意一个汉字两个长度
#返回字符串中字符的个数:char_length(str)

#返回str字符串从start位置起的len个长度的字符串:substring(str,start,len),当len缺少时,默认截取到字符串尾,注意字符串的起始下标从1开始,不是0

数值函数

#向上取整:ceil(x);					
#向下取整:floor(x);
#取绝对值:abs(x);
#返回x/y的模:mod(x,y);

#返回0~1的随机数浮点数:rand();
#返回一个0~1的固定的浮点数:rand(x);====>即每次使用相同的x得到的值都是相等的

#对x四舍五入取整:round(x);
#对x保留y位小数,符合四舍五入规则:round(x,y);
#对x的小数位截断,留下y位小数:truncate(x,y);

空处理函数

#在SQL语句中,凡是有NULL参与的数学运算,最终的计算结果都是NULL:
#当x为NULL时,将x当做y处理:ifnull(x, y);
#表示如果员工的津贴是NULL时当做0处理:ifnull(comm, 0);

日期和时间函数

#当前日期:curdate();
#当前时间:curtime();
#当前日期和时间:now()或sysdate()
#区别:
#now():获取的是执行select语句的时刻。
#sysdate():获取的是执行sysdate()函数的时刻。

#查询指定date是一周中的第几天,注意周日是第一天:dayofweek(date);
#查询指定date是一月中的第几天:dayofmonth(date);
#查询指定date是一年中的第几天:dayofyear(date);

#获取指定date的年:year(date);
#获取指定date的月:month(date);
#获取指定date的日:day(date);
#获取指定datetime的时:hour(datetime);
#获取指定datetime的分:minute(datetime);
#获取指定datetime的秒:second(datetime);
#获取指定date的年月日:date(date);
#获取指定datetime的时分秒:time(datetime);

#获取指定date所在月的最后一天的日期:last_day(date);

#在datetime的基础上加上exper个typer类型的时间:date_add(datetime,interval expr typer);
#datetime:一个日期类型的数据
#interval:关键字,翻译为“间隔”,固定写法
#expr:指定具体的间隔量,一般是一个数字。也可以为负数,如果为负数,效果和date_sub函数相同
#type:值year表年;值month表月;值day表日;值hour表时;值minute表分;值second表秒;值microsecond表微秒(1秒等于1000毫秒,1毫秒等于1000微秒);值week表周;值quarter表季度
#注意:type还有复合型单位,此时注意expr和type的写法

#将datetime日期格式化为某种形式:date_format(datetime,'日期格式');
#形式:%Y:四位年份		%y:两位年份		%m:月份(1..12)	%d:日(1..30)					  %H:小时(0..23)	%i:分(0..59)  %s:秒(0..59)
#如:select date_format(now(),'%Y-%m-%d %H:%i:%s');等同于select now();

#将某种形式日期转换成datetime日期格式:str_to_date('日期格式','对应位置')
#如:select str_to_date('10/01/1998','%m/%d/%Y');等同于select date('1998-10-1');
#注意:1998-10-01;	98-10-01;	1998/10/01;	98/10/01,这四种输入格式能被MySQL直接识别自动转为date类型

#计算天数差,时分秒不算:datediff(date1,date2);
#计算时间差,时分秒也计算:timediff(datetime1,datetime2);

流程函数

#Value为true返回t,否则返回f:if(value,t,f);
#Case when 条件 then 结果 when 条件 then 结果 …… else 结果 end;

类型转换函数

#cast函数用于将值从一种数据类型转换为表达式中指定的另一种数据类型:cast(值 as 数据类型)
#在使用cast函数时,可用的数据类型包括:
#	date:日期类型
#	time:时间类型
#	datetime:日期时间类型
#	signed:有符号的int类型(有符号指的是正数负数)
#	char:定长字符串类型
#	decimal:浮点型
#如:cast('2020-10-11' as date);表示将字符串'2020-10-11'转换成日期date类型。

约束

约束(constraint)通常包括:

所有的约束都存储在一个系统表当中:table_constraints。这个系统表在这个数据库当中:information_schema

列级约束:在字段后面添加的约束

表级约束:一般在字段全部写完后,进行统一添加

下属三种约束添加方法

#建表时添加:具体见上述建表语句。一般采用列级约束

#对已有表字段约束的修改(添加和删除):
alter table 表名 modify 字段名 类型名 约束;#该语句还可以修改数据类型
#注意使用这条语句后,所得到的结果是该字段只会存在该语句列出的约束
#即:原来存在的约束,但该语句未列出,则删除该约束
#原来不存在的约束,但该语句列出,则添加该约束

非空约束

非空约束(not null):限制该字段的数据不能为null

自增约束

自增约束(auto_increment):实现数据的自动增长,由数据库维护

默认约束

默认约束(default 默认值):保存数据时,如果未指定该字段的值,则采用默认值

检查约束

检查约束(check(条件)):保证字段值满足某一个条件

#建表时添加:具体见上述建表语句,一般使用列级约束

#对已有表字段添加约束:alter table 表名 add constraint 约束名 check(条件表达式);
#对已有表字段删除约束:alter table 表名 drop constraint 约束名;

唯一约束

唯一约束(unique):保证该字段的所有数据都是唯一、不重复的。唯一性的字段值是可以为NULL的。但不能重复。

#建表时添加:具体见上述建表语句,列级约束和表级约束都可以使用

#对已有表字段添加约束:alter table 表名 add constraint 约束名 unique(字段名);
#对已有表字段删除约束:alter table 表名 drop constraint 约束名;

主键约束

主键约束(primary key):

  1. 主键约束的字段不能为NULL,并且不能重复。即非空且唯一
  2. 该约束常与自增约束写一起
  3. 主键是一行数据的唯一标识,任何一张表都应该有主键,没有主键的表可以视为无效表。
  4. 主键值是这行记录的身份证号,是唯一标识。在数据库表中即使两条数据一模一样,但由于主键值不同,我们也会认为是两条完全的不同的数据。
  5. 主键分类:
    1. 根据字段数量分类:
      1. 单一主键(1个字段作为主键)==>建议的
      2. 复合主键(2个或2个以上的字段作为主键)
    2. 根据业务分类:
      1. 自然主键(主键和任何业务都无关,只是一个单纯的自然数据)===>建议的
      2. 业务主键(主键和业务挂钩,例如:银行卡账号作为主键)
  6. 单一主键:建议使用列级约束
  7. 复合主键:建议使用表级约束,不过该类型很少见
#建表时添加:具体见上述建表语句

#对已有表字段添加约束:alter table 表名 add primary key(字段名);
#对已有表字段删除约束:alter table 表名 drop primary key;

外键约束

外键约束(foreign key):用来让两张表的数据之间建立连接,保证数据的一致性和完整性

1、添加了外键约束的字段中的数据必须来自其他字段,不能随便填。

2、假设给a字段添加了外键约束,要求a字段中的数据必须来自b字段,b字段不一定是主键,但至少要有唯一性。

3、外键约束可以给单个字段添加,叫做单一外键。也可以给多个字段联合添加,叫做复合外键。复合外键很少用。

4、a表如果引用b表中的数据,可以把b表叫做父表,把a表叫做子表。

#建表时添加:具体见上述建表语句

#对已有表字段添加约束:alter table 表名 add [constraint 外键名] foreign key(字段名) references 主表名(主表字段名) [on update 更新行为] [on delete 删除行为];
#对已有表字段删除约束:alter table 表名 drop foreign key 外键名;

#更新删除行为:
#1、no action:当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除/更新。(与restrict一致)默认行为
#2、restrict:当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除/更新。(与no action一致)默认行为=====>推荐用于删除行为
#3、cascade:当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有,则也删除/更新外键在子表中的记录======>推荐用于更新行为
#4、set null:当在父表中删除对应记录时,首先检查该记录是否有对应外键,如果有则设置子表中该外键值为null(这就要求该外键允许取null)
#5、set default:父表有变更时,子表将外键列设置成一个默认的值(Innodb不支持)

数据表设计三范式

数据表三范式指:数据库表设计的原则。教你怎么设计数据库表有效,并且节省空间。

第一范式:任何一张表都应该有主键,每个字段是原子性的不能再分

第二范式:建立在第一范式基础上的,另外要求所有非主键字段完全依赖主键,不能产生部分依赖;其实就是只能有一个主键

第三范式:建立在第二范式基础上的,非主键字段不能传递依赖于主键字段

三范式解释

第一范式:任何一张表都应该有主键,每个字段是原子性的不能再分

第二范式:建立在第一范式基础上的,另外要求所有非主键字段完全依赖主键,不能产生部分依赖;其实就是只能有一个主键

第三范式:建立在第二范式基础上的,非主键字段不能传递依赖于主键字段

数据表设计

一对多怎么设计

口诀:一对多两张表,多的表加外键。

多对多怎么设计

多对多三张表,关系表添加外键。

一对一怎么设计

两种方案:

  1. 第一种:主键共享

  1. 第二种:外键唯一

最终的设计原则

最终以满足客户需求为原则,有的时候会拿空间换速度。

视图

视图(view)其实是当DQL语句太长时,不便于多次书写,所以可以将该DQL语句变为视图,需要使用时直接调用该视图即可。视图的本质其实是一张DQL语句生成的临时表

#创建视图:
create [or replace] view 视图名 as DQL语句;

#删除视图
drop view [if exists] 视图名;

事务

事务是一个最小的工作单元。一个业务的完成(银行转账)可能需要多条DML语句共同配合才能完成。在数据库当中,事务表示一件完整的事儿,其出现是为了保证在多条DML语句执行时同时成功或同时失败。

注意:事务只针对DML语句有效:因为只有这三个语句是改变表中数据的。

四大特性(ACID)

  1. 原子性(Atomicity):是指事务包含的所有操作要么全部成功,要么同时失败。
  2. 一致性(Consistency):是指事务开始前,和事务完成后,数据应该是一致的。例如张三和李四的钱加起来是5000,中间不管进行过多少次的转账操作(update),总量5000是不会变的。这就是事务的一致性。
  3. 隔离性(Isolation):隔离性是当多个⽤户并发访问数据库时,⽐如操作同⼀张表时,数据库为每⼀个⽤户开启的事务,不能被其他事务的操作所⼲扰,多个并发事务之间要相互隔离。
  4. 持久性(Durability):持久性是指⼀个事务⼀旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

重要指令

#MySQL默认情况下采用的事务机制是:自动提交。所谓自动提交就是只要执行一条DML语句则提交一次。
#在dos命令窗口中关闭自动提交,并开启手动提交MySQL事务:start transaction或者begin;
#回滚事务:rollback; 
#提交事务:commit;
#只要执行以上的rollback或者commit,事务都会结束。

事务隔离级别

#mysql默认的隔离级别:可重复读(REPEATABLE READ)。

#设置事务隔离级别:
#会话级(只对当前会话起作用):set session transaction isolation level 隔离级别英文;
#全局级(对所有会话起作用):set global transaction isolation level 隔离级别英文;
#每打开一次DOS命令窗口就是一次会话

#查看当前会话的隔离级别:select @@transaction_isolation;
#查看全局的隔离级别:select @@gobal.transaction_isolation;

读未提交(read uncommitted)

读提交(read committed)

可重复读(repeatable read)

串行化(serializable)

可重复读的细节

在上面讲解过程中我提到,MySQL默认的隔离级别可重复读,在很大程度上避免了幻读问题(并不能完全解决),那么它是如何解决幻读问题的呢,解决方案包括两种:

存储过程