冬季实战营第三期学习报告

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: MySQL数据库进阶实战以及sql语句使用

## 一、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) 【序列化】 将一个事务与其他事务完全地隔离。 (最高的隔离级别)

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
SQL Web App开发 弹性计算
学习报告:冬季实战营第三期
在《冬季实战营第三期:MySQL数据库进阶实战》的学习报告
252 0
学习报告:冬季实战营第三期
|
弹性计算 关系型数据库 MySQL
关于“冬季实战营第一期”的学习报告
冬奥云小宝带你玩转五期实战营,初识上云基础,非常适合新手上路,上云必备环境准备让您轻松上云。
797 1
关于“冬季实战营第一期”的学习报告
|
弹性计算 Java 关系型数据库
冬季实战营第一期学习报告
冬季实战营第一期学习报告
|
SQL 弹性计算 运维
冬季实战营第三期学习报告
通过本期学期,掌握了MySQL及RDS MySQL基本操作
146 2
|
Web App开发 弹性计算 Kubernetes
学习报告:冬季实战营第四期
在《冬季实战营第四期:零基础容器技术实战》的学习报告
182 0
学习报告:冬季实战营第四期
|
关系型数据库 MySQL 分布式数据库
冬季实战营第一期-学习报告
冬季实战营第一期-学习报告
|
Linux 程序员 Shell
冬季实战营第二期学习报告
针对第二期的Linux操作系统实战入门,通过动手实操的体验写出感受。时间真快,从1月24日到1月28日,参与了五天不同内容的动手实战,从中发现虽然在大学里学过这门课,但是好像没有这期收获很多没有学过的知识点,每一天都在涨知识,不得不感叹,学无止境,感觉真妙,可见大学里学的东西比较浅,还需要自学其它很多新知识点,感谢第二期Linux操作系统实战入门的体验,再接再厉~ 让我们一起向未来。
147 0
冬季实战营第二期学习报告
|
弹性计算 缓存 安全
学习报告:冬季实战营第二期
在冬季实战营第二期:Linux操作系统实战入门的学习报告
212 0
学习报告:冬季实战营第二期
|
Web App开发 弹性计算 关系型数据库
学习报告:冬季实战营第一期
在冬季实战营第一期:从零到一上手玩转云服务器的学习报告
268 0
学习报告:冬季实战营第一期
|
Kubernetes 监控 Docker
冬季实战营第四期学习报告
通过本期学期,掌握了容器的基本技术
92 0