MySQL-day04

事务

一、什么是事务?

1. 事务的概念
  • 事务(TRANSACTION)是作为单个逻辑工作单元的一系列操作。
  • 多个操作作为一个整体向系统提交,要么都执行,要么都不执行。事务是一个不可分割的工作逻辑单元。
2. 事务的四大特性(ACID)
  • 原子性(Actomicity)
    • 事务时一个完整的操作,各步操作是不可分的,要么都执行,要么都不执行。
  • 一致性(Consistency)
    • 当事务完成时,数据必须处于一致状态
  • 隔离性(Isolation)
    • 并发事务之间彼此隔离、独立,它不应以任何方式依赖于或影响其他事务。
  • 持久性(Durability)
    • 事务完成后,它对数据库的修改被永久保持。

二、事务操作

MySQL中支持事务的存储引擎有InnDB和BDB

  1. 创建事务

    1. 开启事务:begin;start transaction;
    2. 设置回滚点:savepoint sp;
    3. 回滚(撤销事务):rollcack ;
    4. 提交事务:commit;
      示例:从张三的账户转出500元,存入李四的账户中
    BEGIN;
    /*--转账:张三的账户减少500元,李四的账户增加500元--*/
    UPDATE `bank` SET `currentMoney`=`currentMoney`-500
    	WHERE `customerName`='张三';
    ## rollback;
    
    UPDATE `bank` SET `currentMoney`=`currentMoney`+500
    	WHERE `customerName`='李四';
    COMMIT;
    SELECT * FROM bank;
    
  2. 自动开启和关闭事务

    • 默认情况下,每条单独的SQL语句视为一个事务
    • 关闭默认提交状态后,可手动开启、关闭事务
    • 语法:set autocommit = 0|1
    • 关闭自动提交后,从下一条SQL语句开始则开启新事务,需使用COMMIT或ROLLBACK语句结束该事务。

    示例:

    SET autocommit=0;
    /*--转账:张三的账户减少500元,李四的账户增加500元--*/
    UPDATE `bank` SET `currentMoney`=`currentMoney`-500
     WHERE `customerName`='张三';
    UPDATE `bank` SET `currentMoney`=`currentMoney`+500
     WHERE `customerName`='李四';
    COMMIT;
    UPDATE `bank` SET `currentMoney`=`currentMoney`-1000 WHERE `customerName`='张三';
    ROLLBACK;
    SET autocommit = 1;
    

三、事务的隔离性

  1. 什么是事务的隔离性?
    隔离性是指: 并发事务之间互相影响的程度。

  2. 隔离性引起的问题

    1. 脏读: 读取未提交的数据。事务A修改了一个数据,但未提交,事务B读到了事务A未提交的更新结果,如果事务A提交失败,事务B读到的就是脏数据。
    时序事务1事务2结果
    1set transaction isolation level read uncommitted;(设置隔离级别)set transaction isolation level read uncommitted;(设置隔离级别)
    2begin;(开启事务)begin;(开启事务)
    3查询语句1结果1
    4更新语句1ok
    5查询语句1结果2
    6查询语句1结果2
    1. 不可重复读: 同一事务中,两次读取同一条数据不一致。比如,事务B在事务A提交前读到的结果,和事务A提交后的结果可能不同。不可重复读出现的原因就是事务并发修改记录。
    时序事务1事务2结果
    1set transaction isolation level read committed;(设置隔离级别)set transaction isolation level read committed;(设置隔离级别)
    2begin;begin;
    3查询语句1结果1
    4更新语句1ok
    5查询语句1结果2
    6commit;(提交事务)
    7查询语句1结果2
    1. 虚读(幻读): 同一事务中,读取到了另一个事务新插入的数据。事务A新增了一条记录,事务B在事务A提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录。幻读是由于并发事务增加记录导致的。
    时序事务1事务2结果
    set global transaction isolation level repeatable read;set global transaction isolation level repeatable read;
    1begin;begin;
    2查询语句1结果1
    3插入语句1ok
    4查找语句1结果2
    5commit;
    6查询语句1结果2
  3. 隔离性问题的解决

    1. 隔离命令(默认为session)
      • 查看隔离级别

        select @@tx_isolation;

      • 设置隔离级别

        set [global/session] transaction isolation level 隔离级别

    2. 脏读问题的解决

      set transaction isolation level read committed;

    3. 不可重复读的解决

      set transaction isolation level repeatable read;

    4. 虚读的解决

      set transaction isolation level serializable

  4. 事务隔离与安全效率

    脏读不可重复读虚读共享锁排它锁
    read uncommitted×××
    read committed××
    repeatable read×
    serializable

    安全性与效率

    • 效率越高安全性越差
    • 安全性:serializable>repeatable read>read committed>read uncommitted
    • MySQL中默认隔离级别为:repeatable read
    • Oracle中默认隔离级别为:read committed
  5. 共享锁与排他锁

    1. 共享锁(Share Lock)
      共享锁又称读锁: 是读取操作创建的锁。其他用户可以并发读取用户,但任何事务都不能对数据进行修改(获取数据上的排他锁),直到已释放所有共享锁。
      用法:

      SELECT ... LOCK IN SHARE MODE;
      

      注: 在查询语句后面增加LOCK IN SHARE MODE,MySQL会对查询结果中的每行都加共享锁,当没有其他线程对查询结果集中的任何一行使用排他锁时,可以成功申请共享锁,否则会被阻塞。其他线程也可以读取使用了共享锁的表,而且这些线程读取的是同一个版本的数据。

    2. 排他锁(eXclusive Lock)
      排他锁又称写锁: 如果事务T对数据A加上排他锁后,则其他事务不能再对A加任何类型的锁,获准排他锁的事务既能读数据,又能修改数据。
      用法:

      SELECT ... FOR UPDATE;
      

      注: 在查询语句后增加FOR UPDATE,MySQL会对查询结果中的每行都加排他锁,当没有其他线程对查询结果集中的任何一行使用排他锁时,可以成功申请排他锁,否则会被阻塞。

    3. 加了共享锁可以再加共享锁,加了排他锁不能再加任何锁。

四、乐观锁与悲观锁

  • 乐观锁和悲观锁只是一种 思想。它体现在数据库及计算机科学中的很多应用方面。
1. 更新丢失问题
时序线程1线程2结果
1查询语句1结果1
2查询语句1结果1
3更新语句1ok
4查询语句1结果2
5更新语句2ok
6查询语句1结果3
7查询语句1结果3
2. 问题分析
  • 本质: 两个线程并发更新数据,后一个线程会覆盖前一个修改。
    设定隔离级别为 serializable 可解决,但是,效率太差;
    在非 serializable 隔离级别下,可使用乐观锁和悲观锁来解决此问题。

3. 乐观锁

  • 乐观锁: 认为数据的变动不会太频繁。因此,它允许多个事务同时对数据进行变动。 但是,乐观不代表不负责,那么怎么去负责多个事务顺序对数据进行修改呢?乐观锁通常是通过在表中增加一个版本(version)或时间戳(timestamp)来实现,其中,版本最为常用。不同于悲观锁,乐观锁是人为控制的。

  • 原理:

    1. 在表中增加一个记录版本的字段;
    2. 在查询时不加任何锁,在修改时基于版本修改。
  • 具体操作:

事务在从数据库中取数据时,会将该数据的版本也取出来(v1),当事务对数据变动完毕想要将其更新到表中时,会将之前取出的版本 v1 与数据中最新的版本 v2 相对比,如果 v1 = v2,那么说明在数据变动期间,没有其他事务对数据进行修改,此时,就允许事务对表中的数据进行修改,并且修改时 version 会加 1,以此来表明数据已被变动。如果,v1 不等于 v2,那么说明数据变动期间,数据被其他事务改动了,此时不允许数据更新到表中,一般的处理办法是通知用户让其重新操作。

  • 缺点: 如果修改操作频繁的话,会造成多次修改失败,重复执行更新。
  • 应用场合: 查询多,修改少。

4. 悲观锁

  • 悲观锁: 悲观锁认为被它保护的数据是极其不安全的,每时每刻都有可能变动,一个事务拿到悲观锁后(可以理解为一个用户),其他任何事务都不能对该数据进行修改,只能等待锁被释放才可以执行。

  • 数据库中的行锁,表锁,读锁,写锁,以及syncronized 实现的锁均为悲观锁。

  • 原理:

  1. 在查询内容上,加上排它锁 for update;
  2. 使其他查询等待,等到本事务执行完毕之后,其他查询才能进行。
  • 缺点: 效率较差,但比 Serializable 好。
  • 应用场合: 查询少,修改多。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值