首页 > 数据库 >mysql进阶

mysql进阶

时间:2023-01-14 22:22:07浏览次数:101  
标签:回滚 进阶 事务 查询 索引 提交 mysql

事务

 要么都成功,要么都失败

ACID

原子,一致,持久,隔离

原子性,一致性,隔离性,持久性

原子性: 要么都成功,要么都失败回滚

一致性: 事务前后的数据完整性要保证一致

持久性:事务一但提交则不可逆,被持久化到数据库

隔离性: 多个用户并发访问数据库时,数据库为每个用户开启一个事务,不能被其他事务的操作所干扰,事务要相互隔离

 

# 开启事务
START TRANSACTION;
# A 的余额 - 200 UPDATE money SET balance = balance - 200.00 WHERE name = 'A';
# B 的余额 + 200 UPDATE money SET balance = balance + 200.00 WHERE name = 'B';
#提交事务
COMMIT;
  • 原子性:要么完全提交(A余额减少200,B 的余额增加200),要么完全回滚(两个人的余额都不发生变化)
  • 一致性:这个例子的一致性体现在 200元不会因为数据库系统运行到第3行之后,第4行之前时崩溃而不翼而飞,因为事务还没有提交。
  • 隔离性:允许在一个事务中的操作语句会与其他事务的语句隔离开,比如事务A运行到第3行之后,第4行之前,此时事务B去查询A余额时,它不能看到在事务A中被减去的200元(账户钱不变),因为事务A和B是彼此隔离的。在事务A提交之前,事务B观察不到数据的改变。
  • 持久性:事务一旦提交,不能更改

隔离失败产生的问题

脏读,幻读,不可重复读,更新丢失

 

脏读:读取到了其他事务未提交的数据,导致产生了脏数据

不可重复读:在一个事务中,多次查询的数据结果不同

幻读:在一个事务中,根据同一个条件查询得到的数据个数不同

更新丢失
丢失更新就是两个不同的事务(或者Java程序线程)在某一时刻对同一数据进行读取后,先后进行修改。导致第一次操作数据丢失。

第一类丢失更新 :A,B 事务同时操作同一数据,A先对改数据进行了更改,B再次更改时失败然后回滚,把A更新的数据也回滚了。(事务撤销造成的撤销丢失)

第二类丢失更新:A,B 事务同时操作同一数据,A先对改数据进行了更改,B再次更改并且提交,把A提交的数据给覆盖了。(事务提交造成的覆盖丢失)

不可重复读和幻读的区别

不可重复读的重点是修改,幻读的重点在于新增或者删除。

怎么解决

解决方法:加锁(不建议使用,锁的粒度大),隔离级别,MVCC

加锁

1.脏读:在修改的时候添加排他锁,知道事务提交才释放,读取的时候共享锁,读完释放锁

2.不可重复读:读数据时加共享锁,写数据时加排他锁

3.幻读:加范围锁

隔离级别

有五种隔离级别:NONE(不使用事务),读未提交,读已提交,可重复读,串行化

读未提交(Read Uncommitted):最低的隔离级别,允许读取尚未提交的数据变更, 允许脏读、幻读或不可重复读。

读已提交(Read Committed):一个事务只能看到已经提交的事务所造成的改变,防止脏读,允许幻读和不可重复读

可重复读(Repeatable Read): 同一个事务的多个实例在并发读取数据时,会看到同样的数据行,mysql默认,防止脏读,不可重复读,允许幻读

串行化 (SERIALIZABLE): 最高的隔离级别,不允许读-写,写-读 的并发操作 (读-读可以),防止脏读,幻读,不可重复读

隔离级别越高,安全性越高,但是事务的并发性能越低。不建议在数据库中添加大量事务,将事务交给应用程序来控制

 添加事务

MySQL中事务隐式开启的,也就是说,一个sql语句就是一个事务,当sql语句执行完毕,事务就提交了。

C:\Users> mysql -uroot -p   #进入数据库 
Enter password: ****** #输入密码
# 查看是否开启了自动提交 autocommit为ON 表示开启了自动提交。 mysql> show variables like 'autocommit'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | autocommit | ON | +---------------+-------+ 1 row in set (0.05 sec) mysql>

显示开启

开启事务
START TRANSACTION   或者 begin
提交
commit;
回滚
ROLLBACK;
设计标记点
SAVEPOINT point_name;
回滚到标记点
ROLLBACK TO point_name

 

# mysql中是默认开启事务自动提交的
SET autocommit = 0;#关闭
SET autocommit = 1;#开启(默认)

#手动处理事务

-- 1.关闭自动提交
SET autocommit = 0;

-- 开启一个事务 START TRANSACTION   或者 begin
START TRANSACTION  

  #sql操作
  update count set money = money -100 where name ='A'; -- A-100
  
  SAVEPOINT p; -- 回滚标记
  update count set money = money +100 where name ='B'; -- B+100
commit; --提交事务
ROLLBACK ; -- 回滚
ROLLBACK TO p; -- 回滚到标记点
SET autocommit = 1; -- 恢复默认值,否则后面的sql都无法提交成功

转载自:SQL事务(非常详细) (biancheng.net)

例如,有包含如下记录的 CUSTOMERS 表:

+----+----------+-----+-----------+----------+
| ID | NAME     | AGE | ADDRESS   | SALARY   |
+----+----------+-----+-----------+----------+
|  1 | Ramesh   |  32 | Ahmedabad |  2000.00 |
|  2 | Khilan   |  25 | Delhi     |  1500.00 |
|  3 | kaushik  |  23 | Kota      |  2000.00 |
+----+----------+-----+-----------+----------+


打开一个 MySQL 命令行窗口(我们称它为 A 窗口),使用事务向表中插入两条数据:

mysql> BEGIN;
mysql> INSERT INTO CUSTOMERS (NAME, AGE, ADDRESS, SALARY) VALUES ('Chaitali', 25, 'Mumbai', 6500.00 );
mysql> INSERT INTO CUSTOMERS (NAME, AGE, ADDRESS, SALARY) VALUES ('Hardik', 27, 'Bhopal', 8500.00 );


再打开另外一个 MYSQL 命令行窗口(我们称它为 B 窗口),使用 SELECT 命令查看 CUSTOMERS 表的内容:

mysql>  SELECT * FROM CUSTOMERS;
+----+---------+-----+-----------+--------+
| id | name    | age | address   | salary |
+----+---------+-----+-----------+--------+
|  1 | Ramesh  |  32 | Ahmedabad |   2000 |
|  2 | Khilan  |  25 | Delhi     |   1500 |
|  3 | Kaushik |  23 | Kota      |   2000 |
+----+---------+-----+-----------+--------+

您看,A 窗口对表的修改并没有影响到 B 窗口,B 窗口只能查看到修改之前的内容,这说明 A 窗口的修改动作并没有立即更新到物理数据库,所以在其它会话窗口中无法看到。

在 A 窗口中提交事务:

mysql> COMMIT;

在 B 窗口中再次查看 CUSTOMERS 表的内容:

mysql>  SELECT * FROM CUSTOMERS;
+----+----------+-----+-----------+--------+
| id | name     | age | address   | salary |
+----+----------+-----+-----------+--------+
|  1 | Ramesh   |  32 | Ahmedabad |   2000 |
|  2 | Khilan   |  25 | Delhi     |   1500 |
|  3 | Kaushik  |  23 | Kota      |   2000 |
|  4 | Chaitali |  25 | Mumbai    |   6500 |
|  5 | Hardik   |  27 | Bhopal    |   8500 |
+----+----------+-----+-----------+--------+

您看,在 A 窗口提交事务以后,对表所做的修改才真正更新到物理数据库中,所以才能在其它会话窗口中查看到 A 窗口中插入的数据。

回滚事务

回滚意味着撤销尚未保存到物理数据库中的操作,具体语法格式如下:

ROLLBACK;

事务执行过程中如果发生了某种故障,事务不能继续执行,就可以撤销事务,此时对数据库的修改并不会保存到物理数据库中。撤销意味着事务结束,并且执行失败。

例如,有包含如下记录的 CUSTOMERS 表:

+----+----------+-----+-----------+--------+
| id | name     | age | address   | salary |
+----+----------+-----+-----------+--------+
|  1 | Ramesh   |  32 | Ahmedabad |   2000 |
|  2 | Khilan   |  25 | Delhi     |   1500 |
|  3 | Kaushik  |  23 | Kota      |   2000 |
|  4 | Chaitali |  25 | Mumbai    |   6500 |
|  5 | Hardik   |  27 | Bhopal    |   8500 |
+----+----------+-----+-----------+--------+


使用事务删除最后两个用户,并回滚:

mysql> BEGIN;
mysql> DELETE FROM CUSTOMERS WHERE ID=4;
mysql> DELETE FROM CUSTOMERS WHERE ID=5;
mysql> ROLLBACK;

mysql> SELECT * FROM CUSTOMERS;
+----+----------+-----+-----------+--------+
| id | name     | age | address   | salary |
+----+----------+-----+-----------+--------+
|  1 | Ramesh   |  32 | Ahmedabad |   2000 |
|  2 | Khilan   |  25 | Delhi     |   1500 |
|  3 | Kaushik  |  23 | Kota      |   2000 |
|  4 | Chaitali |  25 | Mumbai    |   6500 |
|  5 | Hardik   |  27 | Bhopal    |   8500 |
+----+----------+-----+-----------+--------+

您看,回滚事务以后,物理数据库中的数据并没有发生改变,表中的内容和事务执行之前的内容一致。

回滚标记点

ROLLBACK 命令默认回滚整个事务,也即事务中的所有修改操作都无效。但是 SQL 允许回滚事务的一部分,此时需要在事务中设置一个标记点,在该标记点之后的 SQL 语句将被回滚,之前的 SQL 语句将被成功执行。

设置标记点使用 SAVEPOINT 命令,具体语法如下:

SAVEPOINT point_name;    #point_name 为标记点名字。

回滚到标记点使用 ROLLBACK TO 命令,具体语法如下:

ROLLBACK TO point_name;

例如,有包含如下记录的 CUSTOMERS 表:

+----+----------+-----+-----------+--------+
| id | name     | age | address   | salary |
+----+----------+-----+-----------+--------+
|  1 | Ramesh   |  32 | Ahmedabad |   2000 |
|  2 | Khilan   |  25 | Delhi     |   1500 |
|  3 | Kaushik  |  23 | Kota      |   2000 |
|  4 | Chaitali |  25 | Mumbai    |   6500 |
|  5 | Hardik   |  27 | Bhopal    |   8500 |
+----+----------+-----+-----------+--------+


使用事务删除最后两个用户,并回滚到标记点:

mysql> BEGIN;
mysql> DELETE FROM CUSTOMERS WHERE ID=4;
mysql> SAVEPOINT sp;
mysql> DELETE FROM CUSTOMERS WHERE ID=5;
mysql> ROLLBACK TO sp;

mysql> SELECT * FROM CUSTOMERS;
+----+---------+-----+-----------+--------+
| id | name    | age | address   | salary |
+----+---------+-----+-----------+--------+
|  1 | Ramesh  |  32 | Ahmedabad |   2000 |
|  2 | Khilan  |  25 | Delhi     |   1500 |
|  3 | Kaushik |  23 | Kota      |   2000 |
|  5 | Hardik  |  27 | Bhopal    |   8500 |
+----+---------+-----+-----------+--------+

您看,我们回滚到标记点 sp,只有 ID 为 4 的用户被删除,ID 为 5 的用户依然留在数据库中。

索引

主键索引(PRIMARY KEY):唯一的标识,主键不可重复,数值不能为null,只能有一个列作为主键

唯一索引(UNIQUE KEY):避免重复的列数据出现,唯一索引可以有多个,数值可以为null

全文索引(FullText):通过倒序排序,快速定位元素

常规索引(INDEX,KEY):默认的

原则

  • 索引并不是越多越好
  • 不要对进程变动的数据加索引
  • 小数据量的表不需要加索引
  • 索引一般加在用来查询的字段上

EXPLAIN 

执行计划就是sql的执行查询的顺序,以及如何使用索引查询,返回的结果集的行数。

explain  sql; 查看索引

 

id

select 查询的序列号,标识执行的顺序

  • id 相同,执行顺序由上至下

  • id 不同,如果是子查询,id 的序号会递增,id 值越大优先级越高,越先被执行

 select_type

查询的类型,主要是用于区分普通查询、联合查询、子查询等。

  • SIMPLE:简单的 select 查询,查询中不包含子查询或者 union

  • PRIMARY:查询中包含子部分,最外层查询则被标记为 primary

  • SUBQUERY/MATERIALIZED:SUBQUERY 表示在 select 或 where 列表中包含了子查询,MATERIALIZED表示 where 后面 in 条件的子查询

  • UNION:表示 union 中的第二个或后面的 select 语句

  • UNION RESULT:union 的结果

 table

查询涉及到的表。

  • 直接显示表名或者表的别名

  • <unionM,N> 由 ID 为 M,N 查询 union 产生的结果

  • <subqueryN> 由 ID 为 N 查询产生的结果

type

访问类型,SQL 查询优化中一个很重要的指标,结果值从好到坏依次是:system > const > eq_ref > ref > range > index > ALL。

  • system:系统表,少量数据,往往不需要进行磁盘IO

  • const:常量连接

  • eq_ref:主键索引(primary key)或者非空唯一索引(unique not null)等值扫描

  • ref:非主键非唯一索引等值扫描

  • range:范围扫描

  • index:索引树扫描

  • ALL:全表扫描(full table scan)

possible_keys

查询过程中有可能用到的索引。

 key

实际使用的索引,如果为 NULL ,则没有使用索引。

执行计划 rows

根据表统计信息或者索引选用情况,大致估算出找到所需的记录所需要读取的行数。

 filtered

表示返回结果的行数占需读取行数的百分比, filtered 的值越大越好。

Extra

十分重要的额外信息。

  • Using filesort:MySQL 对数据使用一个外部的文件内容进行了排序,而不是按照表内的索引进行排序读取。

  • Using temporary:使用临时表保存中间结果,也就是说 MySQL 在对查询结果排序时使用了临时表,常见于order by 或 group by。

  • Using index:表示 SQL 操作中使用了覆盖索引(Covering Index),避免了访问表的数据行,效率高。

  • Using index condition:表示 SQL 操作命中了索引,但不是所有的列数据都在索引树上,还需要访问实际的行记录。

  • Using where:表示 SQL 操作使用了 where 过滤条件。

  • Select tables optimized away:基于索引优化 MIN/MAX 操作或者 MyISAM 存储引擎优化 COUNT(*) 操作,不必等到执行阶段再进行计算,查询执行计划生成的阶段即可完成优化。

  • Using join buffer (Block Nested Loop):表示 SQL 操作使用了关联查询或者子查询,且需要进行嵌套循环计算。

索引结构

CodingLabs - MySQL索引背后的数据结构及算法原理

数据库备份

保证重要数据不丢失 ,数据转移

https://blog.csdn.net/weixin_51486343/article/details/113702736

-- 导出
# mysqldump -h 主机 -u用户名 -p 密码 数据库 表名 >物理磁盘位置/文件名
mysqldump -hlocalhost -uroot -p1111 school student >D:/a.sql
# mysqldump -h 主机 -u用户名 -p 密码 数据库 表1 表2  >物理磁盘位置/文件名
mysqldump -hlocalhost -uroot -p1111 school student teacher >D:/b.sql
# mysqldump -h 主机 -u用户名 -p 密码 数据库  >物理磁盘位置/文件名
mysqldump -hlocalhost -uroot -p1111 school >D:/c.sql
-- 导入
#登入之后,切换到指定数据库 source 备份文件
source d:/a.sql

 

标签:回滚,进阶,事务,查询,索引,提交,mysql
From: https://www.cnblogs.com/zhuyilong/p/17052687.html

相关文章

  • mysql like性能优化
    网上很多优化like的方法,无非下面几种,抄来抄去的。我用213万条数据,每条数据50个字段左右(用的真实的生产环境的mysql数据库,和真实的生产环境的数据),做了性能测试;时间记录的次数......
  • mysql 处理空格数据
    mysql中有处理空格的函数,做个简单介绍:1.TRIM()函数这个函数的用法很简单,但是无法去除中间的空格--去除左右空格SELECTTRIM('fdfd');SELECTTRIM(BOTH''FROM'......
  • MySQL 高可用:mysql-mmm 部署
    基本信息和规划:#服务器信息:====================================================================ipaddresshostnameServerVersionMySql------------------......
  • Tapdata Cloud 场景通关系列:数据入湖仓之 MySQL → Doris,极简架构,更实时、更简便
    【前言】作为中国的“Fivetran/Airbyte”,TapdataCloud自去年发布云版公测以来,吸引了近万名用户的注册使用。应社区用户上生产系统的要求,TapdataCloud3.0将正式推......
  • SQL---mysql新增字段
    ALTERTABLEpeopleADDCOLUMNnameVARCHAR(100)DEFAULTNULLCOMMENT'姓名'AFTERage;  修改表people 增加字段 name  长度100 默认为null 备注:姓名......
  • SQL---mysql删除重复数据
    开发时,经常会有清理数据库中重复数据的需求,比如下面这张表report_apply :我们需要删除report_name重复的数据,具体步骤如下:--重复数据SELECTreport_namefromreport_apply......
  • MySQL高级【行级锁】
    1:行级锁1.1:介绍行级锁,每次操作锁住对应的行数据。锁定粒度最小,发生锁冲突的概率最低,并发度最高。应用在InnoDB存储引擎中。InnoDB的数据是基于索引组织的,行锁是通过对索引......
  • k8s运行mysql主从架构
    namespacemysql-ns.yamlapiVersion:v1kind:Namespacemetadata:labels:kubernetes.io/metadata.name:wgs-mysqlname:wgs-mysql创建ns#kubectlapply-fmysql-n......
  • 如何高效高性能的选择使用 MySQL 索引?
    想要实现高性能的查询,正确的使用索引是基础。本小节通过多个实际应用场景,帮助大家理解如何高效地选择和使用索引。1.独立的列独立的列,是指索引列不能是表达式的一部分,也......
  • Docker 安装mysql8
    1、获取镜像dockerpullmysql:82、创建数据卷必须创建数据卷,不然容器挂了数据就丢了dockervolumecreatemysql-data#创建dockervolumels#查看所有数据......