Day04 03-MySQL的事务(TCL)

文章目录

      • 第十三章 TCL
        • 13.1 事务的介绍
        • 13.2 事务的特性
        • 13.3 MySQL的事务
          • 13.3.1 隐式事务
          • 13.3.2 显式事务
        • 13.4 并发事务
          • 13.4.1 并发事务出现的问题
          • 13.4.2 事务的隔离级别

第十三章 TCL

13.1 事务的介绍

我们先来看一个场景:

假如把每一张银行卡的信息存入数据库的表中进行存储,每一张表中存储有银行卡的卡号、余额信息。小明需要给小红转账1000元钱,那么在数据库中需要进行的操作是什么?
	- 将小明的银行卡余额,减1000
	- 将小红的银行卡余额,加1000
	
那么,如果在上述的操作中,如果第一步成功了,小明的余额已经减过了。但是在给小红的银行卡余额增1000的时候出现了问题,导致本次操作失败了。那么本次转账整体失败,小明的余额也需要回滚到减1000之前的状态。

当一个业务需求涉及到多个DML操作时,这个业务(或者多个DML操作)当成一个整体来处理。在处理的过程中,如果有失败或异常,我们要回到业务开始时。如果成功处理,我们再将数据持久化到磁盘中。这样一个过程我们称之为一个事务。事务具有原子性。不可切割。

总结: 事务指逻辑上的一组操作,组成这组操作的各个单元,要么全成功,要么全不成功。

13.2 事务的特性

  • 原子性(Atomicity)

    指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
    
  • 一致性(Consistency)

    事务必须使数据库从一个一致性状态变换到另外一个一致性状态。转账前和转账后的总金额不变。
    
  • 隔离性(Isolation)

    事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
    
  • 持久性(Durability)

    指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。
    

13.3 MySQL的事务

13.3.1 隐式事务

隐式事务,或者称为自动事务。不需要进行额外的控制,每一条DML语句都是一个事务,可以自动提交。

  • 事务开始于
    • 连接到数据库上,并执行一条DML语句insert、update或delete。
    • 前一个事务结束后,又输入了另一条DML语句。
  • 事务结束于
    • 执行commit或rollback语句。
    • 执行一条DDL语句,例如create table语句,在这种情况下,会自动执行commit语句。
    • 执行一条DCL语句,例如grant语句,在这种情况下,会自动执行commit。
    • 断开与数据库的连接。
    • 执行了一条DML语句,该语句却失败了,在这种情况中,会为这个无效的DML语句执行rollback语句。
13.3.2 显式事务
-- 禁用自动提交的功能
set autocommit = 0;

-- 开启一个事务(可以省略不写)
start transaction;

-- 执行一组DML操作
...

-- 设置回滚点
savepoint spName;

-- 结束事务
commit;					-- 提交事务
rollback;				-- 回滚到事务的起点
rollback to spName;		-- 回滚到指定的回滚点

13.4 并发事务

13.4.1 并发事务出现的问题

如果有多个事务,同时操作同一个数据库中的同一个数据的时候,会出现如下的问题:

  • 脏读: 事务A读取了事务B刚刚更新的数据,但是事务B回滚了,这样就导致事务A读取的为脏数据,我们称之为脏读。

    如公司某财务人员更新公司入账报表时,在DML语句中的数字后少添加了一个0,但是未提交。然后吃饭,吃饭回来,发现错误,然后更正后做了提交。而在吃饭期间,老板要求秘书查看一下报表,秘书看到的是少个0的数据。这就是脏读。
    
  • 不可重复读: 事务A读取同一条记录两次,但是在两次之间事务B对该条记录进行了修改并提交,导致事务A两次读取的数据不一致。

    它和脏读的区别是: 脏读是事务A读取了另一个事务B未提交的脏数据,而不可重复读则是事务A读取了事务B提交的数据。
    
    多数情况下,不可重复读并不是问题,因为我们多次查询某个数据时,当然要以最后查询得到的结果为主。但在另一些情况下就有可能发生问题,比如,老板让B和C分别核对事务A操作的数据,结果可能不同,老板是怀疑B呢,还是C呢?
    
  • 幻读: 事务A在修改全表的数据,比如将字段age全部修改为0岁,在未提交时,事务B向表中插入或删除数据,如插入一条age为25
    岁的数据。这样导致事务A读取的数据与需要修改的数据不一致,就和幻觉一样。

    幻读和不可重复读的相同点: 都是针对于另外一个已经提交的事务而言。不同点: 不可重复读是针对于同一条记录来说的 (delete或update同一条记录, 而幻读是针对于一批数据来说的 (insert)。
    
13.4.2 事务的隔离级别

我们知道了多个事务同时对相同的数据进行处理的时候,会出现上述的问题,那么应该怎么去解决这个问题呢?

可以通过设置事务的隔离级别

  • 未提交读(read uncommitted)

    就是不做隔离控制,可以读到 “脏数据“,可能发生不可重复读,也可能出现幻读。
    
  • 提交读(read committed)

    提交读就是不允许读取事务没有提交的数据。显然这种级别可以避免了脏读问题。但是可能发生不可重复读,幻读。这个隔离级别是大多数数据库的默认隔离级别。(除了MySQL)
    
  • 可重复读(repeatable read)

    为了避免提交读级别不可重复读的问题,在事务中对符合条件的记录上"排他锁”,这样其他事务不能对该事务操作的数据进行修改,可避免不可重复读的问题产生。由于只对操作数据进行上锁的操作,所以当其他事务插入或删除数据时,会出现幻读的问题,此种隔离级别为Mysql默认的隔离级别。
    
  • 序列化(Serializable)

    在事务中对表上锁,这样在事务结束前,其他事务都不能够对表数据进行操作(包括新增,删除和修改)。这样避免了脏读,不可重复读和幻读,是最安全的隔离级别。但是由于该操作是堵塞的,因此会严重影响性能。
    
避免脏读 避免不可重复读 避免幻读
read uncommitted × × ×
read committed × ×
repeatable read ×
Serializable
-- 查看当前隔离级别
select @@transaction_isolation;
-- 设置当前MysqL连接的级别
set transaction isolation level read committed;
-- 设置数据库系统的全局隔离级别
set global transaction isolation level read committed;
-- 一般需要重启生效

你可能感兴趣的:(全链路数据仓库,mysql,MySQL事务,MySQL并发事务,事务,数据库事务)