Mysql关于事务的几个常见概念

目录

 

一、事务

二、事务4大属性(ACID)

三、事务4种隔离级别

四、mysql事务查看与隔离级别设置

补充:InnoDB支持显示锁定:


一、事务

首先,我们要理解什么是事务?

在计算机中,事务是指访问并可能更新数据库中数据的一个独立工作单元。这个工作单元可能由一条或者多条sql语句组成,事务内的语句要么全部执行成功,要么全部执行失败,以此保证数据库中数据的完整一致性。

举个生活中比较容易理解的例子:例子中的每一条信息假设是一条sql。

1.我先去银行取款机查看卡里有多少钱

2.将身上的500元钱存进去

3.突然想起来没钱吃饭了,又取出来200元

你一定不会希望500块钱存到自助存款机了,但是账上却没多出500;银行也不会愿意取款机吐出了200元钱,账上却没扣掉200元,道理就是这么简单。

所以,如何保证最终结果正确,上面的三个步骤可以理解成一个工作单元:3个步骤必须打包成一个整体,才能保证银行卡里余额最终的正确性,要么都成功,要么都失败。

二、事务4大属性(ACID)

A:原子性    C:一致性     I:隔离性      D:持久性

1.原子性atomicity:一个事务必须被视为一个不可再分割的最小工作单元,不管是有多少个sql语句组成,要么全部成功,要么全部失败,这就是事务的原子性。

2.一致性consistency:数据库总是从一种一致性的状态转换到另外一个一致性的状态,意思就是sql所做的一系列修改,如果事务没有提交,事务中所做的修改也不会保存到数据库中。

3.隔离性isolation:一个事务所作的修改在最终提交以前,对其它的事务是不可见的。也就是说事务之间是不该互相产生干扰的。

4.持久性durabil:一旦事务提交,则其所做的修改就会永久保存到数据库中。哪怕数据库宕机了,当数据库服务重启以后,数据依然是存在的。

三、事务4种隔离级别

1.READ UNCOMMITTED:

未提交读:事务中的修改,即时没有提交,对其它的事务也都是可见的。那么,这样就容易导致一个常见的问题,就是一个事务A可能读取到另一个未提交的事务B所修改的数据,这种现象也被称为脏读。因此,实际开发中,很少使用到这种隔离级别。

2.READ COMMITTED:

提交读:大多数数据库系统的默认隔离级别都是READ COMMITTED(MySQL不是)。该级别满足了事务隔离性的特点,即一个事务从开始到提交之前,所做的任何修改对其它事务都是不可见的。但是这个级别有时候也叫不可重复读,因为两次执行同样的查询,可能会得到不一样的结果。可能在业务中第一次查询某个记录是A,然后进行其它的业务处理,业务完后你想回去再看看那条记录是否是A,结果再查询就却变成了B的这种现象。

3.REPEATABLE READ:(mysql默认的隔离级别)

可重复读:该级别解决了脏读的问题,也保证在同一个事务中多次读取同样记录的结果是一致的。但是无法解决另外一个幻读的问题。即当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前事务再次读取该范围数据的时候,会产生幻行。InnoDB和XtraDB存储引擎通过多版本并发控制(MVCC)解决了幻读的问题。

4.SERIALIZABLE:

可串行化:该级别是最高隔离级别。它的原理其实就是通过强制事务串行执行,避免了前面所说的幻读的问题。由于强制串行化执行是通过在读取的每一行数据上加锁实现的,所以很容易导致大量的超时等待和锁冲突的问题,实际应用中也很少使用该隔离级别。除非非常需要确保数据的一致性且没有并发的情况,才能使用该级别。

隔离级别 脏读可能性 不可重复的可能性 幻读可能性 加锁读
READ UNCOMMITTED YES YES YES NO
READ COMMITTED NO YES YES NO
REPEATABLE READ NO NO YES NO
SERIALIZABLE NO NO NO YES

四、mysql事务查看与隔离级别设置

1.查看是否开启事务自动提交,如果value的值是ON,则表示默认提交事务;MyISAM存储引擎或者内存表等非事务型的表不会受是否开启默认提交事务影响,其始终处于自动提交状态。InnoDB存储引擎会受到其影响。

show VARIABLES like "autocommit"

2.设置隔离级别:

先查看隔离级别:

select @@tx_isolation;

或者如下,因为版本不一样,可能有点区别

show variables like 'transaction_isolation'

再设置隔离级别:

-- 可以选择如下四种隔离级别
-- READ UNCOMMITTED
-- READ COMMITTED
-- REPEATABLE READ
-- SERIALIZABLE

set session TRANSACTION ISOLATION LEVEL READ COMMITTED

补充:InnoDB支持显式锁定:

通过select ... FOR UPDATE 来给查询显式加锁,属于悲观锁,有些业务考虑到接口幂等性,sql可以这样操作上锁,不适合并发高的业务,容易造成锁等待或锁超时。

1.首先我们有一个简单的用户表:

2.执行开启事务并查询,但不提交事务的操作;

BEGIN;

SELECT * from  `user` where id = 1 for update;

-- 先不提交事务
COMMIT;

3.执行更新语句,修改id=1的name信息;

UPDATE `user` set name = "tomupdate" where id = 1 

我们可以发现更新一直在等待中,原因就是我们在第一步查询的末尾添加了 FOR UPDATE语句且未提交事务;更新语句等待很久迟迟获取不到锁,就会报锁等待超时,提示如下截图;

4.锁超时以后,我们再执行一次更新,在锁超时以前,将查询用户的commit语句执行一下,完成事务的提交。提交以后,我们就可以发现更新语句立即更新成功,原因就是查询语句完成事务且释放了显式添加的锁。

猜你喜欢

转载自blog.csdn.net/qq_37488998/article/details/113060674