欢迎大家来到IT世界,在知识的湖畔探索吧!
测试环境:Mysql 5.7.20-log
Base on之前的文章,由于InnoDB默认开启事务,所以每次执行sql都有事务参与,造成效率比MyISAM低很多,如果关闭了InnoDB的事务,执行会不会快很多?
查看当前数据库的事务开启状况:
关闭事务:
执行之前的存储过程
PS: 如果你不知到怎么查找已创建的存储过程,请执行以下命令:
select name from mysql.proc where db=’数据库名称’;我的为“test”,查到之前创建的存储过程为:
接下来调用已创建好的存储过程:
关闭事务后,InnoDB插入100W调数据(关闭前76m 4s左右),仅仅耗时18s左右,性能比开启事务前提升了255倍左右,比MyISAM效率还要高,究竟什么是事务?它又做了什么??
什么是事务?
事务是访问并更新数据库中各种数据项的一个程序执行单元,由一个有限的数据库操作序列构成。在事务中的操作,要么都执行修改,要么都不执行,也是事务模型区别于文件系统的重要特征之一。
事务的目的
通常认为它的存在有以下两个目的:
1. 为数据库操作序列提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。
2. 当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。
当事务被提交给了DBMS(数据库管理系统),则DBMS需要确保该事务中的所有操作都成功完成且其结果被永久保存在数据库中,如果事务中有的操作没有成功完成,则事务中的所有操作都需要被回滚,回到事务执行前的状态;同时,该事务对数据库或者其他事务的执行无影响,所有的事务都好像在独立的运行。
但在现实的情况下,失败的风险很高。在一个数据库事务的执行过程中,有可能会遇上事务操作失败、数据库系统/操作系统失败,甚至是存储介质失败等等情况。这便需要DBMS对一个执行失败的事务执行恢复操作,将其数据库状态恢复到一致状态(数据的一致性得到保证的状态)。为了实现将数据库状态恢复到一致状态的功能,DBMS通常需要维护事务日志以追踪事务中所有影响数据库数据的操作。
典型的就是银行转账问题,例如A转给B 100元,银行要进行2个操作,将A账号扣除100元,B账号增加100元,整个转账过程就构成可一个完整的事务,但若将2个步骤放在两个事务中,则可能会出现中间态(A的钱扣除了,B可能没到账)
事务的四大特性ACID
原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。
隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。
注意:在 MySQL 命令行的默认设置下,事务都是自动提交的,即执行 SQL 语句后就会马上执行 COMMIT 操作。因此要显式地开启一个事务务须使用命令 BEGIN 或 START TRANSACTION,或者执行命令 SET AUTOCOMMIT=0,用来禁止使用当前会话的自动提交。
事务控制语句:
- BEGIN或START TRANSACTION;显式地开启一个事务;
- COMMIT;也可以使用COMMIT WORK,不过二者是等价的。COMMIT会提交事务,并使已对数据库进行的所有修改成为永久性的;
- ROLLBACK;有可以使用ROLLBACK WORK,不过二者是等价的。回滚会结束用户的事务,并撤销正在进行的所有未提交的修改;
- SAVEPOINT identifier;SAVEPOINT允许在事务中创建一个保存点,一个事务中可以有多个SAVEPOINT;
- RELEASE SAVEPOINT identifier;删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;
- ROLLBACK TO identifier;把事务回滚到标记点;
- SET TRANSACTION;用来设置事务的隔离级别。InnoDB存储引擎提供事务的隔离级别有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ和SERIALIZABLE。
MYSQL 事务处理主要有两种方法:
1、用 BEGIN, ROLLBACK, COMMIT来实现
- BEGIN 开始一个事务
- ROLLBACK 事务回滚
- COMMIT 事务提交
2、直接用 SET 来改变 MySQL 的自动提交模式:
- SET AUTOCOMMIT=0 禁止自动提交
- SET AUTOCOMMIT=1 开启自动提交
事务的隔离级别
任何事务都有两面性,自然事务也不例外,例如我们在开发中经常遇到的事务并发问题:
1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
3、幻读(虚读):系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
Mysql默认事务隔离级别为 Repeatable read(可重复读)
Mysql事务隔离级别测试
创建一张表account
create table account(id int primary key auto_increment, name varchar(10) )engine='InnoDB';
欢迎大家来到IT世界,在知识的湖畔探索吧!
1.读未提交(read uncimmitted)
1>开启客户端A,开启事务A,设置Mysql事务隔离级别为read uncommitted,此时并没有插入数据,所以查询结果为空
2>开启另一个客户端窗口B,开启事务B,执行以下sql,并插入一条数据
3>此时在A窗口查询,便可以看到刚插入的数据(此时窗口B的事务并未提交)
4>若此时事务B因某种原因回滚,A事务读取的数据即为脏数据
2.读已提交(可避免脏读)
1>把事务隔离级别设置为read committed,开启事务A,查询当前表所有数据
2>在另一个客户端窗口开启事务B,设置事务隔离级别read committed,开启事务,更新一条数据,事务并没有提交
3>此时事务A再次查询表数据,发现并没有读取到事务B更新的数据,即避免了脏数据
4>此时事务B提交,此时事务A读取到的数据为
3.可重复读(可避免脏读,不可重复读,幻读或者虚读问题)
本文不再做过多演示
4.串行化
将数据库隔离级别设置为serializable
这样,你会看到左边事务A开启后,右边事务B进行插入数据的时候处于等待状态,原因为事务B一直等待事务A释放锁,所以串行化会将这个表锁定,不适合高并发的项目,开发中基本不会用到。
补充
1、事务隔离级别为读提交时,写数据只会锁住相应的行
2、事务隔离级别为可重复读时,如果检索条件有索引(包括主键索引)的时候,默认加锁方式是next-key 锁;如果检索条件没有索引,更新数据时会锁住整张表。一个间隙被事务加了锁,其他事务是不能在这个间隙插入记录的,这样可以防止幻读。
3、事务隔离级别为串行化时,读写数据都会锁住整张表
4、隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。
深层原理分析
Mysql中MVCC实现机制:MVCC是一种多版本并发控制机制。
大多数的MYSQL事务型存储引擎,如,InnoDB,Falcon以及PBXT都不使用一种简单的行锁机制.事实上,他们都和MVCC–多版本并发控制来一起使用,大家都应该知道,锁机制可以控制并发操作,但是其系统开销较大,而MVCC可以在大多数情况下代替行级锁,使用MVCC,能降低其系统开销.
重点:降低其系统开销.
MVCC是通过保存数据在某个时间点的快照来实现的. 不同存储引擎的MVCC. 不同存储引擎的MVCC实现是不同的,典型的有乐观并发控制和悲观并发控制.
由此我们引入到InnoDB中MVCC的使用:
在InnoDB,引擎中,MVCC并发控制,读操作可以分成两类:快照读 (snapshot read)与当前读 (current read)。
快照读,读取的是记录的可见版本 (有可能是历史版本),不用加锁。
当前读,读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。
快照读:简单的select操作,属于快照读,不加锁,例如:
- select * from table where ?;
当前读:特殊的读操作,插入/更新/删除操作,属于当前读,需要加锁。例如:
- select * from table where ? lock in share mode;
- select * from table where ? for update;
- insert into table values (…);
- update table set ? where ?;
- delete from table where ?;
所以,根据InnoDB的事务隔离级别,我们按照MVCC进行分析:
- Read Uncommited
- 可以读取未提交记录。此隔离级别,不会使用,忽略。
- Read Committed (RC)
- 快照读
- 当前读,RC隔离级别保证对读取到的记录加锁 (记录锁),存在幻读现象。
- Repeatable Read (RR)
- 快照读。
- 针对当前读,RR隔离级别保证对读取到的记录加锁 (记录锁),同时保证对读取的范围加锁,新的满足查询条件的记录不能够插入 (间隙锁),不存在幻读现象。
- Serializable
- 从MVCC并发控制退化为基于锁的并发控制。不区别快照读与当前读,所有的读操作均为当前读,读加读锁 (S锁),写加写锁 (X锁)。
- Serializable隔离级别下,读写冲突,因此并发度急剧下降,在MySQL/InnoDB下不建议使用。
下一篇给大家带来Mysql锁机制详解,谢谢支持与关注!
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/17455.html