设为首页 收藏本站
查看: 679|回复: 0

[经验分享] Mysql之事务提交和隔离级别

[复制链接]

尚未签到

发表于 2018-10-4 15:06:20 | 显示全部楼层 |阅读模式
  Mysql之事务提交和隔离级别
  一、事务是什么?
  事务简言之就是一组SQL执行要么全部成功,要么全部失败。MYSQL的事务在存储引擎层实现。
  1、事务都有ACID特性:

  •   原子性(Atomicity):一个事务必须被视为一个不可分割的单元;
  •   一致性(Consistency):数据库总是从一种状态切换到另一种状态;
  •   隔离性(Isolation):通常来说,事务在提交前对于其他事务不可见;
  •   持久性(Durablity):一旦事务提交,所做修改永久保存数据库;
  事务最常用的例子就是银行转账。假设polo需给tom转账1000元,如下步骤:

  •   确认polo账户余额高于1000元;
  •   从polo的账户余额减去1000元;
  •   将tom的账户余额增加1000元;
mysql> create table bank_accout(uid int not null,name varchar(255),balance decimal(9,2));  
mysql> insert into bank_accout values(10001,'polo',5000),(10002,'tom',3000);
  
mysql> select * from bank_accout;
  
+-------+------+---------+
  
| uid | name| balance|
  
+-------+------+---------+
  
| 10001| polo| 5000.00|
  
| 10002| tom | 3000.00|
  
+-------+------+---------+
  SQL语句如下:
mysql> BEGIN;  
mysql> select * from bank_accout;
  
+-------+------+---------+
  
| uid | name| balance|
  
+-------+------+---------+
  
| 10001| polo| 5000.00|
  
| 10002| tom | 3000.00|
  
+-------+------+---------+
  
mysql> UPDATE bank_account SET balance=balance-1000 WHERE uid=10001;
  
mysql> UPDATE bank_account SET balance=balance+1000 WHERE uid=10002;
  
mysql> COMMIT;
  

  
mysql> select * from bank_accout;
  
+-------+------+---------+
  
| uid | name| balance|
  
+-------+------+---------+
  
| 10001| polo| 4000.00|
  
| 10002| tom | 4000.00|
  
+-------+------+---------+
mysql> BEGIN;  
或者
  
mysql> START TRANSACTION;# mysql启动事务
  

  
mysql> Rollback;  # 回滚,返回修改之前。
  
mysql> commit;  # 提交数据,才真实修改数据。
  上述步骤执行在一个事务中就能够保证数据的完整性,要么全部成功,要么全部失败。
  2、Mysql提供两种事务型引擎:
  Innodb和NDBCluster。默认采用自动提交模式,执行一条语句自动COMMIT。通过AUTOCOMMIT变量可启用或者禁用自动提交模式:
mysql> SHOW VARIABLES LIKE "AUTOCOMMIT";  
+---------------+-------+
  
| Variable_name|Value |
  
+---------------+-------+
  
| autocommit  | ON  |
  
+---------------+-------+
  
1 row in set (0.00 sec)
  

  
mysql> SET AUTOCOMMIT=1;
  

  
AUTOCOMMIT=1表示开启默认提交,0表示关闭默认提交需要手动提交。
  二、事务隔离级别
  事务隔离性的解释:通常情况下,事务在提交之前对于其他事务不可见。
  数据库有四种隔离级别,当然Mysql也是如此。分别为:

  •   READ UNCOMMITED(未提交读)
  •   READ COMMITED(已提交读)
  •   EPEATABLE READ(可重复读)
  •   SEAIALIZABLE(可串行化)
  个人理解 : 隔离级别就是决定一个事务的修改,另一个事务什么情况下可见。
  书本解释 : 隔离级别都规定了一个事务中所做修改,哪些在事务内和事务间是可见的。
  上面两段理解的区别在于是否存在事务内可见性的规定。
  开始说明Mysql的四种隔离级别,先准备一张学生表:
mysql> CREATE TABLE `student` (  
`id` int(11) NOT NULL AUTO_INCREMENT,
  
`name` varchar(32) NOT NULL DEFAULT '',
  
PRIMARY KEY (`id`)
  
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
  只有id(主键自增)与name字段
  1、READ UNCOMMITTED(未提交读)
  事务中修改没有提交对其他事务也是可见的,俗称脏读。非常不建议使用。
  例:
  客户端A和B设置隔离级别为未提交读
mysql> SET SESSION TX_ISOLATION='READ-UNCOMMITTED';  客户端A与B开启事务并查询student
mysql> BEGIN;  
mysql> SELECT * FROM student;
  
Empty set (0.00 sec)
  客户端A和B都是空数据
  客服端B插入一条新的数据
mysql> INSERT INTO student(name) VALUES("polo");  
Query OK, 1 row affected (0.00 sec)
  此时事务未提交,客服端A查看student表
mysql> SELECT * FROM student;  
+----+------+
  
| id| name|
  
+----+------+
  
| 1 | polo|
  
+----+------+
  客户端A看到B未提交的修改
  客户端B执行回滚操作
mysql> ROLLBACK;  成功之后,客户端A查看student表
mysql> SELECT * FROM student;  
Empty set (0.00 sec)
  客户端A查看数据为空
  以上可以看出未提交读隔离级别的危险性,对于一个没有提交事务所做修改对另一个事务是可见状态,容易造成脏读。非特殊情况不得使用此级别
  2、READ COMMITTED(提交读)
  多数数据库系统默认为此级别(Mysql不是)。已提交读级别即为一个事务只能已提交事务所做的修改,也就解决了未提交读的问题,即脏读的问题。
  例:
  客户端A和B设置隔离级别为已提交读
mysql> SET SESSION TX_ISOLATION='READ-COMMITTED';  客户端A与B开启事务并查询student
mysql> BEGIN;  
mysql> SELECT * FROM student;
  
Empty set (0.00 sec)
  客户端A和B都为空
  客服端B插入一条新的数据,不提交
mysql> INSERT INTO student (name) VALUES('polo');  客户端A查看student
mysql> SELECT * FROM student;  
Empty set (0.00 sec)
  注意这里与上面不同了,在客户端B没有提交事务情况下无数据
  下面客户端B提交事务
mysql> COMMIT;  客户端A再次查看student表。
mysql> select * from student;  
+----+------+
  
| id|name |
  
+----+------+
  
| 2 |polo |
  
+----+------+
  成功读取到客户
  从上面的示例可以看出,提交读没有了未提交读的问题,但我们可以看到在客户端A的一个事务中执行两次同样的SELECT语句得到不同结果,因此已提交读又被称为不可重复读。同样筛选条件可能得到不同的结果。
  3、REPEATABLE READ(可重复读)
  解决已提交读不可重复读取的问题。
  例:
  客户端A和B设置隔离级别为可重复读
mysql> SET SESSION tx_isolation='REPEATABLE-READ';  客户端A与B开启事务并查看
mysql> BEGIN;  
mysql> select * from student;
  
+----+------+
  
| id | name |
  
+----+------+
  
| 2 | polo |
  
+----+------+
  客服端B更新polo为tom,并提交事务
mysql> UPDATE student SET name='tom' WHERE id=2;  
mysql> COMMIT;
  客户端A查看student表
mysql> select * from student;  
+----+------+
  
| id| name|
  
+----+------+
  
| 2 | polo|
  
+----+------+
  注意客户端A查看数据未变,没有不可重复读问题
  客户端A提交事务,并查看student表
mysql> COMMIT;  
mysql> select * from student;
  
+----+------+
  
| id| name|
  
+----+------+
  
| 2 | tom |
  
+----+------+
  上面实例可知,可重复读两次读取内容一样。数据库这级别并没有解决幻读的问题。但是MYSQL在可重复读基础上增加了MVCC机制解决了此问题,实例无法演示幻读效果。
  什么是幻读?
  首先,可重复读锁定范围为当前查询到的内容,如执行
mysql> SELECT * FROM student WHERE id>=1  锁定的即id>=1查到的行,为行级锁。如另一事务执行并默认提交以下语句
mysql> INSERT INTO student (name) VALUES ('polo');  新增的这行并没有被锁定,此时读取student
mysql> SELECT * FROM student WHERE id>=1;  
+----+-------+
  
| id| name |
  
+----+-------+
  
| 2 | tom |
  
| 3 | polo |
  
+----+-------+
  便出现了幻读
  除了使用MYSQL的MVCC机制,还可以使用可串行化隔离级别解决此问题。
  4、SEAIALIZABLE(可串行化)
  可串行化是最高隔离级别,强制事务串行执行。执行串行了也就解决了一切的问题,这个级别只有在对数据一致性要求非常严格且没用并发的情况下使用
  例:
  客户端A和B设置隔离级别为可串行化
mysql> SET SESSION tx_isolation='SERIALIZABLE';  客户端A执行查询
mysql> BEGIN;  
mysql> SELECT * FROM student WHERE id INSERT INTO student (name) VALUES('yy');  此时我们会发现INSERT语句被阻塞执行,原因就是A执行了查询表student同时满足id

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-611952-1-1.html 上篇帖子: MySQL常用的日期SQL查询语句 下篇帖子: Centos7配置mysql主从:一主多从
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表