面试面试常问之数据库事务

Posted 黑黑白白君

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试面试常问之数据库事务相关的知识,希望对你有一定的参考价值。


1)什么是事务?

事务(Transaction)是一个最小的不可再分的工作单元,通常一个事务对应一个完整的业务

  • 所谓的事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位
  • 一个完整的业务需要批量的DML(insert、update、delete)语句共同联合完成。
  • 事务只和DML语句有关,或者说DML语句才有事务。

为什么需要事务?

事务的提出主要是为了解决并发情况下保持数据一致性的问题

例如,银行转账工作:从一个账号扣款并使另一个账号增款,这两个操作要么都执行,要么都不执行。所以,应该把它们看成一个事务。

  • 以下是银行账户表t_act(账号、余额):
    actnobalance
    1500
    2100
  • 进行转账操作:
    update t_act set balance=400 where actno=1;
    update t_act set balance=200 where actno=2;
  • 以上两条DML语句必须同时成功或者同时失败:
    • 当第一条DML语句执行成功后,并不能将底层数据库中的第一个账户的数据修改,只是将操作记录了一下,这个记录是在内存中完成的
    • 当第二条DML语句执行成功后,和底层数据库文件中的数据完成同步
    • 若第二条DML语句执行失败,则清空所有的历史操作记录,要完成以上的功能必须借助事务

事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性

事务四大特征(ACID)

  • 原子性(Atomic):事务是最小工作单位,不可再分。事务中的操作要么全部成功,要么全部失败。
  • 一致性(Consistency):保证数据的状态操作前和操作后保持一致
  • 隔离性(Isolation):多个事务同时操作相同数据库的同一个数据时,一个事务的执行不受另外一个事务的干扰
  • 持久性(Durability):一个事务一旦提交,则数据将持久化到本地,除非其他事务对其进行修改。

1.1 事务的分类

  • 隐式事务:

    没有明显的开启和结束事务的标志。

    • 比如insert、update、delete语句本身就是一个事务。
  • 显式事务:

    具有明显的开启和结束事务的标志。

    1、开启事务
    set autocommit=0;  //取消自动提交事务的功能
    start transaction;
    	
    2、编写事务的一组逻辑操作单元(多条sql语句)
    insert
    update
    delete
    savepoint  //断点
    	
    3、提交事务或回滚事务
    commit;
    rollback;
    
    commit to 断点
    rollback to 断点
    

*关于savepoint

用户在事务(transaction)内可以声明(declare)被称为保存点(savepoint)的标记。保存点将一个大事务划分为较小的片断

  • 用户可以使用保存点(savepoint)在事务(transaction)内的任意位置作标记。
  • 之后用户在对事务进行回滚操作(rolling back)时,就可以选择从当前执行位置回滚到事务内的任意一个保存点。
  • 例如用户可以在一系列复杂的更新(update)操作之间插入保存点,如果执行过程中一个语句出现错误,用户可以回滚到错误之前的某个保存点,而不必重新提交所有的语句。

1.2 步骤

  1. 开启事务(任何一条DML语句(insert、update、delete)执行,标志事务的开启)
  2. 编写事务的一组逻辑操作单元(多条sql语句)
  3. 提交事务或回滚事务


2)事务的隔离性(Isolation)

为什么需要隔离性?

当多个事务同时操作同一个数据库的相同数据时,可能发生事务并发问题

  • 事务的并发问题有哪些?

    • 脏读:一个事务读取到了另外一个事务未提交的数据
    • 不可重复读:同一个事务中,多次读取到的数据不一致
    • 幻读:一个事务读取数据时,另外一个事务进行更新,导致第一个事务读取到了没有更新的数据
  • 如何避免事务的并发问题?

    通过设置事务的隔离级别:
    1、READ UNCOMMITTED
    2、READ COMMITTED 可以避免脏读
    3、REPEATABLE READ 可以避免脏读、不可重复读和一部分幻读
    4、SERIALIZABLE可以避免脏读、不可重复读和幻读

2.1 事务的隔离级别

在这里插入图片描述

1、读未提交:read uncommitted

这种隔离级别最低,这种级别一般是在理论上存在,数据库隔离级别一般都高于该级别

  • 事务中的修改,即使没有提交,在其他事务也都是可见的
  • 结果:产生脏读。

2、读已提交:read committed

Oracle默认隔离级别

  • 一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的
  • 这种级别可以避免“脏数据”
  • 这种隔离级别会导致“不可重复读取”
    • 因为在这多次读之间可能有其他事务更改这个数据,每次读到的数据都是已经提交的。

3、可重复读:repeatable read

MySQL默认级别

  • 事务A在执行查询时,对检索的数据(范围性)都加了行锁(LOCK),这样其他事务就无法对这些加了锁的数据进行更改。
  • 可以避免“不可重复读取”,达到可重复读取。
  • 虽然可以达到可重复读取,但是会导致“幻读”
    • 因为虽然对检索到的数据加了锁,但是并没有阻止别的事物在这些数据行中间插入新的数据行,导致同一事物多次查询时,突然发现多出来一行或几行数据(幻行)。

4、串行化:serializable

这种隔离级别很少使用,吞吐量太低,用户体验差。

  • 事务A和事务B,事务A在操作数据库时,事务B只能排队等待。
  • 这种级别可以避免“幻读”,每一次读取的都是数据库中真实存在数据,事务A与事务B串行,而不并发
  • 由于读取的每行数据都加锁,会导致大量的锁征用问题,因此性能也最差

2.2 查看和设置隔离级别

事务隔离级别的作用范围分为两种:

  • 全局级:对所有的会话有效
  • 会话级:只对当前的会话有效

查看:

select @@tx_isolation;  //查看当前会话隔离级别
select @@global.tx_isolation;  //查看系统当前隔离级别

设置:

set session transaction isolation level repeatable read;  //设置当前会话隔离级别
set global transaction isolation level repeatable read;  //设置系统当前隔离级别


【部分内容参考自】
-mysql——事务(Transaction)详解:https://xulinjie.blog.csdn.net/article/details/79666086

  • 数据库系列之——事务隔离的可重复读:https://blog.csdn.net/weixin_42336774/article/details/86274281

以上是关于面试面试常问之数据库事务的主要内容,如果未能解决你的问题,请参考以下文章

面试面试常问之数据库索引

面试面试常问之堆栈的区别

面试面试常问之堆栈的区别

面试面试常问之python修饰器

面试必问之spring 面试题

面试数据库常问之char与varchar的区别