并发事务问题(脏读、不可重复读、幻读)

数据库的脏读和写脏数据是数据库事务中一个非常重要的概念。在多用户的数据库系统中,为了避免数据不一致,数据库系统需要支持事务的隔离级别。而脏读和写脏数据是隔离级别中的最低级别,意味着事务可以读取或写入未被提交的数据。

脏读(Dirty Read)

脏读是指当一个事务正在访问数据并且对其进行了修改,而这些修改还没有提交给数据库时,另外一个事务也可以访问到这个未提交的数据。如果此时第一个事务回滚了这个修改,那么第二个事务就会读到一条不正确的数据。这种现象就被称为脏读。

例如,假设有一个账户表,其中包含账户余额信息。当一个用户正在向该账户转账时,他的账户余额会被减去转账金额。此时,如果另一个用户读取该账户余额,但是转账操作尚未提交,则该用户将看到不正确的余额。

脏读是非常危险的,因为它可能会导致数据不一致。一些事务需要在多个步骤中修改数据,如果这些步骤之间没有适当的隔离,则可能会发生脏读。

写脏数据(Write Dirty Data)

写脏数据是指当一个事务正在访问数据并且对其进行了修改,但是这些修改还没有提交给数据库时,另外一个事务也可以修改同一条数据。如果此时第一个事务回滚了这个修改,那么第二个事务就会提交一个不正确的数据。这种现象就被称为写脏数据。

例如,假设有一个销售表,其中包含商品的销售信息。当一个销售员正在输入销售记录时,另一个销售员可能会同时修改同一条记录。如果这个销售员没有在第一个销售员提交之前撤回修改,则第二个销售员可能会提交不正确的记录。

写脏数据也是非常危险的,因为它可能会导致数据不一致。如果多个事务同时修改同一条数据,则需要适当地隔离它们,以确保只有一个事务可以修改该数据。

不可重复读

不可重复读指的是在同一个事务中,多次读取同一数据却得到不同结果的情况。这种情况通常发生在并发事务中,其中一个事务在读取数据的同时,另一个事务修改了同一数据。

例如,事务A读取某个行的数据,此时事务B修改了该行数据并提交,然后事务A再次读取该行数据,此时得到的数据与第一次读取的数据不同。这种情况可能会导致数据的不一致性。

解决不可重复读的方法之一是使用更高级别的隔离级别,如可重复读或序列化。

幻读

幻读指的是在同一个事务中,多次执行同一查询语句却得到不同结果的情况。这种情况通常发生在并发事务中,其中一个事务在执行查询的同时,另一个事务插入了符合查询条件的新数据。

例如,事务A执行查询语句,此时事务B插入了一些新数据并提交,然后事务A再次执行查询语句,此时得到的结果与第一次执行的结果不同。这种情况可能会导致数据的不一致性。

解决幻读的方法之一是使用更高级别的隔离级别,如序列化。

隔离级别

事务隔离级别
隔离级别 脏读 不可重复读 幻读
Read uncommitted Y Y Y
Read committed N Y Y
Repeatable Read(默认) N N Y
Serializable  N N N

为了避免脏读和写脏数据,数据库系统支持不同的隔离级别。隔离级别指定了多个事务之间的可见性和影响范围。

常见的隔离级别包括:

  • 读未提交(Read Uncommitted):事务可以读取未提交的数据,这意味着它可以看到其他事务的脏数据。
  • 读已提交(Read Committed):事务只能读取已经提交的数据,这意味着它不会看到其他事务的脏数据。但是,在同一事务内,如果一个数据被修改多次,则只会看到最新的修改。
  • 可重复读(Repeatable Read):在同一事务内,事务可以多次读取相同的数据,每次读取的数据都是一致的,即使其他事务正在修改数据。这是通过使用锁和版本控制实现的。
  • 序列化(Serializable):最高级别的隔离级别,它确保每个事务看到的数据都是其他事务提交之前的数据。这是通过使用强制锁定实现的,因此它可能会导致较高的锁冲突和降低性能。

1). 查看事务隔离级别

SELECT @@TRANSACTION_ISOLATION; 


2). 设置事务隔离级别

SET [ SESSION | GLOBAL ] TRANSACTION ISOLATION LEVEL { READ UNCOMMITTED |
READ COMMITTED | REPEATABLE READ | SERIALIZABLE }


注意:事务隔离级别越高,数据越安全,但是性能越低。

在选择隔离级别时,需要权衡数据一致性和性能。更高的隔离级别可能会增加锁竞争和降低性能,但可以提供更好的数据一致性。相反,较低的隔离级别可能会提高性能,但会牺牲一些数据一致性。

猜你喜欢

转载自blog.csdn.net/bigBbug/article/details/129984787
今日推荐