MySQL的事务与事务隔离
MySQL中自从引入InnoDB引擎后,在MySQL中就支持事务,事务就是一组原子性的查询语句,也即将多个查询当作一个独立的工作单元,平时通过提交工作单元来完成在事务中的相应的查询或修改,在能支持事务的数据库中必须要满足ACID测试,即事务的四个特性:
A:Atomicity,原子性(都执行或者都不执行)
C:Consistency,一致性(从一个一致性状态转到另外一个一致性状态)
I:Isolaction,隔离性(一个事务的所有修改操作在提交前对其他事务时不可见的)
D: Durability,持久性(旦事务得到提交,其所做的修改会永久有效)
而在早期默认的引擎MyISAM是不支持事务的,所以如果是在MyISAM表中是不支持事物的,想要知道数据中具体支持哪些表引擎可以通过”SHOW ENGINES;”查看在所使用版本中MySQL所支持的所有引擎。在这里先创建一张表transaction_tbl用于测试:
CREATE TABLE transaction_tbl (id int(4)) ENGINE=InnoDB;
INSERT INTO transaction_tbl VALUE (1);
INSERT INTO transaction_tbl VALUE (2);
INSERT INTO transaction_tbl VALUE (3);
INSERT INTO transaction_tbl VALUE (4);
INSERT INTO transaction_tbl VALUE (5);
在正常的使用过程中需要关闭自动提交的功能默认系统下是开启的
mysql> SHOW GLOBAL VARIABLES LIKE 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
1 row in set (0.00 sec)
在使用事务之前需要关闭,在平时使用事务之前需要先检查是否有开启autocommit,当然如果对事务的依赖比较大建议可以永久关闭全局的自动提交,但是在平时使用的过程中只要在使用时关闭自动提交,而使用手动启动事务,这样在事务中需要回滚时才能根据相关的事务隔离级别得到想要的效果,可以在使用事务时关闭autocommit,在所有的事务结束后再开启autocommit
mysql> SET GLOBAL AUTOCOMMIT=off;#当然这里也可以使用布尔值的0和1
Query OK, 0 rows affected (0.00 sec)
其中事务的控制语句也很简单,如下:
BEGIN; 或 START TRANSACTION; 显式地开启一个事务COMMIT; 提交事务即结束事务,并使已对数据库进行的所有修改为持久性的ROLLBACK; 事务回滚,会结束用户的事务并撤销正在进行的所有未提交的修改SAVEPOINT identifier; 允许在事务中创建一个保存点,一个事务中可以有多个SAVEPOINTRELEASE SAVEPOINT identifier; 删除一个事务的保存点,当没有指定的保存点时,执行该SQL语句会报异常ROLLBACK TO identifier; 把事务回滚到标记点
而在事务中的隔离级别不同,则事物的安全性就不同,但是事物得安全性越高,并发性越低,当然需要根据实际情况选择,在MySQL中事务的隔离级别有四种,安全级分别由低至高:
READ UNCOMMITTEND:读未提交
READ COMMITTEND:读提交
REPEATABLE READ :可重读
SERIALIZABLE:可串行化
查看当前使用的默认的事务隔离级别:
mysql> SHOW GLOBAL VARIABLES LIKE 'tx_isolation';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
+---------------+-----------------+
1 row in set (0.00 sec)
而在使用四个隔离级别中,所带来效果都是不相同的,此时测试需要开启2个session更为直观,在这里就用A、B来代表两个session中开启事务A、B:
mysql> SELECT * FROM transaction_tbl;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+----+
5 rows in set (0.01 sec)
一、READ UNCOMMITTEND:读未提交,顾名思义即所有的事务都可以读取到其他事务中未提交的内容,该隔离模式在平时一般都不使用,因为使用READ UNCOMMITTEND会带来脏读问题,下面就用transaction_tbl举一个简单例子说明下:
A、B中:
mysql> SET tx_isolation='READ-UNCOMMITTED';
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW VARIABLES LIKE 'tx_isolation';
+---------------+------------------+
| Variable_name | Value |
+---------------+------------------+
| tx_isolation | READ-UNCOMMITTED |
+---------------+------------------+
1 row in set (0.00 sec)
事务A中做了操作,但不提交:
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)mysql> UPDATE transaction_tbl SET id = '6' WHERE id='1';
Query OK, 1 row affected (0.02 sec)
Rows matched: 1 Changed: 1 Warnings: 0mysql> SELECT * FROM transaction_tbl;
+----+
| id |
+----+
| 6 |
| 2 |
| 3 |
| 4 |
| 5 |
+----+
5 rows in set (0.00 sec)
但是此时事务B是可以看见事务A中数据
事务B:
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)mysql> SELECT * FROM transaction_tbl;
+----+
| id |
+----+
| 6 |
| 2 |
| 3 |
| 4 |
| 5 |
+----+
5 rows in set (0.01 sec)
此时事务A回滚:
mysql> ROLLBACK;
Query OK, 0 rows affected (0.01 sec)mysql> SELECT * FROM transaction_tbl;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+----+
5 rows in set (0.00 sec)
事务B中查出来的是事务A中未提交的数据:
mysql> SELECT * FROM transaction_tbl;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+----+
5 rows in set (0.00 sec)
这样就是由READ UNCOMMITTEND所带来的脏读,一般数据库生产环境中都不用这种事务隔离级别。
二、READ COMMITTEND,读提交,同理根据名字可知事物的隔离级别会比读未提交高一个事务隔离级别更高,从而解决了脏读的问题,这也是大多数数据库中所用的默认事务隔离级别,但并不是MySQL的默认事务隔离级别,该事务隔离级别虽然解决了脏读问题,但是带来新的问题是不可重读,如果此时恰好有2个事务对相同的一张表做操作时,在一个事务中执行相同的查询时会查出不同的结果:
A、B中:
mysql> SET tx_isolation='READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)mysql> SHOW VARIABLES LIKE 'tx_isolation';
+---------------+----------------+
| Variable_name | Value |
+---------------+----------------+
| tx_isolation | READ-COMMITTED |
+---------------+----------------+
1 row in set (0.00 sec)
在事务A中:
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)mysql> SELECT * FROM transaction_tbl;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+----+
5 rows in set (0.00 sec)
此时事务B中也开启事务做了一个操作:
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)mysql> UPDATE transaction_tbl SET id = '6' WHERE id='1';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0mysql> SELECT * FROM transaction_tbl;
+----+
| id |
+----+
| 6 |
| 2 |
| 3 |
| 4 |
| 5 |
+----+
5 rows in set (0.01 sec)
此时看下事务A中的查询:
mysql> SELECT * FROM transaction_tbl;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+----+
5 rows in set (0.00 sec)
#但此时事务B中COMMIT提交后,事务A中
mysql> SELECT * FROM transaction_tbl;
+----+
| id |
+----+
| 6 |
| 2 |
| 3 |
| 4 |
| 5 |
+----+
5 rows in set (0.00 sec)
这样就是由READ COMMITTEND所带来的不可重读问题,所以在一般数据库生产环境中也不建议采用这种事务隔离级别。
三、REPEATABLE READ,可重读,同理该事务隔离级别解决了不可重读的问题,在REPEATABLE READ中使用MVCC(多版本并发控制)在每个事务启动时,InnoDB会为每个启动的事务提供一个当下时刻的快照,为实现此功能,InnoDB会为每个表提供两隐藏的字段,一个用于保存行的创建时间,一个用于保存行的失效时间,里面存储的系统版本号,MVCC旨在READ COMMITTEND和REPEATABLE READ两个事务隔离中生效,但是在REPEATABLE READ同以上事务隔离级别一样,在解决了不可重读的问题同时也带来新的问题幻读,此时恰好有2个事务对相同的一张表做操作时,在一个事务中提交之前其中一个事务在另一事务提交前后查询的结果不一样:
A、B中:
mysql> SET tx_isolation='REPEATABLE-READ';
Query OK, 0 rows affected (0.01 sec)mysql> SHOW VARIABLES LIKE 'tx_isolation';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
+---------------+-----------------+
1 row in set (0.01 sec)
事务A:
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)mysql> SELECT * FROM transaction_tbl;
+----+
| id |
+----+
| 6 |
| 2 |
| 3 |
| 4 |
| 5 |
+----+
5 rows in set (0.02 sec)
事务B中做相关操作并提交:
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)mysql> SELECT * FROM transaction_tbl;
+----+
| id |
+----+
| 6 |
| 2 |
| 3 |
| 4 |
| 5 |
+----+
5 rows in set (0.00 sec)mysql> UPDATE transaction_tbl SET id = '1' WHERE id='6';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0mysql> SELECT * FROM transaction_tbl;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+----+
5 rows in set (0.01 sec)mysql> COMMIT;
Query OK, 0 rows affected (0.02 sec)
此时再来看下事务A中:
mysql> SELECT * FROM transaction_tbl;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+----+
5 rows in set (0.02 sec)mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)mysql> SELECT * FROM transaction_tbl;
+----+
| id |
+----+
| 6 |
| 2 |
| 3 |
| 4 |
| 5 |
+----+
5 rows in set (0.00 sec)
这样就是REPEATABLE READ带来的幻读问题,当然在实际生产中这么恰好的事比较少,所以一般都做为MySQL的默认事务隔离级别。
四、SERIALIZABLE,可串行化,强事务排序也是最高级别的事务隔离,所有的事务都有使用共享锁,这样就解决相应的幻读问题,但是因为共享锁的原因从而使写入的性能降低,从而降低了MySQL的性能:
A、B中:
mysql> SET tx_isolation='SERIALIZABLE';
Query OK, 0 rows affected (0.00 sec)mysql> SHOW VARIABLES LIKE 'tx_isolation';
+---------------+--------------+
| Variable_name | Value |
+---------------+--------------+
| tx_isolation | SERIALIZABLE |
+---------------+--------------+
1 row in set (0.00 sec)
在事务A中插入一条数据不提交:
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)mysql> INSERT INTO transaction_tbl VALUE ('7');
Query OK, 1 row affected (0.00 sec)mysql> SELECT * FROM transaction_tbl;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 7 |
+----+
6 rows in set (0.00 sec)
此时在事务B中,在事务A未提交前是无法写入提交的
mysql> SHOW GLOBAL VARIABLES LIKE 'tx_isolation';
+---------------+--------------+
| Variable_name | Value |
+---------------+--------------+
| tx_isolation | SERIALIZABLE |
+---------------+--------------+
1 row in set (0.00 sec)mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)mysql> SELECT * FROM transaction_tbl;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+----+
5 rows in set (0.00 sec)mysql> UPDATE transaction_tbl SET id = '6' WHERE id='1';
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
只有在事务A中COMMIT提交后才能在事务B中做相关的写入,但是在此需要注意的是在MySQL 中都是默认都是使用REPEATABLE READ的事务隔离级别,而在平时利用事务时多用于存储过程中大量使用,而不同数据库,语法差别很大,移植困难,换了数据库,需要重新编写,所以把过多业务逻辑写在存储过程不好维护,不利于分层管理,容易混乱,一般存储过程适用于个别对性能要求较高的业务,其它的必要性不是很大,在平时使用需要根据实际情况而定。
转载于:https://blog.51cto.com/jim123/1964004
MySQL的事务与事务隔离相关推荐
- mysql选什么隔离级别_互联网项目中mysql应该选什么事务隔离级别
摘要 企业千万家,靠谱没几家. 社招选错家,亲人两行泪. 祝大家金三银四跳槽顺利! 引言 开始我们的内容,相信大家一定遇到过下面的一个面试场景 面试官:"讲讲mysql有几个事务隔离级别?& ...
- 互联网项目中MySQL应该选什么事务隔离级别
引言 开始我们的内容,相信大家一定遇到过下面的一个面试场景 面试官:"讲讲mysql有几个事务隔离级别?" 你:"读未提交,读已提交,可重复读,串行化四个!默认是可重 ...
- MySQL 中事务、事务隔离级别详解
一.事务的概念 1.事务的概念 2.在mysql中哪些存储引擎(表类型)支持事务哪些不支持 3.事务的四个属性 4.mysql事务的创建与存在周期 5.mysql行为 6.事务的隔离性和性能 7.my ...
- mysql特性举例_MySQL事务的四大特性和隔离级别
1.事务的四大特性(ACID) #### 1.1.原子性(Atomicity) 原子性是指事务包含的一系列操作要么全部成功,要么全部回滚,不存在部分成功或者部分回滚,是一个不可分割的操作整体. 1.2 ...
- mysql spring隔离级别_MySQL事务与Spring隔离级别实现
1.事务具有ACID特性 原子性(atomicity):一个事务被事务不可分割的最小工作单元,要么全部提交,要么全部失败回滚. 一致性(consistency):数据库总是从一致性状态到另一个一致性状 ...
- mysql 126_MySQL教程126-MySQL事务隔离级别
在 数据库事务的概念和特性 中介绍了 MySQL 事务的四大特性,其中事务的隔离性就是指当多个事务同时运行时,各事务之间相互隔离,不可互相干扰.如果事务没有隔离性,就容易出现脏读.不可重复读和幻读等情 ...
- MySQL深度剖析之事务隔离级别和锁机制(2021)
一 事务隔离级别和锁机制 1.1 多个事务并发修改同一条数据或者对同一条数据并发读写存在哪些事务并发问题 1.1.1 脏读(未提交读) A事务读取了别的事务还未提交的更新,而B事务是有可能回滚的. 1 ...
- MySQL 之事务 及 其隔离级别
MySQL 之事务 及 其隔离级别 /* 事务:表示一组操作(sql),要么同时成功,要么同时失败,那么这种操作就构成了一个事务. 例如: 张三 给 李四 转账 500元 (1)把张三的余额减少500 ...
- 【MySQL】MySQL的四种事务隔离级别
[MySQL]MySQL的四种事务隔离级别 本文实验的测试环境:Windows 10+cmd+MySQL5.6.36+InnoDB 一.事务的基本要素(ACID) 1.原子性(Atomicity):事 ...
最新文章
- Python杂谈——Python都能干什么呢?
- python读取txt文件并批量写入不同的excel
- BZOJ1055: [HAOI2008]玩具取名[区间DP]
- 常用JS正则匹配函数
- 为什么叫光呆公式光_光镊力学理论简析
- oracle的sql的substr用法,oracle中substr函数的用法(sqlserver right)
- leetcode959. Regions Cut By Slashes
- CCF201409试题
- 分治法 ——查找问题 —— 寻找两个等长有序序列的中位数
- [论文笔记]DistilBERT, a distilled version of BERT: smaller, faster, cheaper and lighter
- 学术会议html模板,标准的学术会议的通知模板
- opencv4.5.5的下载与环境配置
- 论软件测试工程师面试套路和暗语灵魂解密
- wordpress后台打开速度非常慢怎么办
- carte执行job任务时出现中文乱码
- Windows mobile屏幕旋转解决方案
- QQ个人文件夹保存位置无效
- LaTeX中手动修改参考文献格式
- 双十二大家都在买哪些书?这份书单请码住
- 电磁阀安装和使用事项