zl程序教程

您现在的位置是:首页 >  数据库

当前栏目

MySQL基础篇 | 存储引擎、事务、索引、视图、DBA命令、数据库设计三范式

2023-09-14 09:14:07 时间

✅作者简介:大家好我是@每天都要敲代码,希望一起努力,一起进步!
📃个人主页:@每天都要敲代码的个人主页
🔥系列专栏:MySQL专栏

目录

一:存储引擎(了解)

1. 存储引擎的使用

2. 常见的存储引擎

二:事务(重要)

1. 概述

2. commit 与 rollback

3.事务的隔离级别

三:索引 

四:视图(了解)

五:DBA命令 (了解)

1. 数据库的导入导出

六:数据库设计三范式 (重点)


一:存储引擎(了解)

1. 存储引擎的使用

(1)数据库中的各表均被(在创建表时)指定的存储引擎来处理

(2)服务器可用的引擎依赖于以下因素:

①MySQL的版本

②服务器在开发时如何被配置

③启动选项

(3)查看一个表的建表引擎

建表的时候可以指定存储引擎,也可以指定字符集;mysql默认使用的存储引擎是InnoDB方式,默认采用的字符集是UTF8。

show create table emp; --查看建表语句

(4)完整的建表语句
  注意:在MySQL当中,凡是标识符是可以使用 飘号`` 括起来的,最好别用,不通用。

  例如:下面的t_x和id

     CREATE TABLE `t_x` (
         `id` int(11) DEFAULT NULL
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2. 常见的存储引擎

(1)什么是存储引擎呢?
存储引擎这个名字只有在mysql中存在

Oracle中有对应的机制,但是不叫做存储引擎; Oracle中叫作“表的存储方式”

mysql支持很多存储引擎,每一个存储引擎都对应了一种不同的存储方式。
每一个存储引擎都有自己的优缺点,需要在合适的时机选择合适的存储引擎。
(2)查看当前mysql支持的存储引擎?

select version();
show engines \G
-- mysql 5.5.36版本支持的存储引擎有9个

(3)常见的存储引擎 

1、MyISAM

MyISAM是mysql最常用的存储引擎,但是这种引擎不是默认的。

MyISAM这种存储引擎不支持事务!
MyISAM采用三个文件组织一张表:
①xxx.frm(存储格式的文件)
②xxx.MYD(存储表中数据的文件)
③xxx.MYI(存储表中索引的文件)

优点:可被压缩,节省存储空间,并且可以转换为只读表,提高检索效率。
缺点:不支持事务。

2、InnoDB

优点:支持事务、行级锁、外键等,这种存储引擎数据的安全得到保障。
①表的结构存储在xxx.frm文件中。
②数据存储在tablespace这样的表空间中(逻辑概念),无法被压缩,无法转换成只读。

这种InnoDB存储引擎在MySQL数据库崩溃之后提供自动恢复机制
InnoDB支持级联删除和级联更新删除过更新父表,字表也跟着删除或者更新。

3、MEMORY

优点:查询速度最快。

缺点:不支持事务;数据容易丢失。因为所有数据和索引都是存储在内存当中的,一关机就没。 以前叫做HEPA引擎

二:事务(重要)

1. 概述

(1)什么是事务(Transaction)?

一个事务是一个完整的业务逻辑单元,不可再分!

比如:银行账户转账,从A账户向B账户转账10000需要执行两条update语句: 

 以下两条DML语句必须同时成功,或者同时失败,不允许出现一条成功,一条失败;要想保证以上的两条DML语句同时成功或者同时失败,那么就需要使用数据库的“事务机制”。        

   update t_act set balance = balance - 10000 where actno = 'act-001';
   update t_act set balance = balance + 10000 where actno = 'act-002';

(2)和事务相关的语句只有:DML语句。(insert delete update)
为什么?因为它们这三个语句都是和数据库表当中的“数据”相关的。事务的存在是为了保证数据的完整性,安全性。

(3)假设所有的业务都能使用1条DML语句搞定,还需要事务机制吗?
不需要事务;但实际情况不是这样的,通常一个“事务【业务】”需要多条DML语句共同联合完成。

(4)事物的原理

假如一个事,需要先执行一条insert,执行一条update,最后执行一条delete,才算完成。

开启事物机制:无论是执行insert语句、update、delete,把这个执行记录到数据库的操作历史当中(记录到缓存),并不会向文件保存一条数据,不会真正的修改硬盘上的数据。

结束事物:提交事物或者回滚事物;提交事务会写到硬盘文件里,让文件真正发生改变;回滚事物,不会写到硬盘文件里,只会清空所有的历史记录;这样就能保持同时成功或者同时失败。

(5)事务的特性:ACID
A: 原子性(Atomicity):事务是最小的工作单元,不可再分。
C: 一致性(Consistency):事务必须保证多条DML语句同时成功或者同时失败。
I:隔离性(Isolation):事务A与事务B之间具有隔离。
D:持久性(Durability):持久性说的是最终数据必须持久化到硬盘文件中,事务才算成功的结束。

(6)关于事务之间的隔离性
事务隔离性存在隔离级别,理论上隔离级别包括4个:
第一级别:读未提交(read uncommitted)
对方事务还没有提交,我们当前事务可以读取到对方未提交的数据。
读未提交存在脏读(Dirty Read)现象:表示读到了脏的数据
第二级别:读已提交(read committed)
对方事务提交之后的数据我方可以读取到。
这种隔离级别解决了: 脏读现象没有了。
读已提交存在的问题是:不可重复读
第三级别:可重复读(repeatable read)
这种隔离级别解决了:不可重复读问题。
这种隔离级别存在的问题是:读取到的数据是幻象
第四级别:序列化读/串行化读(serializable) 
解决了所有问题。效率低;需要事务排队
oracle数据库默认的隔离级别是:读已提交。
mysql数据库默认的隔离级别是:可重复读!

2. commit 与 rollback

mysql事务默认情况下是自动提交的。
什么是自动提交?只要执行任意一条DML语句则提交一次。
怎么关闭自动提交?start transaction(开启事务)。

(1)准备表

drop table if exists t_user;
create table t_user(
    id int primary key auto_increment,
    username varchar(255)
);

(2)演示:mysql中的事务是支持自动提交的,只要执行一条DML,则提交一次

insert into t_user (username) values ('zs'); --插入数据
select * from t_user; 
rollback; --已经自动提交,我们回滚,回不去了
select * from t_user; --查询的结果和第一次查询一样

(3)演示:使用start transaction; 关闭自动提交机制

start transaction; --关闭自动回滚
insert into t_user (username) values ('lisi'); --插入数据
select * from t_user; 
rollback; --已经关闭了自动提交了,可以回滚过去
select * from t_user; -- 回滚到插入上面这条数据之前的状态

 (4)演示:手动提交

start transaction; --上面rollback事物就结束了,要重新关闭
insert into t_user (username) values ('lisi'); --插入数据
select * from t_user; 
commit; --提交
rollback; --提交过后就回滚不过去了
select * from t_user; -- 不能回滚

3.事务的隔离级别

 (1)演示读未提交(read uncommitted)

-- 登录数据库,设置事务的隔离级别
set global transaction isolation level read uncommitted; --设置事务的全局隔离级别为读未提交
select @@global.tx_isolation; -- 查看事务的全局隔离级别
-- 设置好隔离级别以后,关闭重新登录,开两个窗口
use bjpowernode; -- 使用相同的数据库
start transaction; --都关闭事务自动提交
select * from t_user; --第一个窗口查看当前t_user的数据
insert into t_user (username) values ('ww'); --第二个窗口插入这条数据
-- 注意:此时事务关闭了自动提交
select * from t_user; --第一个窗口再次查看当前t_user的数据,发现能读到未提交的,插入的ww数据

 

(2)演示读已提交(read committed)

-- 登录数据库,设置事务的隔离级别
set global transaction isolation level read committed; --设置事务的全局隔离级别为读已提交
select @@global.tx_isolation; -- 查看事务的全局隔离级别
-- 设置好隔离级别以后,关闭重新登录,开两个窗口
use bjpowernode; -- 使用相同的数据库
start transaction; --都关闭事务自动提交
select * from t_user; --第一个窗口查看当前t_user的数据
insert into t_user (username) values ('zl'); --第二个窗口插入这条数据
-- 注意:此时事务关闭了自动提交,是自动提交状态
select * from t_user; --第一个窗口再次查看当前t_user的数据,读不到插入的zl数据
commit; --第二个窗口提交
select * from t_user; 第一个窗口再次查看当前t_user的数据,就能读到插入的zl数据

 

(3)演示可重复读(repeatable read)

-- 登录数据库,设置事务的隔离级别
set global transaction isolation level repeatable read; --设置事务的全局隔离级别为可重复读
select @@global.tx_isolation; -- 查看事务的全局隔离级别

-- 设置好隔离级别以后,关闭重新登录,开两个窗口
use bjpowernode; -- 使用相同的数据库
start transaction; --都关闭事务自动提交
select * from t_user; --第一个窗口查看当前t_user的数据
delect from t_user; --第二个窗口删除这个表中的数据
commit; --并提交
select * from t_user; --第一个窗口再次查看当前t_user的数据,还是能查到,可重复读

(4)演示序列化读/串行化读(serializable)

-- 登录数据库,设置事务的隔离级别
set global transaction isolation level serializable; --设置事务的全局隔离级别为可序列化
select @@global.tx_isolation; -- 查看事务的全局隔离级别

-- 设置好隔离级别以后,关闭重新登录,开两个窗口
use bjpowernode; -- 使用相同的数据库
start transaction; --都关闭事务自动提交
select * from t_user; --第一个窗口查看当前t_user的数据,此时为空
insert into t_user (username) values ('gh'); --第一个窗口插入数据,此时不提交
select * from t_user; --第二个窗口再次查看当前t_user的数据,会卡住,等待提交后才能显示
commit; --第一个窗口提交后,第一个窗口立马就能显示数据

三:索引 

(1)什么是索引?有什么用?
索引就相当于一本书的目录,通过目录可以快速的找到对应的资源。在数据库方面,查询一张表的时候有两种检索方式:
第一种方式:全表扫描
第二种方式:根据索引检索(效率很高)

(2)索引为什么可以提高检索效率呢?
其实索引最根本的原理是缩小了扫描的范围。
索引虽然可以提高检索效率,但是不能随意的添加索引,因为索引也是数据库当中的对象,也需要数据库不断的维护;是有维护成本的。

比如:表中的数据经常被修改这样就不适合添加索引,因为数据一旦修改,索引需要重新排序,进行维护。

添加索引是给某一个字段,或者说某些字段添加索引,例如:

当ename字段上没有添加索引的时候,以上sql语句会进行全表扫描,扫描ename字段中所有的值。当ename字段上添加索引的时候,以上sql语句会根据索引扫描,快速定位!

 select ename,sal from emp where ename = 'SMITH';

(3)怎么创建索引对象?怎么删除索引对象?

创建索引对象:           

create index 索引名称 on 表名(字段名);

  删除索引对象:            

drop index 索引名称 on 表名;

(4)什么时候考虑给字段添加索引
①数据量庞大。(根据客户的需求,根据线上的环境)
②该字段很少的DML操作。(因为字段进行修改操作,索引也需要维护)
③该字段经常出现在where子句中。(经常根据哪个字段查询)

注意:主键和具有unique约束的字段自动会添加索引;根据主键查询效率较高,尽量根据主键检索。

(5)查看sql语句的执行计划,explain:       

drop table if exists t_emp;
create table t_emp as select * from emp; --创建一个t_emp表

没有索引,使用查询语句       

explain select ename,sal from t_emp where sal = 5000;


  

给薪资sal字段添加索引:

create index emp_sal_index on t_emp(sal);
explain select ename,sal from t_emp where sal = 5000;


删除索引,并再次查看

drop index emp_sal_index on t_emp;
explain select ename,sal from t_emp where sal = 5000;

(6)索引的实现原理
索引底层采用的数据结构是:B + Tree,通过B Tree缩小扫描范围,底层索引进行了排序,分区,索引会携带数据在表中的“物理地址”,最终通过索引检索到数据之后,获取到关联的物理地址,通过物理地址定位表中的数据,效率是最高的。           

select ename from emp where ename = 'SMITH';
--通过索引转换为:
select ename from emp where 物理地址 = 0x3;

(7)索引的分类
单一索引:给单个字段添加索引
复合索引: 给多个字段联合起来添加1个索引
主键索引:主键上会自动添加索引
唯一索引:有unique约束的字段上会自动添加索引

 ....

(8)索引什么时候失效      

模糊查询的时候,第一个通配符使用的是%,这个时候索引是失效的。

 select ename from emp where ename like '%A%'; --模糊查询

四:视图(了解)

(1)什么是视图
站在不同的角度去看到数据。(同一张表的数据,通过不同的角度去看待)。
视图实际上操作的还是原表的内容,不会提高检索效率!

(2)怎么创建视图?怎么删除视图? 

注意:只有DQL查询语句才能以视图对象的方式创建出来         

 create view myview as select empno,ename from emp; --创建视图
 drop view myview; --删除视图

(3)对视图进行增删改查,会影响到原表数据。(通过视图影响原表数据的,不是直接操作的原表),可以对视图进行CRUD操作。

(4)面向视图操作

通过操作视图,可以操作原数据,删除视图myview里的7369那一行数据,我们发现原表t_emp的7369数据也被删除了

创建视图:

create view myview as select * from t_emp;
select * from myview;

delete from t_emp where empno = 7369;
select * from myview;
select * from t_emp;

    

(5)视图的作用
视图可以隐藏表的实现细节。保密级别较高的系统,数据库只对外提供相关的视图,java程序员只对视图对象进行CRUD:Create(增) Retrieve(检索) Update(修改) Delete(删除)

五:DBA命令 (了解)

1. 数据库的导入导出

(1)将数据库当中的数据导出,使用mysqldump命令!

在windows的dos命令窗口中执行:(导出整个库)            

mysqldump bjpowernode>D:\bjpowernode.sql -uroot -p123
-- 导出整个bjpowernode数据库
-- 注意是退出mysql,在dos命令窗口执行,并且没有分号结尾

在windows的dos命令窗口中执行:(导出指定数据库当中的指定表)           

 mysqldump bjpowernode emp>D:\bjpowernode.sql -uroot –p123
-- 只导出bjpowernode数据库中的emp表

(2)导入数据,使用source命令   !     

mysql -uroot -p123 -- 登录mysql
create database bjpowernode; -- 创建数据库
use bjpowernode; -- 使用数据库
source D:\bjpowernode.sql -- 利用source执行sql脚本导入数据

六:数据库设计三范式 (重点)

(1)什么是设计范式
设计范式就是设计表的依据;按照这个三范式设计的表不会出现数据冗余

(2)数据库设计三范式

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

第二范式:建立在第一范式的基础之上,所有非主键字段完全依赖主键不能产生部分依赖
第三范式:建立在第二范式的基础之上,所有非主键字段直接依赖主键不能产生传递依赖
  

(3)多对多、一对多、一对一   

第一种情况:多对多;三张表、关系表两个外键         

t_student学生表
            sno(pk)        sname
            ---------------------
            1                张三
            2                李四
            3                王五

t_teacher 讲师表
            tno(pk)        tname
            ---------------------
            1                王老师
            2                张老师
            3                李老师

t_student_teacher_relation 学生讲师关系表
            id(pk)        sno(fk)        tno(fk)
            ----------------------------------
            1                1                3
            2                1                1
            3                2                2
            4                2                3
            5                3                1
            6                3                3

 第二种情况:一对多,两张表,多的表加外键     

班级t_class
            cno(pk)            cname
            --------------------------
            1                    班级1
            2                    班级2

学生t_student
            sno(pk)            sname            classno(fk)
            ---------------------------------------------
            101                张1                1
            102                张2                1
            103                张3                2
            104                张4                2
            105                张5                2

第三种情况:一对一,两种方法:主键共享、外键唯一

第一种方案:主键共享         

t_user_login  用户登录表
            id(pk)        username            password
            --------------------------------------
            1                zs                    123
            2                ls                    456

t_user_detail 用户详细信息表
            id(pk+fk)       realname            tel            
            ------------------------------------------------
            1                张三                1111111111
            2                李四                1111415621
-- id既是主键又是外键,主键表示不唯一、不能重复;
--                  外键表示数据只能来自t_user_login用户登录表的id


第二种方案:外键唯一      

t_user_login  用户登录表
            id(pk)        username            password
            --------------------------------------
            1                zs                    123
            2                ls                    456

t_user_detail 用户详细信息表
            id(pk)       realname            tel           userid(fk+unique)
            -----------------------------------------------------------
            1                张三           1111111111        2
            2                李四           1111415621        1
-- userid是外键并且唯一,外键表示数据来自t_user_login  用户登录表的id
--                      unique表示数据不能重复

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