什么是mysql的事务

  MySQL 事务主要用于处理操作量大,复杂度高的数据。简单的说,事务就是一连串的DML的sql语句组合在一起,所以语句执行成功才算成功,如果有语句执行失败,执行就不成功 。比如说,在人员管理系统中,你删除一个人员,你即需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!

  注意:mysql只有Innodb存储引擎才支持事务。DML之的是数据库管理语句:insert, update, delete语句。

事务的特性

原子性(Atomicity):一个事务的所有操作,要么全部都完成,要么全部都不完成,不会再在中间的环节结束。如果其中一个地方发生了错误,会回滚到开始的地方,即该事务的语句一个都没有执行。

一致性(Consistency):在事务开始之前和事务结束之后,数据库的完整性没有被破坏,即修改的数据完全符合预期,例如从某个表减去一些数据,并将减去的数据加到另一表,这整个过程不会出现其他多余的数据,也不会突然减少数据。

隔离性(lsolation):数据库可以多个事务并行执行,相互之间不影响,隔离性可以放在多个事务并发执行时由于交叉执行而导致的数据不一致的问题。而隔离性的隔离效果是有等级的。在接下来回对隔离级别产生的影响和解决方法进行详述。

永久性(Durability):事务处理后,对数据的修改是永久的,即便系统故障也不会丢失。

事务的简单使用:

若要进行事务处理,必须先把MySQL的提交方式更改为手动提交,而不是自动提交。自动提交是指:MySQL的每一次语句执行就进行提交,而手动提交就是,我们可以同时执行多个语句然后一起提交。

查看提交方式:

设置提交方式:

然后我们就可以进行事务的实例训练了:

实例1:commit方式提交

mysql> select * from student;  // 事务开始前的数据
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | 老汪 | 25 |
| 2 | peilin | 20 |
| 3 | 微微 | 21 |
| 4 | 老晴 | 22 |
+----+--------+------+
4 rows in set (0.00 sec) mysql> start transaction; // 开始事务
Query OK, 0 rows affected (0.00 sec) mysql> insert into student values(5, '老个', 22); // 数据操作
Query OK, 1 row affected (0.00 sec) mysql> commit; // 事务接受,也就是提交
Query OK, 0 rows affected (0.60 sec) mysql> select * from student; // 事务介绍后的数据
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | 老汪 | 25 |
| 2 | peilin | 20 |
| 3 | 微微 | 21 |
| 4 | 老晴 | 22 |
| 5 | 老个 | 22 |
+----+--------+------+
5 rows in set (0.00 sec)

从上面看来和普通的方式没有什么区别,接下来是rollback方式进行提交:

实例2:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec) mysql> insert into student values(6, '情感', 22);
Query OK, 1 row affected (0.00 sec) mysql> rollback; // 事务回滚
Query OK, 0 rows affected (0.00 sec) mysql> select * from student; // 查询发现数据不变,没有插入
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | 老汪 | 25 |
| 2 | peilin | 20 |
| 3 | 微微 | 21 |
| 4 | 老晴 | 22 |
| 5 | 老个 | 22 |
+----+--------+------+
5 rows in set (0.00 sec)

从上面两个简单的事务可以看出:rollback提交是会将所有事务中的执行失效,回到事务开始前的状态。

注意:假如使用commit的方式提交,若事务中的sql语句有一句出错了,其他的没错,commit 提交后,除了出错的语句,其他的语句一样有效。

例如3:

mysql> select * from student;
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | 老汪 | 25 |
| 2 | peilin | 20 |
| 3 | 微微 | 21 |
| 4 | 老晴 | 22 |
| 5 | 老个 | 22 |
+----+--------+------+
5 rows in set (0.00 sec) mysql>
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec) mysql> insert into student values(7,'老人', 22);
Query OK, 1 row affected (0.00 sec) mysql> insert into student values('情感', 22); // 插入错语句
ERROR 1136 (21S01): Column count doesn't match value count at row 1
mysql> commit;
Query OK, 0 rows affected (0.00 sec) mysql> select * from student; // 事务中的语句仍然成功
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | 老汪 | 25 |
| 2 | peilin | 20 |
| 3 | 微微 | 21 |
| 4 | 老晴 | 22 |
| 5 | 老个 | 22 |
| 7 | 老人 | 22 |
+----+--------+------+
6 rows in set (0.00 sec)

注意:如果不在进行事务处理,需要把手动提交给关闭改为自动提交。

隔离性的隔离级别和可能出现的问题

隔离的级别:

读取未提交(read-uncommited):
事务A为提交的数据,事务B可以读取到,会导致脏数据
离级别最低:这一级别一般是理论上存在,数据库的一般级别都会高于该级别。
读取已提交:事务A和事务B,事务A提交的数据,事务B可以读取到。可以避免脏数据的产生。但是会导致'不可重复读取的问题'。
可重复读取:事务A和事务B,事务A提交之后的数据,事务B读取不到,事务B是可重复读取数据,这种隔离级别高于读已提交,换句话说
  ,对方提交之后的数据,我还是读取不到,这种隔离级别可以避免“不可重复读取”,达到可重复读取,比如1点和2点读到数据是同一个, MySQL默认级别,虽然可以达到可重复读取,但是会导致“幻像读”
串行化:事务A和事务B,事务A在操作数据库时,事务B只能排队等待,这种隔离级别很少使用,吞吐量太低,用户体验差,这种级别可以避免“幻像读”,每一次读取的都是数据库中真实存在数据,事务A与事务B串行,而不并发

导致的问题解释:

  1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

  2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。

  3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

  小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
事务隔离级别 脏读 不可重复读 幻读
读取未提交(read-uncommitted)
读取已提交(不可重复读取)(read-committed)
可重复读(repeatable-read)(默认)
串行化(serializable)

接下来就为大家演示一下什么是脏数据,不可重复读和幻读:

首先要对隔离级别进行设置,默认的是可重复读取:   这个数据可以在配置文件进行配置:

查看方式:

mysql> show variables like '%isolation%';
+-----------------------+-----------------+
| Variable_name | Value |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set, 1 warning (0.00 sec)

对隔离级别进行设置:

mysql> set session transaction isolation level read uncommitted;   // 对当前的事务进行设置,而不是全局  set global transaction isolation level read uncommitted; 这是全局设置
Query OK, 0 rows affected (0.00 sec) mysql> show variables like '%isolation%';
+-----------------------+------------------+
| Variable_name | Value |
+-----------------------+------------------+
| transaction_isolation | READ-UNCOMMITTED |
+-----------------------+------------------+
1 row in set, 1 warning (0.00 sec)

出现问题一,脏数据:

第一个客户端进行事务操作,但不提交:事务A

mysql> show variables like '%isolation%';
+-----------------------+------------------+
| Variable_name | Value |
+-----------------------+------------------+
| transaction_isolation | READ-UNCOMMITTED |
+-----------------------+------------------+
1 row in set, 1 warning (0.00 sec) mysql>
mysql>
mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
| 0 |
+--------------+
1 row in set (0.00 sec) mysql>
mysql>
mysql>
mysql> begin; // 事务开始
Query OK, 0 rows affected (0.00 sec) mysql> select * from student;
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | 老汪 | 25 |
| 2 | peilin | 20 |
| 3 | 微微 | 21 |
| 4 | 老晴 | 22 |
| 5 | 老个 | 22 |
| 7 | 老人 | 22 |
| 8 | 老杨 | 22 |
+----+--------+------+
7 rows in set (0.00 sec) mysql> insert into student values(9, 'wallace', 33); // 插入数据,但未提交
Query OK, 1 row affected (0.00 sec)

第二个客户端进行数据查询:客户端B

mysql> use school;
Database changed
mysql> select * from student;
+----+---------+------+
| id | name | age |
+----+---------+------+
| 1 | 老汪 | 25 |
| 2 | peilin | 20 |
| 3 | 微微 | 21 |
| 4 | 老晴 | 22 |
| 5 | 老个 | 22 |
| 7 | 老人 | 22 |
| 8 | 老杨 | 22 |
| 9 | wallace | 33 | ===>这条数据是事务A的数据,但A并未提交,B还是查询出来了,这就是脏数据。
+----+---------+------+
8 rows in set (0.00 sec)

出现问题二,不可重复读取:

一,解决脏读问题:

  客户端A,设置全局为read committed 查询数据

mysql> set global transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec) mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> select * from student; // 客户端B在事务跟新前
+----+------------+------+
| id | name | age |
+----+------------+------+
| 1 | yangyang | 25 |
| 2 | peilin | 20 |
| 3 | 微微 | 21 |
| 4 | 老晴 | 22 |
| 5 | 老个 | 22 |
| 7 | 老人 | 22 |
| 8 | 老杨 | 22 |
| 9 | wallace | 33 |
| 10 | wace | 33 |
| 11 | 老五年 | 33 |
| 12 | 老年 | 33 |
| 13 | 老大法师年 | 33 |
| 14 | aaa | 333 |
+----+------------+------+
13 rows in set (0.00 sec) mysql> select * from student; // 客户端B在事务跟新为提交之前
+----+------------+------+
| id | name | age |
+----+------------+------+
| 1 | yangyang | 25 |
| 2 | peilin | 20 |
| 3 | 微微 | 21 |
| 4 | 老晴 | 22 |
| 5 | 老个 | 22 |
| 7 | 老人 | 22 |
| 8 | 老杨 | 22 |
| 9 | wallace | 33 |
| 10 | wace | 33 |
| 11 | 老五年 | 33 |
| 12 | 老年 | 33 |
| 13 | 老大法师年 | 33 |
| 14 | aaa | 333 |
+----+------------+------+
13 rows in set (0.00 sec)

客户端B:

mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> update student set name='aixs' where id=1; // 更新B,但在A中未查询到脏数据。
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from student;
+----+------------+------+
| id | name | age |
+----+------------+------+
| 1 | aixs | 25 |
| 2 | peilin | 20 |
| 3 | 微微 | 21 |
| 4 | 老晴 | 22 |
| 5 | 老个 | 22 |
| 7 | 老人 | 22 |
| 8 | 老杨 | 22 |
| 9 | wallace | 33 |
| 10 | wace | 33 |
| 11 | 老五年 | 33 |
| 12 | 老年 | 33 |
| 13 | 老大法师年 | 33 |
| 14 | aaa | 333 |
+----+------------+------+
13 rows in set (0.00 sec)

二,不可重复读取:

对B中的事务进行提交:查询客户端A的数据,发现和之前的不一样这就是不可重复读取

mysql> select * from student;
+----+------------+------+
| id | name | age |
+----+------------+------+
| 1 | aixs | 25 | ====》变更的值
| 2 | peilin | 20 |
| 3 | 微微 | 21 |
| 4 | 老晴 | 22 |
| 5 | 老个 | 22 |
| 7 | 老人 | 22 |
| 8 | 老杨 | 22 |
| 9 | wallace | 33 |
| 10 | wace | 33 |
| 11 | 老五年 | 33 |
| 12 | 老年 | 33 |
| 13 | 老大法师年 | 33 |
| 14 | aaa | 333 |
+----+------------+------+
13 rows in set (0.00 sec)

出现问题三,幻读:

一,可重复读取: 客户端A对age更新,事务并提交

mysql> set global transaction isolation level repeatable read;
  Query OK, 0 rows affected (0.00 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> select * from student;
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | quert | 20 |
| 2 | peilin | 20 |
| 3 | 微微 | 21 |
| 4 | 老晴 | 22 |
+----+--------+------+
4 rows in set (0.00 sec) mysql> update student set age = age -5 where id =1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0 mysql> commit;
Query OK, 0 rows affected (0.00 sec) mysql> select * from student;
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | quert | 15 |
| 2 | peilin | 20 |
| 3 | 微微 | 21 |
| 4 | 老晴 | 22 |
+----+--------+------+
4 rows in set (0.00 sec)

客户端B,在事务是否提交时进行数据查询,数据都一致:

mysql> select * from student;
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | quert | 20 |
| 2 | peilin | 20 |
| 3 | 微微 | 21 |
| 4 | 老晴 | 22 |
+----+--------+------+
4 rows in set (0.00 sec) mysql> select * from student;
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | quert | 20 | ====》提交后数据仍然不变,可重复读取
| 2 | peilin | 20 |
| 3 | 微微 | 21 |
| 4 | 老晴 | 22 |
+----+--------+------+
4 rows in set (0.00 sec)

二,幻读

客户端A 进行事务,提交插入数据

mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> insert into student values(18, 'aa', 33);
Query OK, 1 row affected (0.00 sec) mysql> commit;
Query OK, 0 rows affected (0.00 sec) mysql> select * from student;
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | quert | 15 |
| 2 | peilin | 20 |
| 3 | 微微 | 21 |
| 4 | 老晴 | 22 |
| 18 | aa | 33 |
+----+--------+------+

客户端B:但是在事务B中无法查询出新增的数据,就好像什么都没有方式,这就是幻读

mysql> select * from student;
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | quert | 15 |
| 2 | peilin | 20 |
| 3 | 微微 | 21 |
| 4 | 老晴 | 22 |
+----+--------+------+
4 rows in set (0.00 sec)

四,串行化

客户端A,进行事务,但不提交

mysql> set session transaction isolation level serializable;
Query OK, 0 rows affected (0.00 sec) mysql> start transaction;
Query OK, 0 rows affected (0.00 sec) mysql> select * from account;
+------+--------+---------+
| id | name | balance |
+------+--------+---------+
| 1 | lilei | 10000 |
| 2 | hanmei | 10000 |
| 3 | lucy | 10000 |
| 4 | lily | 10000 |
+------+--------+---------+
4 rows in set (0.00 sec)

客户端B,进行事务操作,不能执行,会报错,因为是串行化,A事务必须先结束。B才可以执行。

mysql> set session transaction isolation level serializable;
Query OK, 0 rows affected (0.00 sec) mysql> start transaction;
Query OK, 0 rows affected (0.00 sec) mysql> insert into account values(5,'tom',0);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

补充:

  1、事务隔离级别为读提交时,写数据只会锁住相应的行

  2、事务隔离级别为可重复读时,如果检索条件有索引(包括主键索引)的时候,默认加锁方式是next-key 锁;如果检索条件没有索引,更新数据时会锁住整张表。一个间隙被事务加了锁,其他事务是不能在这个间隙插入记录的,这样可以防止幻读。

  3、事务隔离级别为串行化时,读写数据都会锁住整张表

   4、隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。

   5、MYSQL MVCC实现机制参考链接:https://blog.csdn.net/whoamiyang/article/details/51901888

   6、关于next-key 锁可以参考链接:https://blog.csdn.net/bigtree_3721/article/details/73731377

MySQL 基础 事务的更多相关文章

  1. mysql基础 事务的认识和使用

    事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit).事务是恢复和并发控制的基本单位. 在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或整个程序 ...

  2. MySQL基础之事务编程学习笔记

    MySQL基础之事务编程学习笔记 在学习<MySQL技术内幕:SQL编程>一书,并做了笔记.本博客内容是自己学了<MySQL技术内幕:SQL编程>事务编程一章之后,根据自己的理 ...

  3. mysql基础之-mysql锁和事务(七)

    0x01 MySQL锁: 执行操作时施加锁的模式 读锁:用户在读的时候施加的锁,为防止别人修改,但是用户可以读,还被称为共享锁 不会对其他用户进行阻塞 理解: ----->(这里的不阻塞,是可以 ...

  4. Mysql基础代码(不断完善中)

    Mysql基础代码,不断完善中~ /* 启动MySQL */ net start mysql /* 连接与断开服务器 */ mysql -h 地址 -P 端口 -u 用户名 -p 密码 /* 跳过权限 ...

  5. MYSQL基础操作

    MYSQL基础操作 [TOC] 1.基本定义 1.1.关系型数据库系统 关系型数据库系统是建立在关系模型上的数据库系统 什么是关系模型呢? 1.数据结构可以规定,同类数据结构一致,就是一个二维的表格 ...

  6. mysql 基础篇5(mysql语法---数据)

    6 增删改数据 -- ********一.增删改数据********* --- -- 1.1 增加数据 -- 插入所有字段.一定依次按顺序插入 INSERT INTO student VALUES(1 ...

  7. MySQL基础学习总结

    1.MySQL基础概念 mysql逻辑架构如下: 每个客户端连接都会在服务器中拥有一个线程,这个连接的查询只会在这个单独的线程中执行. MySQL是分层的架构.上层是服务器层的服务和查询执行引擎,下层 ...

  8. MYSQL 基础操作

    1.MySQL基础操作 一:MySQL基础操作 1:MySQL表复制 复制表结构 + 复制表数据 create table t3 like t1; --创建一个和t1一样的表,用like(表结构也一样 ...

  9. mysql基础之存储引擎

    原文:mysql基础之存储引擎 数据库对同样的数据,有着不同的存储方式和管理方式,在mysql中,称为存储引擎 常用的表的引擎 Myisam ,批量插入速度快, 不支持事务,锁表 Innodb, 批量 ...

随机推荐

  1. iOS - UILabel添加图片之富文本的简单应用

    //创建富文本 NSMutableAttributedString *attri = [[NSMutableAttributedString alloc] initWithString:@" ...

  2. day_5.10py 爬妹子图片 mm131

    #目前学的爬虫还有潭州教育的直播课,都是千篇一律的requests urllib 下面这个也是,还没有我后面的下载网易云歌单爽来都用到多线程了不过可以用协程,完全异步 1 #!/usr/bin/env ...

  3. MacTex TexStudio Configuration 配置

    在Mac上使用Latex的话主流是安装MacTex,对于IDE的选择有很多,像什么自带的TexShop,或者是TexStudio,Latexian,Texpad,Texmaker等,甚至可以直接使用一 ...

  4. Ubuntu下搭建高匿HTTP代理(亲测可用)

    功能用途 我们在生活中见过各种代理,比如我们距离火车站较远,我们可以选择通过距离最近的火车票代售点来购买火车票.又比如商品代理商,我们拿不到厂家的直接或者,可以通过厂家授权的代理经销商来获得产品.代理 ...

  5. Flask web开发之路三

    今天写一个URL传参.反转URL.页面跳转和重定向 URL传参 主app文件代码: from flask import Flask app = Flask(__name__) @app.route(' ...

  6. 泡泡一分钟:Motion Planning for a Small Aerobatic Fixed-Wing Unmanned Aerial Vehicle

    Motion Planning for a Small Aerobatic Fixed-Wing Unmanned Aerial Vehicle Joshua Levin, Aditya Paranj ...

  7. 熟悉ROS系统中的话题

    描述:这篇教程主要讲解ROS系统中的话题及rostopic和rqt_plot等命令工具: 1. Setup安装1.1 roscore 首先确保roscore已经启动运行,打开一个新的命令终端,输入如下 ...

  8. UDP,TCP的套接字编程的Python实现

    UDP,TCP的套接字编程的Python实现 套接字:连接应用层和运输层,应用层的网络应用程序使用IP地址+端口号来标识自己,然后通过套接字调用运输层为其服务,网络应用程序只能指定自己要使用的网络类型 ...

  9. en-zh(社会问题)social problems

    The world's richest man, Amazon founder Jeff Bezos, and his wife MacKenzie have agreed a record-brea ...

  10. NodeJS websocket qr based on location

    https://juejin.im/post/5a5728436fb9a01c982c7d93 http://www.cnblogs.com/panhe-xue/p/5902108.html---br ...