## 一、SQL语句分类
### DQL:数据查询语句(Data Query Language)
select
### DML:数据操作语言(Data Manipulation Language)
对表中的数据进行增删改
insert delete update
主要操作的是表中的数据
### DDL:数据定义语言(Data Definition Language)
create、drop、alter
DDL主要操作的表的结构,不是表中的数据。
### TCL:事务控制语言(Transactional Control Language)
事务提交:commit
事务回滚:rollback
### DCL:数据控制语言(Data Control Language)
授权:grant
撤销:revoke
## 二、常用命令
### 1.查看MySQL版本:
```mysql
mysql -V
mysql --version
select version();
```
### 2.创建数据库
```mysql;
create database <数据库名称>;
使用:use <数据库名>;
```
### 3.查看当前使用的数据库
```mysqk
select database();
```
### 4.终止一条语句
键入\c
### 5.退出mysql
exit、quit
## 三、查看表结构
### 1.查看现有的数据库
```mysql
show databases;
```
### 2.查看当前缺省的数据库
```mysql
use <database name>;
```
### 3.查看当前使用的数据库
```mysql
select database();
```
### 4.查看当前库中的表
```mysql
show tables;
```
### 5.查看其他库中的表
```mysql
show tables from <database name>;
```
### 6.查看表结构
```mysql
desc <table name>;
```
### 7.查看表的创建语句
```mysql
show create table <table name>;
```
## 四、简单的查询
### 1.查询一个字段
```mysql
select <field> from <table name>;
```
### 2.查询多个字段
```mysql
select <field1>,<field2> from <table name>;
```
### 3.查询全部字段
```mysql
select * from <table name>;
```
### 4.计算员工的年薪
```mysql
select empno, ename, sal*12 from emp;
```
### 5.起别名
```mysql
select empno as '员工编号', ename as '员工姓名', sal*12 as '年薪' from emp;
```
注意:字符串必须添加单引号 | 双引号
## 五、条件查询(where)
### 1.等号操作
查询工资=5000的员工
```mysql
select empno,ename,sal from emp where sal=5000;
```
查询字符串必须加上引号
查询job="manager"的员工
```mysql
select empno, ename from emp where job="manager";
```
### 2.<>符操作
查询薪水不等于5000的员工
```mysql
select empno,ename from emp where sal<>5000;
```
### 3.between...and...操作符
查询薪水为1600到3000的员工(第一种方式,采用>=和<=)
```mysql
select empno,ename from emp where sal>=1600 and sal<=3000;
```
查询薪水为1600到3000的员工(第一种方式,采用between … and …) **闭区间**
```mysql
select empno,ename from emp where sal between 1600 and 3000;
```
### 4.is null
空和空字符串不是一回事,null必须用is来比较
```mysql
select empno,ename from emp where comm is null;
```
### 5.and
工作岗位为MANAGER,薪水大于2500的员工
```mysql
select * from emp where job="manager" and sal>2500;
```
### 6.or
太简单了。略。
### 7.表达式的优先级
查询薪水大于1800,并且部门代码为20或30的员工
```mysql
select * from emp where sal>1800 and (deptno=20 or deptno=30);
```
没把握尽量用括号
### 8.in
in表示包含的意思,完全可以采用or来表示,采用in会更简洁一些
查询出job为manager或者job为salesman的员工
```mysql
select * from emp where job in("manager","salesman");
```
### 9.not
查询出薪水不包含1600和薪水不包含3000的员工
```mysql
select * from emp where sal<>1600 and sal<>3000;
select * from emp where not(sal=1600 or sal=3000);
select * from emp where sal not in(1600,3000);
```
查出津贴不为null的所有员工
```mysql;
select * from emp where comm is not null;
```
### 10.like
Like可以实现模糊查询,like支持%和下划线匹配
%匹配任意字符出现的个数
下划线只匹配一个字符
Like 中的表达式必须放到单引号中|双引号中
查询姓名以M开头的所有员工
```mysql
select * from emp where ename like "M%";
```
查询姓名以N结尾的所有的员工
```mysql
select * from emp where ename like "%N";
```
查询姓名中包含O的所有的员工
```mysql
select * from emp where ename like "%o%";
```
查询姓名中第二个字符为A的所有员工
```mysql
select * from emp where ename like "_a%";
```
## 六、排序数据
### 1.单一字段排序
排序采用order by子句,order by后面跟上排序字段,排序字段可以放多个,多个采用逗号间隔,order by默认采用升序,如果存在where子句那么order by必须放到where语句的后面。
按照薪水由小到大排序(系统默认由小到大)
```mysql
select * from emp order by sal;
```
取得job为MANAGER的员工,按照薪水由小到大排序(系统默认由小到大)
```mysql
select * from emp where job="manager" order by sal;
```
按照多个字段排序,如:首先按照job排序,再按照sal排序
```mysql
select * from emp order by job,sal;
```
### 2.手动指定顺序排序
手动指定按照薪水由小到大排序
```mysql
select * from emp order by sal asc;
```
手动指定按照薪水由大到小排序
```mysql
select * from emp order by sal desc;
```
### 3.多个字段排序
按照job和薪水倒序
```mysql
select * from emp order by job desc,sal desc;
```
### 4.使用字段的位置来排序
按照薪水升序 不建议使用位置
```mysql
select * from emp order by 6;
```
## 七、数据处理函数/单行处理函数
| 函数名 | 作用 |
| :---------- | ---------------------------------------------------- |
| count | 求和 |
| avg | 取平均数 |
| max | 取最大的数 |
| min | 取最小的数 |
| lower | 转换小写 |
| upper | 转换大写 |
| substr | 取子串(substr(被截取的字符串,起始下标,截取的长度)) |
| length | 取长度 |
| trim | 去空格 |
| str_to_date | 将字符串转换成日期 |
| data_format | 格式化日期 |
| format | 设置千分位 format(数字,'格式') |
| round | 四舍五入 |
| rand() | 生成随机数 |
| ifnull | 可以将null转换成一个具体的值 |
**注意:分组函数自动忽略空值,不需要手动的加where条件排除空值。**
select count(\*) from emp where xxx; 符合条件的所有记录总数。
select count(comm) from emp; comm这个字段中不为空的元素总数。
**注意:分组函数不能直接使用在where关键字后面。**
mysql> select ename,sal from emp where sal > avg(sal);
ERROR 1111 (HY000): Invalid use of group function
### 1.count
统计该字段下所有不为NULL的元素的总数
取得所有的员工数
```mysql
select count(*) from emp;
```
取得津贴不为null员工数
```mysql
select count(comm) from emp;
```
取得工作岗位的个数
```mysql
select count(distinct job) from emp;
```
### 2.sum
sum可以取得某一个列的和,null会被忽略
取得薪水的合计
```mysql
select sum(sal) from emp;
```
取得津贴的合计
```mysql
select sum(comm) from emp;
```
取得薪水的合计(sal+comm)
```mysql
select sum(sal+IFNULL(comm,0))) from emp;
```
### 3.substr
找出员工名字第一个字母是A的员工信息
```mysql
select ename from emp where substr(ename,1,1) ="A";
```
### 4.trim去前后空格
```mysql
select ename from emp where ename=trim(" king");
```
### 5.round四舍五入
```mysql
select round(12345.678,1) from emp;
```
### 6.ifnull
```mysql
select ename,(sal+ifnull(comm,0))*12 from emp;
```
### 7.case..when..then..when..then..else...end
当员工的工作岗位是MANAGER的时候,工资上调10%,当工作岗位是SALESMAN的时候,工资上调50%,其他正常。 select不会修改原来的数据
```mysql
select ename,job,(case job when "manager" then sal*1.1 when "salesman" then sal*1.5 else sal end) as newsal from emp;
```
## 八、分组函数
必须先进行分组才能使用,否则就是整张表。
分组查询主要涉及到两个子句,分别是:group by 和 having
### 1.group by
取得每个工作岗位的工资合计,要求显示岗位名称和工资合计?
```mysql
select job,sum(sal) from emp group by job;
```
找出每个部门最高薪资大于3000的?
```mysql
select deptno,max(sal) from emp where sal>3000 group by deptno;
```
### 2.having
如果想对分组数据再进行过滤需要使用 having 子句
取得每个岗位的平均工资大于 2000 ?
```mysql
select job,avg(sal) from emp group by job having avg(sal)>2000;
```
### 3.distinct
去除重复记录。如果出现在所有字段的前方表示所有字段联合起来去除重复记录?
```mysql
select distinct job from emp;
```
统计工作岗位的数量?
```mysql
select count(distinct job) from emp;
```
### 大总结(单表查询)
执行顺序?
1. from 从某张表中查询数据
2. where 先经过where条件筛选出有价值的数据
3. group by 对这些有价值的数据进行分组
4. having 分组之后可以使用having进行筛选
5. select select查询出来
6. order by 最后排序输出
找出每个岗位的平均薪资,要求显示薪资大于1500的并保留1位小数,除MANAGER岗位之外,要求按照平均薪资降序排
```mysql
select job,round(avg(sal),1) avgsal from emp where job<>"manager" group by job having avg(sal)>1500 order by avgsal desc;
```
## 九、连接查询
连接查询:也可以叫跨表查询,需要关联多个表进行查询
根据表连接的方式:
内连接:
等值连接
非等值连接
自连接
外连接:
左外连接(左连接)
右外连接(右连接)
全连接(略)
如果多表查询没有加条件,就会出现出笛卡尔积现象
笛卡尔乘积是指在数学中,两个集合*X*和*Y*的笛卡尔积(Cartesian product),又称直积,表示为*X* × *Y*,第一个对象是*X*的成员而第二个对象是*Y*的所有可能有序对的其中一个成员 。
### 1.内连接之等值连接
查询每个员工所在的部门名称,显示员工名和部门名?
```mysql
sql92语法
select e.ename,d.dname from emp e,dept d where e.deptno=d.deptno;
```
```mysql
sql99语法
select e.ename,d.dname from emp e join dept d on e.deptno=d.deptno;
```
sql92的缺点:结构不清晰,表的连接条件,和后期进一步筛选条件都放到了where后面
sql99的优点:表连接的条件是独立的,连接之后如果还需要进一步的筛选,再往后添加where条件
### 2.内连接之非等值连接
找出每个员工的薪资等级,要求显示员工名、薪资、薪资等级?
```mysql
select e.ename,e.sal,s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal;
```
### 3.内连接之自连接
查询员工的上级领导,要求显示员工名和对应的领导名?
```mysql
select e.ename '员工名',m.ename '领导名' from emp e join emp m on m.mgr=e.empno;
```
### 4.外连接(右外连接)
在外连接当中两张表产生了主次关系
right代表什么: 表示将右边的这张表看成主表,主要是为了将右边这张表的数据全查出来,捎带着关联左边的表。
查询所有部门对应的员工姓名?
```mysql
select e.ename,d.dname from emp e right join dept d on e.deptno=d.deptno;
```
### 5.外连接(左外连接)
带有left的是左外连接
查询每个员工的上级领导,要求显示所有员工的名字和领导名?
```mysql
select a.ename '员工',b.ename '领导' from emp a left join emp b on a.mgr=b.empno;
```
### 6.三张表、四张表连接
语法:
select ... from a
join b on a和b的连接条件
left join c on a 和c的连接条件
join d on a和d的连接条件;
找出每个员工的部门名称以及工资等级,要求显示员工名、部门名、薪资、薪资等级、领导名字?
```mysql
select e.ename,d.dname,e.sal,s.grade,l.ename from emp e join dept d on e.deptno=d.deptno join salgrade s on e.sal between losal and hisal left join emp l on e.mgr=l.empno;
```
## 十、子查询
子查询就是嵌套的 select 语句,可以理解为子查询是一张表
### 1.子查询出现在哪里?
select
..(select)
from
..(select)
where
..(select)
### 2.where子句中的子查询
找出比最低工资高的员工姓名和工资?
```mysql
select ename,sal from emp where sal > (select min(sal) from emp);
```
### 3.from子句中的子查询
注意:from后面的子查询,可以将子查询的结果当成一张临时表。
找出每个岗位的平均薪资的薪资等级
```mysql
select t.job,s.grade,t.a from (select job,avg(sal) a from emp group by job) t join salgrade s on t.a between losal and hisal;
```
### 4.select后面出现的子查询
找出员工的部门名,要求显示员工名,部门名?
```mysql
select e.ename,(select d.dname from dept d where d.deptno=e.deptno ) as dname from emp e;
```
## 十一、union、limit
union的效率更高一些。对于表连接来说,每连接一次新表,则匹配的次数满足笛卡尔积,成倍的翻。但是union可以减少匹配的次数。在减少匹配次数的情况下,还可以完成两个结果集的拼接。
### 1.union
查询工作岗位是manager或者salesman
```mysql
select ename,job from emp where job="manager" or job="salesman";
select ename,job from emp where job in("manager","salesman");
select ename,job from emp where job="manager" union select ename,job from emp where job="salesman";
```
### 2.limit
limit是将查询结果集的一部分取出来
完整用法:limit startIndex,length
按照薪资降序,取出前5条数据
```mysql
select ename,sal from emp order by sal desc limit 0,5;
```
### 3.分页
每页显示3条记录
第1页: limit 0,3 [0 1 2]
第2页: limit 3,3 [3 4 5]
第3页: limit 6,3 [6 7 8]
每页显示pasgeSize条记录
第pageNo页: limit (pageNo-1)*pageSize,pagesize;
## 十二、表
### 1.表的创建(DDL)
语法格式
```mysql
create table tableName(
columnName dataType(length),
………………
columnName dataType(length)
);
set character_set_results='gbk';
show variables like '%char%';
```
### 2.关于MySQL中的数据类型
部分常用类型:
| 类型 | 描述 |
| --------------------------- | ------------------------------------------------ |
| char(长度) | 定长字符串,存储空间大小固定,适合作为主键或外键 |
| varchar(长度) | 变长字符串,存储空间等于实际数据空间 |
| double(有效数字位数,小数位) | 数值型 |
| float(有效数字位数,小数位) | 数值型 |
| int(长度) | 整数 |
| bigint(长度) | 长整型 |
| Date | 日期型 |
| BLOB | Binary Large Object(二进制大对象) |
| CLOB | Character Large Object (字符大对象) |
### 3.创建一个学生表
学号、姓名、年龄、性别、邮箱地址
```mysql
create table t_student(
no int,
name varchar(32),
sex char(1) default('m'),
age int(3),
email varchar(255)
);
```
### 4.插入数据insert (DML)
语法格式:
inser into 表名(字段名1,字段名2,字段名3) values(值1,值2,值3);
注意:
字段名和值要一一对应
insert语句但凡执行成功,那么必然会多一条记录
字段名省略的话,就相当于都写上了~ 所以值也要都写上!
```mysql
insert into t_student(no,name,sex,age,email) values(1,'jack','m',21,'test@163.com');
insert into t_student values(2,'tom','m',22,'test1@163.com');
一次插入多条记录:
insert into t_student values(2,'tom','m',22,'test1@163.com'),(3,'zs','m','9','test2@163.com');
```
**将查询结果插入到一张表当中**
```mysql
create table dept_bak as select * from dept;
查询结果必须符合表的结构
insert into dept_bak select * from dept;
```
### 5.insert插入日期
数字格式化:format(数字,'格式')
str_to_date: 将字符串varchar类型转换为date类型,具体格式 str_to_date (字符串,匹配格式)
date_format:将date类型转换成具有一定格式的字符串类型
```mysql
create table t_user(
id int,
name varchar(32),
birth date
);
```
插入数据
```mysql
insert into t_user(id,name,birth) values(1,'jack',str_to_date('12-06-2021','%d-%m-%Y'));
如果输入的字符串是YYYY-mm-dd,还可以自动转换
insert into t_user(id,name,birth) values(2,'tom','2021-6-12');
```
查询的时候还可以以某个特定的日期格式展示
date_format
```mysql
select id,name,date_format(birth,'%m/%d/%Y') as birth from t_user;
```
### 6.date和datetime两个类型的区别
date是短日期:只包括年月信息
datetime是长日期:包括年月日时分秒信息
```mysql
drop table if exists t_user;
create table t_user(
id int,
name varchar(32),
birth date,
create_time datetime
);
```
mysql短日期默认格式:%Y-%m-%d
mysql长日期格式:%Y-%m-%d %h:%i:%s
now()函数可以获取当前系统时间,是datetime类型的格式
```mysql
insert into t_user(id,name,birth,create_time) values(1,'jack','2021-6-12','2021-6-12 19:50:22');
insert into t_user(id,name,birth,create_time) values(2,'tom','2021-6-12',now());
```
### 7.修改update语句(DML)
语法格式:
update 表名 set 字段名1=值1,字段名2=值2,字段名3=值3 where 条件;
```mysql
update t_user set name="zhangsan",birth="2020-01-01" where id=1;
```
**注意**:如果不加where条件默认更新表中的所有数据。
### 8.删除delete语句(DML)
语法格式:
delete from 表名 where 条件
```mysql
delete from t_user where id=2;
```
**注意**:如果不加where条件默认删除表中的所有数据。
### 9.表快速复制
原理:
**将一个查询结果当做一张表创建**
这个可以完成表的快速复制
表创建出来,同时表中的数据也存在了
```mysql
create table t_user_bak as select * from t_user;
```
### 10.删除表
```mysql
drop table t_student; //如果存在就删除
drop table if exists t_student; //如果不存在就不会报错
```
### 11.快速删除表中的数据
不支持回滚
```mysql
truncate table 表名;
```
### 12.对表结构的增删改查
采用 alter table 来增加/删除/修改表结构,不影响表中的数据
一般不用,实际开发中,需求一旦确定之后,表结构确定之后,很少进行表的修改。因为开发进行中的时候,修改表结构,成本比较高。这里简单了解一下,如果修改结构可以用可视化工具。
**1.添加字段**
如需求发生改变,需要向t_user中加入联系电话字段,字段名称为:contact_tel类型为varchar(40)
```mysql
alter table t_user add contact_tel varchar(40);
```
**2.修改字段**
如:name 无法满足需求,长度需要更改为 100
```mysql
alter table t_user modify name varchar(100);
```
如 sex 字段名称感觉不好,想用 gender 那么就需要更爱列的名称
```mysql
alter table t_user change sex gender char(2) not null;
```
**3.删除字段**
如:删除联系电话字段
```mysql
alter table t_user drop contact_tel;
```
## 十三、约束
约束对应的单词:constraint
在创建表的时候,我们可以给表中的字段加上一些约束,来保证表中的数据完整性、有效性
约束的作用就是为了保证:表中的数据有效!!
### **1**.**常见的约束**?
非空约束:not null
唯一性约束:unique
主键约束:primary key
外键约束:foreign key
检查约束:check(mysql不支持,oracle支持)
#### 1.1非空约束:not null
非空约束not null约束的字段不能为NULL。
```mysql
drop table if exists t_user;
create table t_user(
id int,
name varchar(255) not null
);
insert into t_user(id,name) values(1,'zhangsan');
insert into t_user(id,name) values(2,'lisi');
---------------------------------------------------
insert into t_user(id,name) values(2);
ERROR 1136 (21S01): Column count doesn't match value count at row 1
```
#### 1.2唯一性约束:unique
**唯一性约束的unique约束的字段不能重复,但是可以为null**
```mysql
drop table if exists t_user;
create table t_user(
id int,
name varchar(255) unique
);
insert into t_user(id,name) values(1,'zs');
insert into t_user(id,name) values(2,'ls');
insert into t_user(id) values(3);
insert into t_user(id) values(4);
--------------------------------------------------------
insert into t_user(id,name) values(3,'zs');
ERROR 1062 (23000): Duplicate entry 'zs' for key 'name'
```
**name和email联合起来具有唯一性**
如果约束没有添加到字段后面,成为表级约束
```mysql
drop table if exists t_user;
create table t_user(
id int,
name varchar(255),
email varchar(255),
unique(name,email)
);
insert into t_user(id,name,email) values(1,'zhangsasn','123@qq.com');
insert into t_user(id,name,email) values(2,'zhangsasn','1234@qq.com');
-------------------------------------------------------------------
insert into t_user(id,name,email) values(2,'zhangsasn','1234@qq.com');
ERROR 1062 (23000): Duplicate entry 'zhangsasn-1234@qq.com' for key 'name'
```
**在mysql中**,如果一个字段同时被not null和unique约束,自动变成主键字段。
#### 1.3主键约束:primary key
相关术语:主键约束、主键字段、主键值
主键值是每一行记录的唯一标识
任何一张表都应该有主键,建议使用int、bigint、char等类型
主键值不能是null同时也不能重复
```mysql
drop table if exists t_user;
create table t_user(
id int primary key,
name varchar(255)
);
insert into t_user(id,name) values(1,'zs');
insert into t_user(id,name) values(2,'ls');
---------------------------------------------------------
insert into t_user(id,name) values(1,'wz');
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
```
可以俩主键联合起来做表级约束,这样的主键叫复合主键,比较复杂。建议单一主键。
主键除了单一主键和复合主键之外,还可以这样分类:
自然主键:主键值是一个自然数,和业务没关系
单一主键:主键值和业务紧密相连,例如银行卡号。
**主键值可以采用auto_increment自动维护**
```mysql
drop table if exists t_user;
create table t_user(
id int primary key auto_increment,
name varchar(255)
);
insert into t_user(name) values('zs');
insert into t_user(name) values('ls');
select * from t_user;
+----+------+
| id | name |
+----+------+
| 1 | zs |
| 2 | ls |
+----+------+
```
#### 1.4外键约束:foreign key
相关术语:外键约束、外键字段、外键值
子表中的一个字段引用父表中的一个字段。如果删除表,应该先删子表。
这里学生表中的cno字段引用班级表中的classno字段
```mysql
drop table if exists t_student;
drop table if exists t_class;
create table t_class(
classno int primary key,
classname varchar(255)
);
create table t_student(
id int primary key auto_increment,
name varchar(255),
cno int,
foreign key(cno) references t_class(classno)
);
insert into t_class(classno,classname) values(100,'某高级中学1班');
insert into t_class(classno,classname) values(101,'某高级中学2班');
insert into t_student(name,cno) values('zhhangsan',100);
insert into t_student(name,cno) values('lisi',100);
insert into t_student(name,cno) values('wangwu',100);
insert into t_student(name,cno) values('tom',101);
insert into t_student(name,cno) values('jack',101);
insert into t_student(name,cno) values('jreey',101);
------------------------------------------------------------
insert into t_student(name,cno) values('wangwu',109);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`learn`.`t_student`, CONSTRAINT `t_student_ibfk_1` FOREIGN KEY (`cno`) REFERENCES `t_class` (`classno`))
```
字表中的外键引用父表中的某个字段,被引用的字段不一定是主键,至少具有unique约束(唯一性)。
外键值可以为null。
### 2.增加/删除/修改表约束
#### 2.1删除约束
```mysql
删除外键约束:alter table 表名 drop foreign key 外键 (区分大小写);
删除主键约束:alter table 表名 drop primary key;
删除约束:alter table 表名 drop key 约束名称;
```
#### 2.2添加约束
```mysql
添加外键约束:alter table 从表 add constraint 约束名称 foreign key 从表(外键字段) references 主表(主键字段);
添加主键约束:alter table 表 add constraint 约束名称 primary key 表(主键字段);
添加唯一性约束:alter table 表 add constraint 约束名称 unique 表(字段)
```
#### 2.3修改约束,其实就是修改字段
```mysql
alter table t_student modify student_name varchar(30) unique;
```
## 十四、存储引擎(了解)
存储引擎是MySQL中特有的术语。
存储引擎是一个表存储/组织数据的方式。
不同的存储引擎,表存储数据的方式不同。
数据库中的各表均被(在创建表时)指定的存储引擎来处理。
```mysql
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
```
在建表的时候可以在最后的")"的右边使用:
engine来指定存储引擎 。默认是InnoDB
charset来指定这张表的字符编码方式。默认是:utf-8
为了解当前服务器中有哪些存储引擎可用,可使用 SHOW ENGINES 语句 。
### 1.常用存储引擎
**MyISAM**
它管理的表具有以下特征:
– 使用三个文件表示每个表:
• 格式文件 — 存储表结构的定义(mytable.frm)
• 数据文件 — 存储表行的内容(mytable.MYD)
• 索引文件 — 存储表上索引(mytable.MYI)
– 灵活的 AUTO_INCREMENT 字段处理
– 可被转换为压缩、只读表来节省空间
**InnoDB**
它管理的表具有下列主要特征:
– 每个 InnoDB 表在数据库目录中以.frm 格式文件表示
– InnoDB 表空间 tablespace 被用于存储表的内容
– 提供一组用来记录事务性活动的日志文件
– 用 COMMIT(提交)、SAVEPOINT 及 ROLLBACK(回滚)支持事务处理
– 提供全 ACID 兼容
– 在 MySQL 服务器崩溃后提供自动恢复
– 多版本(MVCC)和行级锁定
– 支持外键及引用的完整性,包括级联删除和更新
**MEMORY**
使用 MEMORY 存储引擎的表,其数据存储在内存中,且行的长度固定,这两个特点使得 MEMORY 存储引擎非 常快。
• MEMORY 存储引擎管理的表具有下列特征:
– 在数据库目录内,每个表均以.frm 格式的文件表示。
– 表数据及索引被存储在内存中。
– 表级锁机制。
– 不能包含 TEXT 或 BLOB 字段。
• MEMORY 存储引擎以前被称为 HEAP 引擎
### 2.选择合适的存储引擎
• MyISAM 表最适合于大量的数据读而少量数据更新的混合操作。MyISAM 表的另一种适用情形是使用压缩的只 读表。
• 如果查询中包含较多的数据更新操作,应使用 InnoDB。其行级锁机制和多版本的支持为数据读取和更新的混合 操作提供了良好的并发机制。
• 可使用 MEMORY 存储引擎来存储非永久需要的数据,或者是能够从基于磁盘的表中重新生成的数据。
## 十五、事务(重点)
transaction
### 1.事务介绍
事务就是一个完整的业务逻辑,是一个最小的工作单元。
假如转账:从A账户向b账户转10000.
将A账户的钱减去10000(update语句)
将B账户的钱加上10000(update语句)
这就是一个完整的业务逻辑。
以上就是最小的业务单元,不可再分。要么同时成功,要么同时失败。
只有DML语句才有事务:insert update delete。一旦涉及增删改查就要考虑安全问题。
事务是怎么做到多条DML语句同时成功或同时失败的呢?
InnoDB存储引擎: 提供一组用来记录事务性活动的日志文件
事务开启:
insert
insert
delete
update
insert
事务结束!
在事务的执行过程中,每一条DML的操作都会记录到“事务性活动的日志文件”。
我们可以提交事务,可以回滚事务。
提交事务:清空事务性活动的日志文件,将数据全部彻底持久化到数据库表中。标志着事务全部成功结束。
回滚事务:将之前所有的DML操作全部撤销,并清空事务性活动的日志文件。标志着事务全部失败的结束。
### 2.提交/回滚事务
提交事务:commit; 语句 (MySQL默认自动提交事务)
回滚事务:rollback; 语句 (回滚永远只能回滚到上一次的提交点)
关闭自动提交事务
```mysql
start transaction;
```
### 3.事务四个特性
A:原子性
说明事务是最小的工作单元。不可再分。
C:一致性
所有事物要求,在同一个事务中,所有操作必须同时成功,或者同时失败,以保证数据的一致性。
I:隔离性
A事务和B事务之间具有一定的隔离
D:持久性
失误最终结束的一个保障。事务提交,就相当于没有保存到硬盘上的数据保存到硬盘上。
**隔离性**
**当多个客户端并发地访问同一个表时,可能出现下面的一致性问题:**
– 脏读取(Dirty Read) 一个事务开始读取了某行数据,但是另外一个事务已经更新了此数据但没有能够及时提交,这就出现了脏读取。
– 不可重复读(Non-repeatable Read) 在同一个事务中,同一个读操作对同一个数据的前后两次读取产生了不同的结果,这就是不可重复读。
–幻像读(Phantom Read) 幻像读是指在同一个事务中以前没有的行,由于其他事务的提交而出现的新行。
**InnoDB 实现了四个隔离级别,用以控制事务所做的修改,并将修改通告至其它并发的事务:**
– 读未提交(READ UMCOMMITTED) 允许一个事务可以看到其他事务未提交的修改。(最低的隔离级别)
– 读已提交(READ COMMITTED) 允许一个事务只能看到其他事务已经提交的修改,未提交的修改是不可见的。
– 可重复读(REPEATABLE READ) 确保如果在一个事务中执行两次相同的 SELECT 语句,都能得到相同的结果,不管其他事务是否提交这些修改。(银 行总账) 该隔离级别为 InnoDB 的缺省设置。
– 串行化(SERIALIZABLE) 【序列化】 将一个事务与其他事务完全地隔离。 (最高的隔离级别)