• 第九章 数据库的存储引擎


    一、MySQL存储引擎

    1.MySQL支持的存储引擎

    1.InnoDB
    2.MyISAM
    3.memory
    

    2.InnoDB和MyISAM的物理区别

    #MyISAM存储引擎文件
    -rw-rw---- 1 mysql mysql  10684 10月 19 17:09 user.frm			#表结构
    -rw-rw---- 1 mysql mysql    728 10月 23 20:02 user.MYD			#用户和密码
    -rw-rw---- 1 mysql mysql   2048 10月 27 08:51 user.MYI			#用户
    
    #InnoDB存储引擎文件
    -rw-rw---- 1 mysql mysql    8710 10月 28 19:53 city.frm			#表结构
    -rw-rw---- 1 mysql mysql 2097152 10月 28 19:54 city.ibd			#数据文件
    

    3.InnoDB存储引擎核心特性

    事务		CSR
    备份
    

    4.存储引擎相关命令

    1)查看当前存储引擎

    #查看当前所在库的存储引擎
    mysql> SELECT @@default_storage_engine;
    +--------------------------+
    | @@default_storage_engine |
    +--------------------------+
    | InnoDB                   |
    +--------------------------+
    1 row in set (0.00 sec)
    
    mysql> show variables like 'default_storage_engine';
    +------------------------+--------+
    | Variable_name          | Value  |
    +------------------------+--------+
    | default_storage_engine | InnoDB |
    +------------------------+--------+
    1 row in set (0.01 sec)
    
    #查看指定表的存储引擎
    mysql> select table_schema,table_name,engine from information_schema.tables where table_name='city';
    +--------------+------------+--------+
    | table_schema | table_name | engine |
    +--------------+------------+--------+
    | world        | city       | InnoDB |
    +--------------+------------+--------+
    1 row in set (0.00 sec)
    

    2)修改默认的存储引擎

    #在配置文件的[mysqld]标签下添加,永久设置
    [root@db01 ~]# vim /etc/my.cnf
    [mysqld]
    default-storage-engine=InnoDB
    
    #在MySQL命令行中临时设置
    SET @@storage_engine=MyISAM
    

    3)建表时指定存储引擎

    mysql> create table test4(id int) engine=myisam;
    Query OK, 0 rows affected (0.01 sec)
    

    二、企业案例一

    1.项目背景

    公司原有的架构:一个展示型的网站,LAMT,MySQL5.1.77版本(MYISAM),50M数据量
    

    1)经常出现小问题

    1.表级锁:对表中任意一行数据修改类操作时,整个表都会锁定,对其他行的操作都不能同时进行。
    2.不支持故障自动恢复(CSR):当断电时有可能会出现数据损坏或丢失的问题
    

    2)提出问题解决方案

    1.提建议将现有的MYISAM引擎替换为Innodb,将版本替换为5.6.38
    	1)如果使用MYISAM会产生”小问题”,性能安全不能得到保证,使用innodb可以解决这个问题。
    	2)5.1.77版本对于innodb引擎支持不够完善,5.6.38版本对innodb支持非常完善了。
    2.实施过程和注意要素
    

    2.实施过程

    #1.准备一台新数据库服务器
    #2.设置新数据库密码
    #3.备份旧数据库数据
    [root@db01 ~]# mysqldump -uroot -p -A > /tmp/full.sql
    [root@db01 ~]# mysqldump -uroot -p -B  -R --triggers --single-transaction --master-data=2 > /tmp/full1.sql
    #4.将数据推到远端服务器
    [root@db01 ~]# scp /tmp/full.sql 172.16.1.52:/tmp/
    #5.修改存储引擎为InnoDB
    [root@db02 ~]# sed -i 's#ENGINE=MyISAM#ENGINE=InnoDB#g' /tmp/full.sql
    #6.将数据导入新库
    [root@db02 ~]# mysql -uroot -p < /tmp/full.sql 
    Enter password:
    #7.查看新库数据的存储引擎
    #8.将业务切换到新库进行存储
    
    #9.根据binlog打点备份获取到数据迁移过程中产生的新数据,导入新库
    

    三、InnoDB存储引擎的表空间

    1.共享表空间(ibdata1)

    1)存储的内容

    1.系统数据
    2.临时表
    3.undo 日志		事务的日志 redo undo
    

    2)查看共享表空间

    mysql> show variables like '%path%';
    +-----------------------+------------------------+
    | Variable_name         | Value                  |
    +-----------------------+------------------------+
    | innodb_data_file_path | ibdata1:12M:autoextend |
    | ssl_capath            |                        |
    | ssl_crlpath           |                        |
    +-----------------------+------------------------+
    3 rows in set (0.00 sec)
    

    3)配置共享表空间

    #1.编辑配置文件
    [root@db01 ~]# vim /etc/my.cnf
    [mysqld]
    innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend
    
    #2.启动数据库报错
    [root@db01 ~]# systemctl restart mysqld.service
    #为了查看报错
    [root@db01 ~]# /etc/init.d/mysqld start
    Starting MySQL. ERROR! The server quit without updating PID file (/usr/local/mysql/data/db01.pid).
    
    #3.看日志报错
    [root@db01 ~]# less /usr/local/mysql/data/db01.err
    2020-10-29 18:10:47 16917 [ERROR] InnoDB: Data file ./ibdata1 is of a different size 4864 pages (rounded down to MB) than specified in the .cnf file 768 pages!
    
    #4.错误原因
    共享表空间ibdata1设置的结束大小与实际ibdata1大小不符合
    
    #5.解决问题
    [root@db01 ~]# vim /etc/my.cnf
    [mysqld]
    #修改ibdata1大小与数据目录下的大小一致即可
    innodb_data_file_path=ibdata1:76M;ibdata2:12M:autoextend
    
    #6.重启服务
    [root@db01 ~]# systemctl restart mysqld.service
    

    2.独立表空间

    1)查看独立表空间

    #1.物理层面查看
    [root@db01 ~]# ll /usr/local/mysql/data/xiangqin
    总用量 144
    -rw-rw---- 1 mysql mysql   8785 10月 28 19:05 user.frm
    -rw-rw---- 1 mysql mysql 131072 10月 28 19:05 user.ibd
    
    #2.数据库查看
    mysql> show variables like '%per_table%';
    +-----------------------+-------+
    | Variable_name         | Value |
    +-----------------------+-------+
    | innodb_file_per_table | ON    |
    +-----------------------+-------+
    1 row in set (0.00 sec)
    

    四、企业案例二

    在没有备份数据的情况下,突然断电导致表损坏,打不开数据库。
    

    1.模拟断电表损坏

    #1.打包某个独立表空间
    [root@db01 /usr/local/mysql/data]# tar zcf world.tar.gz world
    
    #2.将打包的文件传输到一台数据库
    [root@db01 /usr/local/mysql/data]# scp world.tar.gz 172.16.1.52:/tmp/
    
    #3.将新数据库的文件解压到新数据库的数据目录下
    [root@db02 ~]# tar xf /tmp/world.tar.gz -C /service/mysql/data/
    
    #4.新数据库查看数据
    mysql> use world;
    mysql> show tables;
    +-----------------+
    | Tables_in_world |
    +-----------------+
    | city            |
    | country         |
    | countrylanguage |
    | jixiao          |
    +-----------------+
    4 rows in set (0.00 sec)
    
    #5.操作表数据
    mysql> select * from city;
    ERROR 1146 (42S02): Table 'world.city' doesn't exist
    

    2.解决数据库表损坏的问题

    #1.找一台新的数据库重新建新表
    CREATE TABLE `city_new` (
      `ID` int(11) NOT NULL AUTO_INCREMENT,
      `Name` char(35) NOT NULL DEFAULT '',
      `CountryCode` char(3) NOT NULL DEFAULT '',
      `District` char(20) NOT NULL DEFAULT '',
      `Population` int(11) NOT NULL DEFAULT '0',
      PRIMARY KEY (`ID`),
      KEY `CountryCode` (`CountryCode`),
      KEY `index_key` (`Name`),
      KEY `idx_key` (`ID`),
      KEY `population_key` (`Population`),
      KEY `District_key` (`District`)
    ) ENGINE=InnoDB AUTO_INCREMENT=4080 DEFAULT CHARSET=latin1;
    
    #2.数据库操作city_new清除自己的表空间
    mysql> alter table city_new discard tablespace;
    
    #3.物理拷贝city的数据文件
    [root@db02 /service/mysql/data/world]# cp city.ibd city_new.ibd
    [root@db02 /service/mysql/data/world]# chown -R mysql.mysql city_new.ibd
    
    #4.city_new读取自己的表空间数据
    mysql> alter table city_new import tablespace;
    
    #5.数据查询
    mysql> select * from city_new;
    
    #6.删除损坏的表
    mysql> drop table city;
    ERROR 1051 (42S02): Unknown table 'world.city'		#只是说不认识,没说不能删除
    
    [root@db02 /service/mysql/data/world]# rm city.ibd		#物理删除表数据
    
    #7.修改表名
    mysql> alter table city_new rename city;
    

    3.恢复业务

    1.开发修改数据库连接信息
    2.将数据重新导出再导入旧机器
    

    五、InnoDB核心特性-事务

    1.什么是事务

    主要针对DML语句(update,delete,insert)
    
    1.一组数据操作执行步骤,这些步骤被视为一个工作单元:
    	1)用于对多个语句进行分组
    	2)可以在多个客户机并发访问同一个表中的数据时使用
    	
    2.所有步骤都成功或都失败
    	1)如果所有步骤正常,则执行
    	2)如果步骤出现错误或不完整,则回滚
    

    2.事务演示

    #1.创建一个表
    mysql> create table jiaoyi(id int,name varchar(10),money int);
    
    #2.插入数据
    mysql> insert jiaoyi values(1,'qiudao',300),(2,'lhd',200);
    
    #3.开启一个事务
    mysql> begin;
    mysql> update jiaoyi set money=400 where id=2;
    mysql> update jiaoyi set money=100 where id=1;
    
    #4.提交事务之前,再开一个窗口查看数据,数据没有发生改变
    mysql> select * from jiaoyi;
    +------+--------+-------+
    | id   | name   | money |
    +------+--------+-------+
    |    1 | qiudao |   300 |
    |    2 | lhd    |   200 |
    +------+--------+-------+
    2 rows in set (0.00 sec)
    
    #5.提交事务
    mysql> commit;
    
    #6.再次到新窗口查看数据
    mysql> select * from jiaoyi;
    +------+--------+-------+
    | id   | name   | money |
    +------+--------+-------+
    |    1 | qiudao |   100 |
    |    2 | lhd    |   400 |
    +------+--------+-------+
    2 rows in set (0.00 sec)
    
    #7.再次开启事务修改数据
    mysql> begin;
    mysql> update jiaoyi set money=-100 where id=1;
    mysql> update jiaoyi set money=600 where id=2;
    mysql> select * from jiaoyi;
    +------+--------+-------+
    | id   | name   | money |
    +------+--------+-------+
    |    1 | qiudao |  -100 |
    |    2 | lhd    |   600 |
    +------+--------+-------+
    2 rows in set (0.00 sec)
    
    #8.结束事务之前,由程序判断,发现money钱数不能为负数,所以这次修改数不符合逻辑,只能回滚
    mysql> rollback;
    mysql> select * from jiaoyi;
    +------+--------+-------+
    | id   | name   | money |
    +------+--------+-------+
    |    1 | qiudao |   100 |
    |    2 | lhd    |   400 |
    +------+--------+-------+
    2 rows in set (0.00 sec)
    

    3.事务的通俗理解

    伴随着“交易”出现的数据库概念。
    
    我们理解的“交易”是什么?
    	1)物与物的交换(古代)
    	2)货币现金与实物的交换(现代1)
    	3)虚拟货币与实物的交换(现代2)
    	4)虚拟货币与虚拟实物交换(现代3)
    
    数据库中的“交易”是什么?
    	1)事务又是如何保证“交易”的“和谐”?
    	2)ACID
    

    4.事务完整流程

    #成功的事务
    begin;
    sql1;
    sql2;
    ....
    commit;
    
    #失败的事务
    begin;
    sql1;
    sql2;
    ....
    rollback;
    

    5.事务的特性(ACID)

    Atomic(原子性)
    所有语句作为一个单元全部成功执行或全部取消。
    
    Consistent(一致性)
    如果数据库在事务开始时处于一致状态,则在执行该事务期间将保留一致状态。
    
    Isolated(隔离性)
    事务之间不相互影响。
    
    Durable(持久性)
    事务成功完成后,所做的所有更改都会准确地记录在数据库中。所做的更改不会丢失。
    

    6.事务的控制语句

    #事务常用的语句
    BEGIN:		开始一个新事务
    COMMIT:		永久记录当前事务所做的更改
    ROLLBACK:	回滚当前事务所做的更改
    
    #事务指定回滚
    SAVEPOINT:	分配事务过程中的一个位置,以供将来引用
    ROLLBACK TO SAVEPOINT:取消在 savepoint 之后执行的更改
    RELEASE SAVEPOINT:删除 savepoint 标识符
    
    #自动提交
    SET AUTOCOMMIT:为当前连接禁用或启用默认 autocommit 模式
    

    7.自动提交

    #临时关闭自动提交
    mysql> set autocommit=0;
    
    #永久关闭自动提交
    [root@db01 ~]# vim /etc/my.cnf
    [mysqld]
    autocommit=0
    

    8.隐式提交

    1.现在版本在开启事务时,不需要手工begin,只要你输入的是DML语句,就会自动开启事务。
    2.有些情况下事务会被隐式提交
    	1)在事务运行期间,手工执行begin的时候会自动提交上个事务
    	2)在事务运行期间,加入DDL、DCL操作会自动提交上个事务
    	3)在事务运行期间,执行锁定语句(lock tables、unlock tables)
    	
    	4)load data infile
    	5)select for update
    
  • 相关阅读:
    Grails笔记二:grails 2.4.3版本下generate-*失效问题解析
    java常量池中基本数据类型包装类的小陷阱
    Mysql中使用聚合函数对null值的处理
    集合框架
    List的三个子类ArrayList,LinkedList,Vector之面试题
    String类面试题2
    String类常见面试题1
    常见对象之String类
    Scanner的概述和方法介绍
    Java开发工具(Eclipse工作空间的基本配置)
  • 原文地址:https://www.cnblogs.com/jhno1/p/13902151.html
Copyright © 2020-2023  润新知