mysql 幻读,脏读和不可重复读

	MySQL的脏读、幻读和不可重复读是数据库事务处理中的三种常见问题,它们都涉及到数据的一致性和并发性。

事务的几大特性

  1. A(原子性 Atomicity)
原子性是指事务必须是一个原子的操作,事务中包含的各项操作在一次执行过程中,要么都发生,要么都不发生
  1. C(一致性 Consistency)
一个事务在执行之前和执行之后,数据库都必须处以一致性状态
例如:从A账户转账到B账户,不能因为程序报错或其他原因A账户扣了钱,而B账户没有增加钱
  1. I(隔离性 Isolation)
事务的隔离性是指在并发场景中,每个事务之间是互相隔离、互相独立的,一个事务的执行不能被其它事务干扰
  1. D(持久性 Durability)
事务的持久性是指事务一旦提交后,数据库中的数据必须被永久的保存下来(写入磁盘)。即使服务器系统崩溃或服务器宕机等故障。只要数据库重新启动,那么一定能够将其恢复到事务成功结束后的状态

一,脏读

脏读是指一个事务读取了另一个事务未提交的数据。这可能导致数据不一致的问题。
例如:
用户user1的初始balance是100,事务A减少了他的余额50,并进行其余的操作,但还未提交
同时
事务B正在读取user1的数据,读到他的balance为50
但是随后
可能其余的操作发生了某种错误,事务A回滚了,user1的余额现在还是100
那么事务B读到的user1的balance=50就是个脏读数据

-- 事务A
START TRANSACTION;
SELECT * FROM users WHERE id = 1; -- 假设此时用户1的balance数据为100
UPDATE users SET balance = balance - 50 WHERE id = 1;
********* 其余操作
COMMIT;
 
-- 事务B
START TRANSACTION;
SELECT * FROM users WHERE id = 1; -- 此时用户1的balance数据为50,因为事务A已经修改了数据
COMMIT;                            

解决方案:
使用事务的隔离级别来避免脏读。MySQL提供了四种隔离级别:
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE
其中,READ UNCOMMITTED是最低的隔离级别,它允许脏读;而SERIALIZABLE是最高的隔离级别,它可以避免脏读、不可重复读和幻读。在创建事务时,可以通过以下命令设置隔离级别:

 
-- 设置隔离级别为READ UNCOMMITTED
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

二,幻读

幻读是指一个事务在多次查询中返回了不一致的结果。例如,假设有两个事务C和D,C首先按照某个范围条件(如id>10 and id<20)查询了表中的数据,然后D在这个范围内插入了新的数据。当C再次查询这个范围时,它可能会发现多了一些新插入的数据。这就是幻读。
解决方案:
使用事务的隔离级别来避免幻读。与脏读类似,通过设置合适的隔离级别可以解决幻读问题。此外,还可以使用行级锁或表级锁来限制查询的范围,从而避免幻读的发生。

三,不可重复读

不可重复读是指在一个事务内,多次读取同一数据返回的结果不一致。这通常发生在一个事务内先进行了一次查询操作,然后又对该数据进行了更新操作,而另一个事务在此期间也对该数据进行了更新操作。当第一个事务再次读取该数据时,它读取到的是更新后的值,而不是初始值。这就是不可重复读。
例如:
事务A中读取user1的balance是100
同时
事务B更新的user1的balance是50,并提交成功了事务
然后
事务A又来读取user1的balance,结果是50,两次读取结果就不一致,导致了不可重复读。
解决方案:同样可以使用事务的隔离级别和行级锁来避免不可重复读。另外,MySQL还提供了一个特殊的锁——可重复读锁(Repeatable Read),它可以避免不可重复读的问题。要使用可重复读锁,可以在查询语句前加上FOR REPLICATE READ关键字

四,隔离级别

不同的隔离级别对并发问题的解决情况:

隔离级别 脏读 幻读 不可重复读 第一类丢失更新 第二类丢失更新
READ UNCOMMITED(读未提交) 允许 允许 允许 不允许 允许
READ COMMITTED(读已提交) 不允许 允许 允许 不允许 允许
REPEATABLE READ(可重复读) 不允许 允许 不允许 不允许 不允许
SERIALIZABLE (串行化) 不允许 不允许 不允许 不允许 不允许

隔离级别脏读幻读不可重复读
READ UNCOMMITED(读未提交)允许允许允许
READ COMMITTED(读已提交不允许允许允许
REPEATABLE READ(可重复读)不允许允许不允许
SERIALIZABLE (串行化)不允许不允许不允许

注意:事务的隔离级别和数据库并发性是成反比的,隔离级别越高,并发性越低。
在MySQL的InnoDB存储引擎中,REPEATABLE READ(RR)隔离级别通过多版本并发控制(MVCC)和一致性快照来实现非锁定读取,并防止幻读。

五,设置隔离级别

  1. 查看当前的用户隔离级别
select @@tx_isolation; 
  1. 修改当前登录用户的隔离级别
set session transaction isolation level read uncommitted;
  1. 修改全局的隔离级别需要使用root登录执行
set global transaction isolation level read uncommitted;

或者修改mysql.ini配置文件,在最后加上

[mysqld]
transaction-isolation = REPEATABLE-READ

其中可以选择隔离级别有:READ-UNCOMMITTED、READ-COMMITTED、 REPEATABLE-READ、SERIALIZABLE

  • 24
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值