MySQL基础整理

1 数据库及数据准备

1.1 SQL和数据库概述

  • DB:DataBase,数据库,在硬盘上以文件的形式存在
  • DBMS:DataBase Management System,数据库管理系统,常见的有MYSQL、Oracle、SqlServer、DB2…
  • SQL:Strutured Query Language,结构化查询语言,是一门高级语言,标准的SQL适用于所有数据库管理系统。SQL语句在执行时也会进行编译,编译由DBMS完成。
  • 三者的关系:DBMS负责执行SQL语句,来操作DB中的数据。

1.2 表

  • 表(table)是一种结构化文件,用来存储特定类型的数据,如学生信息、课程信息等。
  • 表是数据库的基本组成单元,所有数据都以表格的形式组织,可读性强。
  • 表都有特定的名称,而且不能重复。
  • “列”叫做字段(column),“行”叫做记录/数据(data),每一个字段都有字段名称、字段数据类型、字段约束和字段长度。

1.3 SQL语句分类

  • 数据查询语言DQL(Data Query Language):select,查询语句
  • 数据操作语言DML(Data Manipulation Language):insert,delete,update,对表中数据进行增删改
  • 数据定义语言DDL(Data Defination Language):create,drop,alter,对表结构进行增删改
  • 事务控制语言TCL(Transaction Control Language):commit提交事务,rollback回滚事务
  • 数据控制语言DCL(Data Control Language):grant授权,revoke撤销权限

1.4 导入数据

  • 登陆mysql数据库管理系统

    • dos命令窗口—>mysql -uroot -p1234
  • 查看数据库

    • show databases;(MySQL命令,不是SQL语句)
  • 创建自己的数据库

    • creat database liuyupeng;(MySQL命令,不是SQL语句)
  • 使用数据库

    • use liuyupeng;(MySQL命令,不是SQL语句)
  • 查看当前使用的数据库有哪些表

    • show tables;(MySQL命令,不是SQL语句)
  • 初始化数据

    • source D:\Programming\MySQL\resources\bjpowernode.sql

    • 初始化后,有3张表

      mysql> show tables;
      +---------------------+
      | Tables_in_liuyupeng |
      +---------------------+
      | dept                |
      | emp                 |
      | salgrade            |
      +---------------------+
      3 rows in set (0.00 sec)
      
  • 查看表的创建语句

    • show create table emp;
  • 删除数据库

    • drop database liuyupeng;

1.5 sql脚本

扩展名是.sql,且其中编写了大量的sql语句的文件称为”sql脚本“。sql脚本数据量太大,无法打开的时候,可以直接使用source命令执行sql脚本,完成初始化。

1.6 表结构

查看表结构:desc 表名称;

查看表中的数据:select * from 表名称;

2 常用命令

查看mysql版本:

C:\Users\Yupeng>mysql --version
mysql  Ver 14.14 Distrib 5.5.36, for Win64 (x86)

C:\Users\Yupeng>mysql -V
mysql  Ver 14.14 Distrib 5.5.36, for Win64 (x86)

创建数据库:

create database 数据库名称;
use 数据库名称;

查询当前使用的数据库:

select  database();

终止一条正在编写的语句,可输入\c

3 简单查询

3.1 查询一个字段

select 字段名称 from 表名称;,select语句后面跟的是字段名称,select是关键字,select和字段名称之间采用空格隔开,from表示将要查询的表,它和字段之间采用空格隔开。

注意:

  • 任何一条sql语句以”;“结尾
  • sql语句不区分大小写

3.2 查询多个字段

select 字段名称1,字段名称2,字段名称3... from 表名称;,查询多个字段,select中的字段采用逗号隔开。

字段可以参与数学运算:select ename,sal * 12 from emp;

给查询结果的列重命名:select ename,sal * 12 as yearsalary from emp;

as关键字可以省略:select ename,sal * 12 yearsalary from emp;

如果重命名中有中文,标准sql语句要求用单引号将字符串括起来,select ename,sal * 12 as '年薪' from emp;

去除查询结果集中的重复记录,select distinct 字段名称 from 表名称;,但distinct关键字只能出现在所有字段的最前面,去除所有联合字段的重复记录。不会改变源数据。统计岗位的数量:select count (distinct job) from emp;

3.3 查询全部字段

select * from 表名称;,实际开发中不建议使用,效率较低。

4 条件查询

条件查询的语法格式:

select 字段名称1,字段名称2... from 表名称 where 条件;

支持以下运算符:

运算符说明
=等于
<>或!=不等于
<小于
<=小于等于
>大于
>=大于等于
between … and ….两个值之间,等同于 >= and <=
is null为null(is not null 不为空)
and并且
or或者
in包含,相当于多个or(not in是不在这个范围中)
notnot可以取非,主要用在is或in中
likelike称为模糊查询,支持%或下划线匹配,%匹配任意个字符,下划线只匹配一个字符

4.1 等号操作符

查询薪水为5000的员工

select ename from emp where sal = 5000;

查询某员工的薪水

select sal from emp where ename = 'SMITH';

4.2 <>操作符

查询薪水不等于5000的员工

select ename, sal from emp where sal <> 5000;或者select ename, sal from emp where sal != 5000;

4.3 between … and ….操作符

用于数字,闭区间:查询薪水在1100到3000之间的员工

select ename, sal from emp where sal between 1100 and 3000;

(使用较少)用于字符串,左闭右开:查询员工的姓名

select ename from emp where ename between 'A' and 'D';

4.4 is null运算符

null不是一个值,不能用等号,必须使用is null或者is not null。

查询没有津贴的员工

select ename, sal, comm from emp where comm is null;

查询有津贴的员工

select ename, sal, comm from emp where comm is not null;

4.5 and和or(in)运算符

查询岗位是MANAGER和SALESMAN的员工

select ename, job from emp where job = 'MANAGER' or job = 'SALESMAN';或者select ename, job from emp where job in ('MANAGER', 'SALESMAN')

查询薪水大于1000并且部门编号是20或30的员工

select ename, sal, deptno from emp where sal > 1000 and deptno = 20 or sal > 1000 and deptno = 30;或者select ename, sal, deptno from emp where sal > 1000 and (deptno = 20 or deptno = 30);,当运算符的优先级不确定时,加小括号。

4.6 模糊查询

模糊查询中,%代表任意多个字符,_代表任意1个字符

查询名字中含有’O‘的员工

select ename from emp where ename like '%O%';

查询名字的第三个字母是A的员工

select ename from emp where ename like '__A%';

查询名字中含有下划线’_'的员工

select ename from emp where ename like '%\_%';,要加转义字符。

5 排序数据

5.1 单字段排序

按照薪水升序,查询员工名字和薪水

select ename, sal from emp order by sal;,默认是升序。

可以指定排序顺序,asc表示升序,desc表示降序。select ename, sal from emp order by sal desc;

5.2 多字段排序

越靠前的字段起到主导作用。

按薪水降序排列,薪水相同时再按照名字升序排列。

select ename, sal from emp order by sal desc, ename asc;

查询工作岗位是SALESMAN的员工,且按照薪水降序排列。

select ename, job, sal from emp where job = 'salesman' order by sal desc;,先执行from,再对比条件where,然后查询select,最后排序order。

5.3 使用字段顺序排序

select ename, sal from emp order by 2;,按照第2列排序,也就是ename和sal中的第二个,即按照sal排序。不建议使用此种方式,因为采用数字含义不明确,程序不健壮。

6 分组函数

分组函数是对某一组数据进行操作。

分组函数也称多行处理函数,特点是输入多行,输出结果是一行。对比地,单行处理函数特点是输入几行,也输出几行。重点:只要有null参与的运算结果一定是null,处理方法是使用ifnull函数, 查询津贴select ename, ifnull(comm,0) as comm from emp;,查询年薪select ename, (sal+ifnull(comm,0))*12 as yearsal from emp;

分组函数自动忽略null

函数名称作用
count取得记录数
sum求和
avg取平均
max取最大值
min取最小值

查询薪水总和

select sum(sal) from emp;

查询最高薪水

select max(sal) from emp;

查询平均薪水

select avg(sal) from emp;

查询员工总人数

select count(*) from emp;或者select count(ename) from emp;

组合使用

select count(*), max(sal), min(sal), avg(sal), sum(sal) from emp;

注意:语法规则:分组函数不能直接使用在where关键字后面。查询薪水高于平均薪水的员工:select ename,sal from emp where sal > avg(sal);,报错:ERROR 1111 (HY000): Invalid use of group function,正确写法:select ename, sal from emp where sal > (select avg(sal) from emp);

count(*)count(某个字段)的区别:count(*)是统计总记录条数,和具体字段无关,count(某个字段)统计某个字段不为null的记录条数。

7 分组查询

7.1 group by

group by:按照某个字段或某些字段进行分组。

注意:1.分组函数一般和group by联合使用,且分组函数是在group by语句执行结束后执行的;2.如果一条sql语句没有group by的话,整张表的数据会缺省分为一组;3.在SQL语句中若有group by 语句,那么在select语句后面只能跟分组函数和参与分组的字段,不能跟其他字段。比如select ename, max(sal), job from emp group by job;,该语句在mysql中是有查询结果的,但结果没有意义,而在Oracle数据库中会报语法错误。

查询每个岗位的最高薪水

select job,sal from emp group by job;

查询每个工作岗位的平均薪水

select job, avg(sal) from emp group by job;

查询各个部门不同岗位的最高薪水

select deptno, job, max(sal) from emp group by deptno, job;

7.2 having

having:对分组之后的数据进行再次过滤,不可以单独出现。

查询每个部门的最高薪水,要求显示薪水大于2900的数据

select deptno, max(sal) from emp group by deptno having max(sal) > 2900;或者

select deptno, max(sal) from emp where sal > 2900 group by deptno;,后者效率较高,建议能使用where的时候尽量使用此方式。

查询每个部门的平均薪水,要求显示薪水大于2000的数据

select deptno, avg(sal) from emp group by deptno having avg(sal) > 2000;,此时不能使用where,select deptno, avg(sal) from emp where avg(sal) > 2000 group by deptno;,因为where后面不能直接跟分组函数。

7.3 select总结

一个完整的select语句格式如下

select 字段名称 from 表名 where... group by... having... order by...

以上语句的执行顺序:

  1. 执行from,从某张表查询
  2. 执行where,过滤原始数据
  3. 执行group by,进行分组
  4. 执行having,对分组后数据进行再次过滤
  5. 执行select,选出数据
  6. 执行order by,排序

8 连接查询

连接查询:在实际开发中,大部分情况下都不是从单表中查询数据,一般都是多张表联合查询取出最终的结果。

笛卡尔积现象:当两张表进行连接查询的时候,如果没有任何条件限制,最终的查询结果条数是两张表记录条数的乘积。查询每个员工的部门名称,要求显式员工名字和部门名字:select ename, dname from emp, dept;,出现14 * 4 = 56条记录。避免笛卡尔积现象的方法是加条件进行过滤,避免后只显示有效记录,但不会减少匹配次数。

使用表的别名:两个优点,一是执行效率高,二是可读性好。select e.ename, d.dname from emp e, dept d;

连接查询的分类:

  • 根据语法出现的时间可分为:
    • SQL92
    • SQL99
  • 根据表的连接方式可划分为:
    • 内连接
      • 等值连接
      • 非等值连接
      • 自连接
    • 外连接
      • 左外连接
      • 右外连接
    • 全连接

8.1 内连接

假设A表和B表连接,使用内连接,A表和B表能够匹配的记录都查询出来,两张表没有主副之分。如果A表中有某条记录,而B表中没有匹配的记录,则最终查询结果会丢失这条记录。

8.1.1 等值连接

连接条件是等量关系。语法格式:... A join B on 连接条件 where ...,将表的连接条件和where条件分离,使结构更清晰。

查询每个员工的部门名称,要求显示员工名字和部门名字:select e.ename, d.dname from emp e (inner,可省略)join dept d on e.deptno = d.deptno;

8.1.2 非等值连接

连接条件是非等量关系。

查询每个员工的工资等级,要求显示员工名字、工资和工资等级:select e.ename, e.sal, s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal;

8.1.3 自连接

特点是一张表看作两张表,自己连接自己。

查询每个员工的上级领导,要求显示员工名字和对应的领导名字:select a.ename as '员工名', b.ename as '领导名' from emp a inner join emp b on a.mgr = b.empno;

8.2 外连接

假设A表和B表连接,使用外连接,两张表中有一张是主表,另一张是副表,主要查询主表数据,主表的记录可以都查询出来,如果副表中有与A表匹配的记录,则查询显示,如果有的记录没有匹配上,则模拟出null与之匹配(这里对比内连接来理解)。外连接比内连接使用得多。

8.2.1 左外连接

左外连接也称左连接,表示左边的表是主表。

查询每个员工的上级领导(所有员工)select a.ename as '员工', b.ename as '领导' from emp a left (outer,可省略)join emp b on a.mgr = b.empno;查询到14条记录。

如果采用内连接:select a.ename as '员工', b.ename as '领导' from emp a join emp b on a.mgr = b.empno;,查询到13条记录,以为KING没有上级领导,会丢失1条记录。

8.2.2 右外连接

右外连接也称右连接,表示右边的表是主表。查询每个员工的上级领导(所有员工)select a.ename as '员工', b.ename as '领导' from emp b right join emp a on a.mgr = b.empno;

查询没有员工的部门select d.deptno from emp e right join dept d on d.deptno = e.deptno where e.empno is null;或者select d.deptno from emp e right join dept d on d.deptno = e.deptno where e.ename is null;

8.3 三张表以上的连接

查询每个员工的部门名称以及薪水等级select e.ename, d.dname,s.grade from emp e join dept d on e.deptno = d.deptno join salgrade s on e.sal between s.losal and s.hisal;

查询每个员工的部门名称、薪水等级和上级领导select e.ename, a.ename '上级领导', d.dname,s.grade from emp e join dept d on e.deptno = d.deptno join salgrade s on e.sal between s.losal and s.hisal left join emp a on e.mgr = a.empno;,注意此例中查询上级领导时要用外连接。

9 子查询

select语句中嵌套select语句,被嵌套的select语句是子查询。

9.1 where子句中使用子查询

查询高于平均薪水的员工信息select * from emp where sal > (select avg(sal) from emp);

9.2 from后面嵌套子查询

查询每个部门平均薪水的薪资等级

第一步,查询每个部门的平均薪水select deptno, avg(sal) as avgsal from emp group by deptno;

第二步,将以上查询结果作为临时表t,t表和salgrade s表连接。select t.*, s.grade from (select deptno, avg(sal) as avgsal from emp group by deptno) t join salgrade s on t.avgsal between s.losal and s.hisal

9.3 select后面嵌套子查询

查询每个员工所在的部门名称select e.ename, (select d.dname from dept d where e.deptno = d.deptno) as dname from emp e;

10 union

union可以将查询结果相加,两个select查询的字段数量应该一致。

查询工作岗位是SALESMAN和MANAGER的员工。

第一种:select ename, job from emp where job = 'SALESMAN' or job = 'MANAGER';

第二种:select ename, job from emp where job in('SALESMAN','MANAGER');

第三种:select ename, job from emp where job = 'MANAGER' union select ename, job from emp where job = 'SALESMAN';

11 limit(重点)

limit是mysql特有的,其他数据库没有。

limit取结果集中的部分数据。

limit是SQL语句最后执行的一个环节。

语法机制:limit startIndex, length,startIndex表示起始位置(0表示第一条数据),length表示取的数量。startIndex不写时,默认从第一条数据开始获取。

查询薪水前5名的员工select ename, sal from emp order by sal desc limit 0, 5;

查询薪水第4名到第9名的员工select ename, sal from emp order by sal desc limit 3, 6;

通用分页SQL:每页显示pageSize条记录,第pageNo页:limit (pageNo - 1) * pageSize, pageSize

12 表

12.1 创建表

建表语句的语法格式:

create table 表名( 
	字段名1 数据类型,
    字段名2 数据类型,
    字段名3 数据类型,
    ...
);

表名一般建议以t_tbl_开头。

常见的MySQL字段的数据类型:

int			整数型(对应java中的int)
bigint		长整型(对应java中的long)
float		浮点型(对应java中的float double)
char		定长字符串(对应java中的String)
varchar		可变长字符串(对应java中的StringBuffer/StringBuilder)
date		日期类型(对应java中的java.sql.date)
BLOB		二进制大对象(Binary Large Object,存储图片、视频等流媒体信息)(对应java中的Object)
CLOB 		字符大对象(Charactter Large Object,存储较大文本)(对应java中的Object)

char和varchar的选择:在开发中,当某个字段的数据长度不发生改变时,如性别、生日等,采用char;当一个字段的数据长度不确定时,例如简介、姓名等,采用varchar,varchar动态分配长度,节省空间,但不如char效率高。

创建学生表:

create table t_student(
	no bigint,
    name varchar(255),
    sex char(1),
    classno varchar(255),
    birth char(10)
);

创建表时,如果字段不赋默认值,默认为null。赋默认值的语法格式为:birth char(10) 1970-01-01

可以通过另一种方式创建表,将查询结果复制:create table 表名 as select语句

create table emp1 as select empno,ename from emp;,将表emp中的empno和ename字段复制作为一张新表emp1。

12.2 添加、修改、删除数据

12.2.1 添加数据

insert语句插入数据:insert into 表名(字段名1,字段名2,字段名3...) values(值1,值2,值3...),要求字段数量和值的数量要相同,且数据类型要对应。

添加张三的学生信息:insert into t_student(no,name,sex,classno,birth) values(1,'zhangsan','1','gaosan1ban','1990-11-12');

添加李四的学生信息:insert into t_student(name,sex,classno,birth,no) values('lisi','1','gaosan1ban','1991-03-19',2);,字段的顺序可以与表的默认顺序不同,但要和值的顺序对应。

添加王五的学生信息:insert into t_student(no,name,sex,classno) values(3,'wangwu','1','gaosan1ban');,插入部分字段时,其他字段默认为null。

添加赵六的学生信息:insert into t_student values(4,'zhaoliu','0','gaosan2ban','1991-05-06');,表明后面不加字段名时,values后面的值需要和表的默认顺序和类型一致。

一次添加多行数据,用逗号隔开:insert into t_student(no,name,sex,classno,birth) values(5,'xiaoqi','1','gaosan1ban','1991-08-12'),(6,'zhangba','0','gaosan2ban','1992-01-19');

批量添加:insert into 表名1 select * from 表名2,将一张表中select查询出的数据插入到另一张表。

12.2.2 修改数据

update语句修改数据:update 表名 set 字段名1 = 值1,字段名2 = 值2... where 条件;。不加判断条件时,更新整张表。

将学号为5的学生的班级改为gapsan2ban,生日改为1990-02-02:update t_student set classno = 'gaosan2ban',birth = '1990-02-02' where no = 5;

12.2.3 删除数据

delete语句山下湖数据:delete from 表名 where 条件。不加判断条件时,全部删除。

删除学号为6的学生数据:delete from t_student where no = 6;

删除大数据量的表中的数据:truncate table 表名;,表被截断,永久丢失,不可回滚!

13 约束

在创建表的时候,可以给表的字段添加相应的约束,目的是保证表中数据的合法性、有效性、完整性。

常见的约束:

  • 非空约束,not null,约束的字段不能为null
  • 唯一约束,unique,约束的字段不能重复
  • 主键约束,primary key,约束的字段既不能为null,也不能重复
  • 外键约束,foreign key
  • 检查约束,check(不建议使用)(Oracle支持,在mysql中还不支持)

13.1 非空约束

drop table if exists t_user;
create table t_user(
	id int,
    username varchar(255) not null,
    password varchar(255)
);
#以下代码会报错
insert into t_user(id,password) values(1,'123');
#错误信息:ERROR 1364 (HY000): Field 'username' doesn't have a default value,因为没有给username字段赋值,所以默认赋空值,而username字段要求非空
#正确写法:
insert into t_user(id,username,password) values(1,'zhangsan','123');

13.1 唯一约束

唯一约束修饰的字段具有唯一性,不可重复,但可以为null。

单个字段添加unique约束:列级约束

drop table if exists t_user;
create table t_user(
	id int,
    username varchar(255) unique
);
insert into t_user(id,username) values(1,'zhangsan');
insert into t_user(id,username) values(2,'zhangsan'); #报错:ERROR 1062 (23000): Duplicate entry 'zhangsan' for key 'username'
# 几个记录的username字段可以都为null
insert into t_user(id) values(2);
insert into t_user(id) values(3);
insert into t_user(id) values(4);

多个字段联合unique:表级约束。注意:非空约束只能加到单个字段后面,没有表级的。

drop table if exists t_user;
create table t_user(
	id int,
    usercode varchar(255),
    username varchar(255),
    unique(usercode,username)
);
#以下代码是可执行的
insert into t_user values(1,'111','zhangsan');
insert into t_user values(1,'111','lisi');
insert into t_user values(1,'222','zhangsan');

/*如果创建代码是两个字段分开unique,以下代码就会报错:ERROR 1062 (23000): Duplicate entry '111' for key 'usercode'
ERROR 1062 (23000): Duplicate entry 'zhangsan' for key 'username'*/
drop table if exists t_user;
create table t_user(
	id int,
    usercode varchar(255) unique,
    username varchar(255) unique
);
insert into t_user values(1,'111','zhangsan');
insert into t_user values(1,'111','lisi');
insert into t_user values(1,'222','zhangsan');

13.2 主键约束

主键约束:primary key,约束的字段既不能为null,也不能重复。

主键字段:被主键约束修饰的字段

主键值:主键字段的每一个值都是主键值

表的设计三范式的第一范式就要求任何一张表都应该有主键,主键值是一条记录在这张表中的唯一标识(就像人的身份证,其他信息都可以相同,但身份证号不能相同)。

注意:一张表的主键约束只能有1个!

主键的分类:

  • 根据主键字段的数量:
    • 单一主键
    • 复合主键
  • 根据主键性质:
    • 自然主键,主键值是一个和业务没有关系的自然数。
    • 业务主键,主键值和系统的业务挂钩,不推荐用,最好不要将和业务挂钩的字段作为主键,因为业务一旦发生变化,主键值可能也需要随之变化,但有时候无法变化,因为变化可能导致主键值重复,解决方法是设立自然主键,而将和业务挂钩的主键设为唯一约束。
drop table if exists t_user;
create table t_user(
	id int primary key,
    username varchar(255),
    email varchar(255)
);

insert into t_user(id,username,email) values(1,'zs','zs@123.com');
insert into t_user(id,username,email) values(2,'ls','ls@123.com');
insert into t_user(id,username,email) values(3,'ww','ww@123.com');

#报错:ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY',主键重复
insert into t_user(id,username,email) values(1,'zl','zl@123.com');
#报错:ERROR 1364 (HY000): Field 'id' doesn't have a default value,主键不能为空
insert into t_user(username,email) values('lb','lb@123.com');

mysql的主键值自增id int primary key auto_increment,id字段自动维护一个自增的数字,从1开始,以1递增。Oracle中也提供了自增机制:序列(sequence)。

13.3 外键约束

外键约束:foreign key

外键字段:添加有外键约束的字段

外键值:外键约束中的每一个值,外键值可以为null

语法格式:子表字段名x 字段类型 foreign key (x) references 父表名(父表字段名)

注意:被引用的字段不一定是主键,但至少有unique约束。

#先创建父表
drop table if exists t_classes;
create table t_classes(
	classes_id int(3),
	classes_name varchar(30) not null,
	constraint pk_classes_id primary key(classes_id) 
)
#再创建子表
drop table if exists t_student;
create table t_student(
	student_id	int(10),
	student_name 	varchar(50) not null,
	sex		char(2) not null,
	birthday	date not null,
	email		varchar(30) unique,
	classes_id	int (3) not null,
	constraint	pk_student_id	primary key(student_id),
	constraint	fk_classes_id	foreign key(classes_id) references t_classes(classes_id) 
)

14 事务

  • 事务是一个完整的业务逻辑单元,不可再分。
  • 和事务相关的语句只有数据操作语言DML语句(insert、delete、update),因为它们是和数据库表中的数据相关的。
  • 通常一个事务需要多条DML语句共同联合完成。
  • 事务的四大特性ACID:
    • 原子性(Atomicity):事务是最小的工作单元,不可再分。
    • 一致性(Consistency):事务必须保证多条DML语句同时成功或同时失败。
    • 隔离性(Isolation):事务之间具有隔离,一个事务不会影响其他事务的运行。
    • 持久性(Durability):最终数据必须持久化到硬盘中,事务才算结束。

14.1 事务的隔离级别

事务的隔离性存在隔离级别,理论上隔离级别包括4个:

  • 第一级别,读未提交(read uncommitted),允许一个事务可以看到其他事务未提交的修改。这一级别存在脏读现象(Dirty Read)现象:读到了脏的数据。
  • 第二级别,读已提交(read committed),允许一个事务只能看到其他事务已经提交的修改,未提交的修改是不可见的。解决了脏读现象。但问题是不可重复读旧数据。
  • 第三级别,可重复读(repeatable read),解决了不可重复读的问题。但问题是读取到的数据是幻象。
  • 第四级别,序列化/串行化(serializable),解决以上问题,但效率低,需要事务排队。

MySQL的默认隔离级别是可重复读,Oracle的默认隔离级别是读已提交。

14.2 演示事务

MySQL事务默认情况下是自动提交的,即只要执行任意一条DML语句,则提交一次。关闭自动提交:start transaction;

#准备表
drop table if exists t_user;
create table t_user(
	id int primary key auto_increment,
    username varchar(255)
);
#插入一条数据(默认提交)
insert into t_user(username) values('zhangsan');
#查看表
select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | zhangsan |
+----+----------+
#回滚
rollback;
#回滚之后,数据还在,因为回滚之前已默认提交
select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | zhangsan |
+----+----------+
#关闭自动提交,一个事务开启
start transaction;
#插入两条数据
insert into t_user(username) values('lisi');
insert into t_user(username) values('wangwu');
#回滚
rollback;
#查看表,还是一条数据,插入的两条数据并没有持久化到硬盘中
select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | zhangsan |
+----+----------+
#重新开启事务
start transaction;
#插入3条数据
insert into t_user(username) values('zhaoliu');
insert into t_user(username) values('xiaoqi');
insert into t_user(username) values('xiaoba');
#提交
commit;
#查看数据,4条记录
select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | zhangsan |
|  4 | zhaoliu  |
|  5 | xiaoqi   |
|  6 | xiaoba   |
+----+----------+
#提交以后已经持久化到硬盘了,再回滚查看数据,还是4条记录
rollback;
select * from t_user;
+----+----------+
| id | username |
+----+----------+
|  1 | zhangsan |
|  4 | zhaoliu  |
|  5 | xiaoqi   |
|  6 | xiaoba   |
+----+----------+

15 索引

15.1 索引原理

  • 索引相当于一本书的目录,通过目录可以快速找到对应资源。
  • 在数据库中,查询一张表有两种检索方式:全表扫描和根据索引检索(效率很高)。
  • 索引的检索效率高是因为缩小了扫描范围。
  • 索引虽然可以提高检索效率,但是不能随意的添加索引,比如表中的数据需要经常被修改时,就不适合添加索引,因为数据一旦修改,索引需要重新排序,维护成本高。

索引的实现原理:

索引底层的数据结构是B + Tree,通过B Tree缩小扫描范围,底层索引对记录进行排序和分区,索引会携带数据在表中的“物理地址”;通过索引检索到数据之后,由关联的物理地址定位到表中的数据,效率是最高的。

15.2 索引的使用

1、什么时候考虑给字段添加索引?

  • 数据量庞大。(根据客户需求和线上环境)
  • 该字段很少的DML操作。(因为字段进行修改操作后,索引也需要维护)
  • 该字段经常出现在where子句中。(经常根据哪个字段查询)
    • select ename,sal from emp where ename = 'SMITH';,当ename字段上没有添加索引的时候,以上sql语句会进行全表扫描,扫描ename字段中所有的值;当ename字段上添加索引的时候,以上sql语句会根据索引扫描,快速定位

2、创建索引的语法格式:create index 索引名 on 表名(字段名);,删除索引的语法格式:``drop index 索引名 on 表名`

3、索引的分类:

  • 单一索引:给单个字段添加索引
  • 复合索引:给多个字段联合添加一个索引
  • 主键索引:主键上会自动添加索引,所以根据主键查询效率较高
  • 唯一索引:有unique约束的字段上会自动添加索引

4、索引失效:模糊查询的时候,第一个通配符使用的是%时,索引是失效的:select ename from emp where ename like '%A%';

16 视图(了解)

1、视图是通过不同的角度看待同一张表的数据。

2、创建视图:create view 视图名 as select语句,删除视图:drop view 视图名

3、对视图进行CRUD操作,会影响到基表数据。

4、视图作用:视图可以隐藏表的实现细节。例如保密级别较高的系统,数据库只对外提供相关的视图,程序员只对视图对象进行CRUD。

17 数据库设计三范式

设计范式是设计表的依据,按照三范式设计的表不会出现数据冗余。

第一范式:任何一张表都应该有主键,并且每一个字段原子性不可再分。

第二范式:建立在第一范式的基础之上,所有非主键字段完全依赖主键,不能产生部分依赖。多对多:三张表,关系表有两个外键。

第三范式:建立在第二范式的基础之上,所有非主键字段直接依赖主键,不能产生传递依赖。一对多:两张表,多的表加外键。

提醒:在实际的开发中,以满足客户的需求为主,有时会拿冗余换执行速度。

写在最后:本笔记整理于B站——动力节点视频,感谢!

https://www.bilibili.com/video/BV1fx411X7BD?p=1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值