本文我们将围绕一下几点进行分析
- 什么是事务?
- 为什么需要隔离性?
- 事务的隔离级别有哪几种?怎么设置?
- 隔离级别的实现原理?
一 :什么是事务?
数据库事务(简称:事务)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。—— 维基百科
说白了,数据库的事物就是由一步或几步数据库操作序列组成逻辑执行单元,这个单元要么全部成功执行,要么全部不执行。事物是在mysql引擎层面支持的,那么Mysql有哪些类型的存储引擎呢?都支持事物么?
对于>=MySQL 5.5的版本,默认的存储引擎是InnoDB。在5.5版本之前,MySQL的默认存储引擎是MyISAM。
- Innodb 支持事务
用于事务处理应用程序,具有众多特性,包括ACID事务支持。 - MyISAM 不支持事物
默认的MySQL插件式存储引擎,它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一 - Memory 不支持事物
将所有数据保存在RAM中,在需要快速查找引用和其他类似数据的环境下,可提供极快的访问。 - BDB 支持事务
可替代InnoDB的事务引擎,支持COMMIT、ROLLBACK和其他事务特性。 - 等
MySQL有多种存储引擎,每种存储引擎有各自的优缺点,可以择优选择使用
如何查看默认存储引擎的方式
查看 默认的存储引擎可以使用 show engines命令
mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine | Support | Comment | Transactions | XA | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| ARCHIVE | YES | Archive storage engine | NO | NO | NO |
| BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO |
| MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO |
| FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL |
| MyISAM | YES | MyISAM storage engine | NO | NO | NO |
| PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO |
| InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES |
| MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO |
| CSV | YES | CSV storage engine | NO | NO | NO |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
9 rows in set (0.00 sec)
- DEFAULT 表示默认使用的引擎
- YES代表这个版本的MYSQL支持的引擎
- NO代表不支持
如何查看单张表使用的存储引擎?
mysql> SELECT TABLE_SCHEMA,TABLE_NAME,TABLE_TYPE, ENGINE from information_schema.TABLES where TABLE_NAME = 'user_info';
+--------------+------------+------------+--------+
| TABLE_SCHEMA | TABLE_NAME | TABLE_TYPE | ENGINE |
+--------------+------------+------------+--------+
| olatest | user_info | BASE TABLE | InnoDB |
+--------------+------------+------------+--------+
1 row in set (0.01 sec)
如何修改MySQL的默认存储引擎
修改my.cnf,在配置文件里面
增加参数default-storage-engine,然后重启数据库服务。
修改单张表的存储引擎
mysql> ALTER TABLE user_info ENGINE = MyISAM;
Query OK, 1000001 rows affected (7.02 sec)
Records: 1000001 Duplicates: 0 Warnings: 0
mysql> SELECT TABLE_SCHEMA,TABLE_NAME,TABLE_TYPE, ENGINE from information_schema.TABLES where TABLE_NAME = 'user_info';
+--------------+------------+------------+--------+
| TABLE_SCHEMA | TABLE_NAME | TABLE_TYPE | ENGINE |
+--------------+------------+------------+--------+
| olatest | user_info | BASE TABLE | MyISAM |
+--------------+------------+------------+--------+
1 row in set (0.00 sec)
扯的有点远。。。回正题,事物ACID四大特性也是必须要了解的
- 原子性(Atomicity)
说明:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样 - 一致性(Consistency)
说明:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。 - 隔离性(Isolation)
说明:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable) - 持久性(Durability)
说明:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失
为什么事物需要隔离性?
如果事务之间不是互相隔离的,可能将会很多的问题 脏读、不可重复读、幻读
- 脏读
脏读就是A事务在处理过程中读取了B事务还未提交的数据。这种数据称之为脏数据。那个在脏数据的基础上A做的操作肯定都是脏操纵~例如:数据库中有字段 amount = 100 1.开启事物A 2.开启事物B 3.事物B 100+50 = 150 4.事物A 查询 amount = 150 脏数据 5.事物A 150+50 = 200 脏操作 6.事物B失败回滚 7.事物A提交 库中 amount = 200 脏结果
- 不可重复读
脏读就是是指一个事务范围内,多次查询某【条】数据,却得到不同的结果例如:数据库中有字段 amount = 100 1.开启事物A 2.事物A查询amount = 100 3.开启事物B 4.事物B 100+50 = 150 5.事物B 提交事物 6.事物A 再次查询amount = 150
- 幻读
脏读就是是指一个事务范围内,多次查询某【些】数据,却得到不同的数据,是比不可重复读更高级别的不可重复。不可重复读针对一条数据、幻读针对一些数据例如:数据库中有订单表 1.开启事物A 2.事物A查询订单列表有4条订单 id分别为1、2、3、4 3.开启事物B 4.事物B 插入 一条订单id = 5 5.事物B 提交事物 6.事物A查询订单列表有5条订单 id分别为1、2、3、4、5
*** 脏读与不可重复读有点懵逼?脏读 vs 不可重复读
------1.脏读是某事务读取了另外一事务未提交的数据
------2.不可重复读是读取了其他事务已经提交成功的数据
*** 不可重复读与幻读有点懵逼?不可重复读 vs 幻读
------1.不可重复读针对一条数据
------2.幻读是比不可重复读更高级别的不可重复,针对一些数据
PS:不可重复读其实是正常现象,比如我们在银行取钱的时候,显示的5000块,但是点击提现的时候,卡里的钱自己败家媳妇前几秒取走了买包了,
提示余额不足取不出来这想来也是正常~
事务的隔离级别有哪几种?怎么设置?
上面出现这问题场景,肯定是要得到解决的,那么我们就需要设置数据库的隔离级别
SQL标准定义了4种隔离级别的具体规则,用来限定事务内的哪些改变对其他事物是可见的,哪些是不可见的。
当然隔离级别越高,系统性能开销将更大
-
Read Uncommitted(读取未提交内容)
这个是最低的事务隔离级别,一个事务还没提交时,它所有的的变更就能被别的事务看到。这种情况是最不安全的,非常容易发生我们例举出来的问题
-
Read committed (读已提交)
另外一个事务不能读取该事物未提交的数据。保证一个事务提交之后,才能被别的事务读取。可避免脏读的发生,但是可能会造成不可重复读。
-
Repeatable Read(可重读)
这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。
① Serializable(串行化)
“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。
事务 100% 隔离,可避免脏读、不可重复读、幻读的发生。
但是执行效率是最低的
这 4 种隔离级别,性能依次降低,安全性依次提高
(读未提交) ------> (读已提交) ------> (可重读) ------> (串行化)
- 读未提交: 别人的事务未提交我也可以读到
- 读已提交: 别人的事务必须提交我才可以读
- 可重读 : 别人的事务提交了,我也不读
- 串行化 : 别人的事务未提交,我也改不了数据
查看并设置Mysql隔离级别
1.REPEATABLE READ:可重复读(默认)
2.READ COMMITTED:提交读
3.READ UNCOMMITTED:未提交读
4.SERIALIZABLE:串行读
注意!!!!在网上看了很多博客都是用的
select @@tx_isolation;
然后我在终端操作一直提示
mysql> select @@tx_isolation;
ERROR 1193 (HY000): Unknown system variable 'tx_isolation'
其实是因为在8.0+就已经抛弃了这样的查询方法官网有说明:
[https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html](https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html)
具体可参考下图
//最新的查看全局的事务隔离级别
//第1种方法
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
1 row in set (0.00 sec)
//第2种方法
mysql> show variables like 'transaction_isolation';
+-----------------------+-----------------+
| Variable_name | Value |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.00 sec)
设置MysQL的事务隔离级别
语法
SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL
{
REPEATABLE READ
| READ COMMITTED
| READ UNCOMMITTED
| SERIALIZABLE
}
GLOBAL:设置全局的事务隔离级别
SESSION:设置当前session的事务隔离级别,如果语句没有指定GLOBAL或SESSION,默认值为SESSION
mysql> set session transaction isolation level read uncommitted;
Query OK, 0 rows affected (0.01 sec)
mysql> show variables like 'transaction_isolation';
+-----------------------+------------------+
| Variable_name | Value |
+-----------------------+------------------+
| transaction_isolation | READ-UNCOMMITTED |
+-----------------------+------------------+
1 row in set (0.01 sec)
mysql>
Spring 事物隔离级别于Mysql隔离级别的关系?
Spring会在事务开始时,根据你程序中设置的隔离级别,调整数据库隔离级别与你的设置一致。