zl程序教程

您现在的位置是:首页 >  后端

当前栏目

事务的隔离特性与理解

事务 理解 特性 隔离
2023-09-11 14:19:34 时间

转自:https://blog.csdn.net/nbskycity/article/details/106134899

 

事务的隔离在Spring注解中使用@Transactional(isolation = Isolation.REPEATABLE_READ)来配置。

事务的隔离类型

1. REPEATABLE_READ Mysql默认

可重复读,。如果两个事务同时执行,在提交第一个事务之前,第二个事务不能更改现有记录,但是可以添加新记录。提交第二个事务后,新添加的记录将反映在仍未提交的第一个事务中。

2. READ_COMMITTED

读已提交。如果两个事务同时执行,在提交第一个事务之前,可以更改现有记录,也可以通过第二个事务更改新记录。 提交第二个事务后,新添加的记录和更新的记录也会反映在仍未提交的第一个事务中。第二个事务未提交时,第一个事务无法读取到新添加和更新的记录。

3. READ_UNCOMMITTED

读未提交。如果两个事务正在同时执行,在提交第一个事务之前,可以更改现有记录,也可以通过第二个事务更改新记录。即使未提交第二个事务,新添加的以及更新的记录也会反映在仍未提交的第一个事务中。

4. SERIALIZABLE

序列化。如果两个事务同时执行,则好像是串行执行事务,即仅第一个事务被提交,然后第二个事务被执行。这是完全隔离。因此,正在运行的事务永远不会受到其他事务的影响。但是,这可能会导致问题,因为性能会降低,并且可能发生死锁。

事务隔离级别示例中理解

现在有以下场景:智能电表上报读数,如果读数与上次读数差额较大,则处理业务逻辑与预警通知。

这种情况我们一般会使用同步来处理读数计算,如下:

 1     synchronized (Object.class) {
 2         //查询上一次读数
 3         Double lastReading = dao.selectLastReading();
 4         Double thisUseData = lastReading - thisReading;
 5         if(thisUseData <= 0) {
 6             return ;
 7         }
 8         //记录本次读数
 9         dao.save();
10     }

这个时候我们的方法会加上事务处理;假定电表上报读数会同一时间上报多条;业务逻辑用时会较长。

这个时候就会出现第二次上报读数时,查询到的上一次读数一直都是最开始的读数,并不是第一次上报的读数。

这是因为默认的事务隔离级别为REPEATABLE_READ,第一次的事务还未提交,所以第二次上报处理的时候不能获取到第一次的读数。

我们可以修改事务隔离级别为READ_UNCOMMITTED来解决。第二次处理逻辑可以读到第一次未提交的数据。但是这样可能会造成脏读,当第一次处理回滚,第二次处理计算的起始值就会不对。

事务隔离级别性质

  • 脏读-假设有两个事务-事务A和事务B同时运行。如果事务A修改了一条记录但没有提交。事务B读取该记录,但是事务A再次回滚该记录的更改并提交。因此,事务B的值有误。
  • 不可重复读取-假设两个事务-事务A和事务B同时运行。如果事务A读取某些记录。事务B在提交事务A之前先修改这些记录。因此,如果事务A再次读取这些记录,它们将是不同的。因此,相同的select语句会导致不同的现有记录。
  • 幻读-假设有两个事务-事务A和事务B同时运行。如果事务A读取某些记录。事务B在提交事务A之前添加了更多此类记录。因此,如果事务A再次读取,则记录将比前一个select语句更多。因此,相同的select语句会导致显示不同的数字记录,因为也会添加新记录。
隔离级别 脏读 不可重复读 幻读
REPEATABLE_READ 这种情况是不可能的,因为只有在提交事务后才会反映任何现有记录更改。因此,其他交易永远不会读取错误的值。 这种情况是不可能的,因为只有在提交事务后才能更改任何记录。因此,事务提交之前的多个select语句将始终返回相同的现有记录。 这种情况是可能的,因为即使没有进行第一次事务提交,其他事务也可以插入新记录。
READ_COMMITTED 这种情况是不可能的,因为只有在提交事务后才会反映任何现有记录更改。因此,其他交易永远不会读取错误的值。 这种情况是可能的,因为即使没有进行第一次事务提交,其他事务也可以修改现有记录。 这种情况是可能的,因为即使没有进行第一次事务提交,其他事务也可以插入新记录。
READ_UNCOMMITTED 这种情况是可能的,因为即使未提交第一个事务,其他事务也可以读取任何记录。因此,如果第一个事务回滚记录更改,那么其他事务将具有错误的值 由于即使未提交事务也可以更改任何记录,因此这种情况是可能的。 这种情况是可能的,因为即使未提交事务也可以插入任何记录。
SERIALIZABLE 这种情况是不可能的,因为第二个事务要在第一个事务提交后才能开始执行。他们永远不会并行执行,而只会顺序执行 这种情况是不可能的,因为第二个事务要在第一个事务提交后才能开始执行。他们永远不会并行执行,而只会顺序执行 这种情况是不可能的,因为第二个事务要在第一个事务提交后才能开始执行。他们永远不会并行执行,而只会顺序执行