mybatis 源码系列(七) Java基础之数据库事务隔离级别

本文详细探讨了数据库事务的ACID特性,重点解析了四种事务隔离级别:READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ和SERIALIZABLE,通过实例解释了脏读、不可重复读和幻读的概念。文章还讨论了mybatis中如何维护事务隔离级别,并建议读者阅读英文官方文档以深化理解。
摘要由CSDN通过智能技术生成

更多mybatis 源码系列文章可关注我的博客,点击前往

正确设置数据库的事务访问级别,有助于我们的应用程序达到预期的效果

在mybatis中,提供了事务隔离级别的枚举类:org.apache.ibatis.session.TransactionIsolationLevel.java

来看具体代码:

/**
 * @author Clinton Begin
 */
public enum TransactionIsolationLevel {
   
  NONE(Connection.TRANSACTION_NONE),
  READ_COMMITTED(Connection.TRANSACTION_READ_COMMITTED),
  READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED),
  REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ),
  SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE);

  private final int level;

  private TransactionIsolationLevel(int level) {
   
    this.level = level;
  }

  public int getLevel() {
   
    return level;
  }
}

从代码中,我们看到,mybatis维护了一份Connection连接的事务隔离级别枚举类,作用仅仅是简化变量,方便程序调用.

那么,其中几个事务隔离级别具体代表什么意思呢?

英文名称 中文说明
READ_COMMITTED 禁止脏读,允许不可重复读和幻读,此级别仅禁止事务读取具有未提交更改的行。 2
READ_UNCOMMITTED 允许脏读,不可重复读和幻读,此级别允许在提交该行中的任何更改(“脏读”)之前,由另一个事务读取由一个事务更改的行,如果回滚任何更改,则第二个事务将检索到无效行。 1
REPEATABLE_READ 禁止脏读和不可重复读,允许幻读,此级别禁止事务读取具有未提交更改的行,并且还禁止一个事务读取行,第二个事务更改行,第一个事务重新读取行,第二次获取不同值的情况( “不可重复读”)。 4
SERIALIZABLE 事务最高隔离级别,禁止脏读、幻读和不可重复读 8

看了Java中JDK的注释,我们首先需要明白何为脏读、不可重复读及幻读

何为事务

在理解事务隔离级别之前,我们需要知道事务是什么,有什么作用?

当应用程序被许多用户访问获取数据信息时,或者一个用户发出了多次请求时,为使用户获取的数据是完整的是非常重要的事情,而如何保证数据完整性在数据库中称为事务

为确保数据完整性,事务需要遵循四个条件:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability),也就是我们通常所说的ACID

可以查阅mariadb的数据库理论文档,充分了解事务

题外话,最近在写博客温习这些知识的期间,有些不明白的还是会在网上查询资料,加深自己的理解,但我发现国内的很多篇幅都介绍的很片面,所以我建议大家都读英文文章,特别是官方文档,就算是一个单词一个单词的啃,对自己理解这个知识点会深刻许多,再结合自己工作中学到的,会事半功倍.

原子性(Atomicity)

我们都知道,原子是原子是元素中的最小单元

那么在事务中,我们把他理解为一个操作要么成功,要么失败,除了这两种,没有其他情况发生.

原子性意味着整个交易必须完成。如果不是这种情况,则中止整个事务。 这可确保数据库永远不会留下部分完成的事务,从而导致数据完整性不佳。

例如,如果您从一个银行帐户中删除资金,但第二个请求失败且系统无法将资金存入另一个银行,则两个请求都必须失败。 这笔钱不能简单地丢失,也不能从一个帐户中取出而不会进入另一个帐户。

一致性(Consistency)

一致性是指满足某些条件时数据所处的状态。

这个我认为需要结合应用程序来说,因为数据库中的数据状态的变更,都是由我们的应用程序来修改的,数据状态从一个状态变为另外一个状态,这其中的过程是不可见的

通过满足我们的业务需求条件,最终将数据的状态设置为我们的认为正确的状态,这就是数据一致性

一致性是目的(我们希望看到的数据状态),而AID是手段

隔离性(Isolation)

隔离意味着在第一个事务完成之前,另一个事务不能使用在处理一个事务期间使用的任何数据。

例如,如果两个人将100美元存入另一个账户,余额为900美元,则第一笔交易必须加100美元至900美元,第二笔交易必须加100美元至1000美元。 如果第二笔交易在第一笔交易完成前读取900美元,那么这两笔交易似乎都会成功,但100美元将会丢失。 第二个事务必须等到它一个人访问数据。

也就是事务之间是相互隔离的

通过上面的例子,我们也有所了解到隔离性也是确保我们的数据状态的一致

持久性(Durability)

持久性是指一旦事务中的数据被提交,即使系统出现故障,其影响也将保持不变。 当交易正在进行时,效果并不持久。 如果数据库崩溃,备份将始终在事务开始之前将其还原到一致状态。 交易没有什么能够改变这个事实。

我所理解的是事务持久性即事务一旦提交,那么所影响的记录行会持久化保存在我们的磁盘上,及时业务系统崩溃,也不会影响我们的数据(如果你说磁盘蹦了那我也只能漏出尴尬而不失礼貌的微笑了)

事务隔离级别

为了得到更详细的说明,我查看了mariadb的官方文档介绍

READ UNCOMMITTED(读取未提交)

SELECT语句以非锁定方式执行,但可能会使用行的早期版本。因此,使用此隔离级别,会导致非一致性.也叫"脏读",就好像读取到了未提交的行一样.

READ COMMITTED(读取提交)

读取提交内容,关于一致性(非锁定)读取的类似Oracle的隔离级别:即使在同一事务中,每个一致性读取使之读取到的内容都是自己的新快照

对于锁定读取(SELECT FOR FOR UPDATE或LOCK IN SHARE MODE),InnoDB仅锁定索引记录,允许在锁定记录旁边自由插入新记录,对于UPDATE和DELETE语句,锁定取决于语句是使用具有唯一搜索条件的唯一索引(例如WHERE id = 100)还是范围类型搜索条件(例如WHERE id> 100)。对于具有唯一搜索条件的唯一索引,InnoDB仅锁定找到的索引记录,而不是之前的间隙。对于范围类型搜索,InnoDB使用间隙锁或下一键(间隙加索引记录)锁来锁定扫描的索引范围,以阻止其他会话插入范围所涵盖的间隙。这是必要的,因为必须阻止“幻像行”才能使MySQL复制和恢复正常工作

REPEATABLE READ(可重读)

这是InnoDB存储引擎的默认事务隔离级别,关于一致性读取,这和READ COMMITTED事务隔离级别有很大的不同,同一事务中的所有一致读取读取第一次读取建立的快照。此约定意味着如果在同一事务中发出多个普通(非锁定)SELECT语句,则这些SELECT语句也相互一致

使用锁读取的SELECT语句(FOR UPDATE或LOCK IN SHARE MODE ),UPDATE和DELETE语句,锁定取决于语句是否使用具有唯一搜索条件的唯一索引,或范围类型的搜索条件。对于具有唯一搜索条件的唯一索引,InnoDB仅锁定找到的索引记录,而不是之前的间隙。对于其他搜索条件,InnoDB使用间隙锁或下一键(间隙加索引记录)锁来锁定扫描的索引范围,以阻止其他会话插入范围所覆盖的间隙。

这对于并发操作数据库数据获取的数据一致性是有很大的帮助.

SERIALIZABLE(可串行化)

这个级别就像REPEATABLE READ,但InnoDB隐式地将所有普通SELECT语句转换为SELECT lock …如果禁用自动提交,则锁定共享模式。

如果启用了自动提交,则SELECT是其自己的事务。因此,已知它是只读的,并且如果作为一致(非锁定)读取执行则可以序列化,并且不需要阻止其他事务。(这意味着如果其他事务已修改所选行,则强制普通SELECT阻止,您应禁用自动提交。)

分布式XA事务始终应用是该隔离级别

数据库模拟

脏读

顾名思义,在一个事务中读取到了不该读到的数据,举例来说明:

目前我们有User信息表(id,age,name),假设当前有A、B两个事务对该User表进行操作

我们要模拟脏读的场景,首先就需要先设置我们当前数据库连接的事务隔离级别,设置为允许脏读,通过上面的说明,需要设置为READ_UNCOMMITED隔离级别

先来查看mariadb中的默认隔离级别,相关的命令可以查阅官方文档

mysql> SELECT @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.06 sec)

mysql>

mysql中默认事务隔离借呗为可重复读

先设置为READ_UNCOMMITTED级别

mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
Query OK, 0 rows affected (0.04 sec)

mysql> SELECT @@tx_isolation;
+------------------+
| @@tx_isolation   |
+------------------+
| READ-UNCOMMITTED |
+------------------+
1 row in set (0.06 sec)

mysql> 

先看A事务开启事务,查询User信息表:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from user;
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值