关于事务的基础知识(面试知识)

本篇记录一下关于事务的基础知识

一、事务的基本要素(ACID)

  1. 原子性(Atomicity)
      事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。
  2. 一致性(Consistency)
       事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。
  3. 隔离性(Isolation)
       同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
  4. 持久性(Durability)
       事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。

二、四种隔离级别

  • Read Uncommitted(读取未提交内容)
    在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。

  • Read Committed(读取提交内容)
    这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。

  • Repeatable Read(可重读)
    这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。

  • Serializable(可串行化)
    这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted)
不可重复读(read-committed)
可重复读(repeatable-read)
串行化(serializable)

三、事务的并发

  1. 脏读
    事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
  2. 不可重复读
    事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
  3. 幻读
    系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

四、spring事务传播机制

事务传播行为类型 描述
PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中(默认使用这个)
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行
PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常
PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作,这个是事务的嵌套

五、spring事务的重要接口
关于事务的基础知识(面试知识)_第1张图片

  • spring事务管理器->PlatformTransactionManager
    这个接口有三个方法:
    关于事务的基础知识(面试知识)_第2张图片
    1.TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
    他的作用是:根据TransactionDefinition 获取事务,返回结果是TransactionStatus。TransactionDefinition 相当于事务的定义,根据事务的定义获取事务,返回的结果是TransactionStatus事务的状态。
    2.void commit(TransactionStatus status) throws TransactionException;
    通过TransactionStatus提交事务
    3.void rollback(TransactionStatus status) throws TransactionException;
    通过TransactionStatus回滚事务
  • spring事务的状态->TransactionDefinition
    关于事务的基础知识(面试知识)_第3张图片
    可以看到这个类里面定义了上面说过的传播机制,还有隔离级别,还有五个方法
    • int getPropagationBehavior();
      获取事务的传播属性
    • int getIsolationLevel();
      获取事务的隔离级别
    • int getTimeout();
      获取事务超时时间
    • boolean isReadOnly();
      是否只读
    • String getName();
      获取事务的名字

再列出来这个类中的隔离机制的描述:这个描述我简化写了,除了第一个,剩下的和上面第二小节的意义差不多,可以翻上去看看

事务隔离级别 描述
ISOLATION_DEFAULT 和使用的数据库保持一致的隔离机制
ISOLATION_READ_UNCOMMITTED 读取未提交内容
ISOLATION_READ_COMMITTED 读取提交内容
ISOLATION_REPEATABLE_READ 可重读
ISOLATION_SERIALIZABLE 串行
  1. spring事务状态-> TransactionStatus
    关于事务的基础知识(面试知识)_第4张图片
    然后介绍一下这六个方法的作用:
    1. void flush();
      用于刷新底层会话中的修改到数据库,一般用于刷新如Hibernate/JPA的会话,可能对如JDBC类型的事务无任何影响
    2. boolean hasSavepoint();
      返回当前事务是否有保存点,保存点的意思在嵌套事务中的存盘点/保存点,两个事物嵌套的时候会有这个点
    3. boolean isCompleted();
      当前事务否已经完成
    4. boolean isNewTransaction();
      是否是一个新的事务
    5. boolean isRollbackOnly();
      返回事务是否为仅回滚
    6. void setRollbackOnly();
      设置当前事务只能回滚

六、spring事务的实现

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

@Service
public class TestServcieImpl {

    @Autowired
    PlatformTransactionManager platformTransactionManager;//注入事务管理器

    public void test(){
        DefaultTransactionDefinition definition = new DefaultTransactionDefinition();//创建默认的TransactionDefinition
        definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);//传播机制
        TransactionStatus status = platformTransactionManager.getTransaction(definition);//根据TransactionDefinition获取事务 返回结果是TransactionStatus
        try{
            //处理业务代码.....
            platformTransactionManager.commit(status);//提交事务
        } catch(Exception e){
            platformTransactionManager.rollback(status);//回滚事务
        }
    }
}

这是使用纯代码的形式使用事务,一般我们在项目中使用的时候,不会这么写,因为太麻烦了,在spring中使用AOP和代理模式来处理事务管理,这个也是很重要的知识,这里我就不详细解释代理模式了,本篇主要讲事务,以后有机会会写代理模式和AOP的资料。
在springMVC中我们一般使用声明式容器事务管理或者注解式事务管理,这个大家应该都知道,简单说一下:
下面这个一般在配置文件中,是 声明式容器事务管理

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="add*" propagation="REQUIRED" />
        <tx:method name="get*" propagation="REQUIRED" />
        <tx:method name="*" read-only="true" />
    </tx:attributes>
</tx:advice>

还有下面这个是 注解式事务管理

<tx:annotation-driven transaction-manager="transactionManager"/>

至于这两种代码中怎么写,大家应该都用过,这里就不举例子了,不清楚的可以去查查资料
好了,就说到这里。个人浅薄理解,欢迎补充

你可能感兴趣的:(java)