zoukankan      html  css  js  c++  java
  • MySQL中的事务

    1. 事务

    1.1. 为什么需要事务

    现在的很多软件都是多用户,多程序,多线程的,对同一个表可能同时有很多人在用,为保持数据的一致性,所以提出了事务的概念。

    A B 要划钱,A 的账户-1000元, B 的账户就要+1000元,这两个update 语句必须作为一个整体来执行,不然A 扣钱了,B 没有加钱这种情况很难处理。

    1.2. 什么存储引擎支持事务

    1.查看数据库下面是否支持事务(InnoDB支持)?

      show engines;

    2.查看mysql当前默认的存储引擎?

      show variables like '%storage_engine%';

    3.查看某张表的存储引擎?

      show create table 表名 ;

    4.对于表的存储结构的修改?

    建立InnoDB 表:Create table .... type=InnoDBAlter table table_name type=InnoDB;

    1.3. 事务特性

    事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。

    原子性(atomicity

    一致性(consistency

    隔离性(isolation

    持久性(durability

    1.3.1. 原子性(atomicity

    一个事务必须被视为一个不可分割的最小单元,整个事务中的所有操作要么全部提交成功,要么全部失败,对于一个事务来说,不可能只执行其中的一部分操作

    老婆大人给Deer发生活费

    1.老婆大人工资卡扣除500

    2.Deer工资卡增加500

    整个事务要么全部成功,要么全部失败

    1.3.2. 一致性(consistency

    一致性是指事务将数据库从一种一致性转换到另外一种一致性状态,在事务开始之前和事务结束之后数据库中数据的完整性没有被破坏

    老婆大人给Deer发生活费

    1.老婆大人工资卡扣除500

    2.Deer工资卡增加500

    2.Deer工资卡增加1000

    扣除的钱(-500) 与增加的钱(500) 相加应该为0

    1.3.3. 持久性(durability

    一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,已经提交的修改数据也不会丢失

    并不是数据库的角度完全能解决

    1.3.4. 隔离性(isolation

    一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

    (对数据库的并行执行,应该像串行执行一样)

    未提交读(READ UNCOMMITED)脏读

    已提交读 READ COMMITED)不可重复读

    可重复读(REPEATABLE READ

    可串行化(SERIALIZABLE

    mysql默认的事务隔离级别为repeatable-read

    show variables like '%tx_isolation%';

    1.3.4.1. 事务并发问题

    脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

    不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。

    幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

     

    不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

     

    1.3.4.2. 未提交读(READ UNCOMMITED)脏读

    show variables like '%tx_isolation%';

    set SESSION TRANSACTION ISOLATION LEVEL read UNCOMMITTED;

    一个session

      start TRANSACTION

      update account set balance = balance -50 where id = 1

    另外一个session中查询

    select * from account

    回到第一个session中 回滚事务

    ROLLBACK

    在第二个session

    select * from account

    在另外一个session中读取到了为提交的数据,这部分的数据为脏数据

    1.3.4.3. 已提交读 READ COMMITED)不可重复读

    show variables like '%tx_isolation%';

    set SESSION TRANSACTION ISOLATION LEVEL read committed;

    一个session

      start TRANSACTION

      update account set balance = balance -50 where id = 1

    另外一个session中查询 (数据并没改变)

    select * from account

    回到第一个session中 回滚事务

    commit

    在第二个session中

    select * from account (数据已经改变)

    1.3.4.4. 可重复读(REPEATABLE READ

    show variables like '%tx_isolation%';

    set SESSION TRANSACTION ISOLATION LEVEL repeatable read;

    一个session

      start TRANSACTION

      update account set balance = balance -50 where id = 1

    另外一个session中查询 (数据并没改变)

    select * from account

    回到第一个session中 回滚事务

    commit

    在第二个session中

    select * from account (数据并未改变)

    1.3.4.5. 可串行化(SERIALIZABLE

    show variables like '%tx_isolation%';

    set SESSION TRANSACTION ISOLATION LEVEL serializable;

    1.开启一个事务

    begin

    select * from account  发现3条记录

    2.开启另外一个事务

    begin

    select * from account  发现3条记录 也是3条记录

    insert into account VALUES(4,'deer',500)  发现根本就不让插入

    3.回到第一个事务 commit

    1.1.1.1. 间隙锁(gap锁)

     其实在mysql中,可重复读已经解决了幻读问题,借助的就是间隙锁

     

    实验1

    select @@tx_isolation;

     create table t_lock_1 (a int primary key);

    insert into t_lock_1 values(10),(11),(13),(20),(40);

     begin

     select * from t_lock_1 where a <= 13 for update;

     在另外一个会话中

    insert into t_lock_1 values(21) 成功

    insert into t_lock_1 values(19) 阻塞

    rr隔离级别中者个会扫描到当前值(13)的下一个值(20,并把这些数据全部加锁

    实验:2

     

    create table t_lock_2 (a int primary key,b int, key (b));

    insert into t_lock_2 values(1,1),(3,1),(5,3),(8,6),(10,8);

     

    会话1

    BEGIN

     select * from t_lock_2 where b=3 for update;

    1 3 5 8 10

    1 1 3 6 8

    会话2

    select * from t_lock_2 where a = 5 lock in share mode; -- 不可执行,因为a=5上有一把记录锁

    insert into t_lock_2 values(4, 2); -- 不可以执行,因为b=2(1, 3]

    insert into t_lock_2 values(6, 5); -- 不可以执行,因为b=5(3, 6)

    insert into t_lock_2 values(2, 0); -- 可以执行,(2, 0)均不在锁住的范围内

    insert into t_lock_2 values(6, 7); -- 可以执行,(6, 7)均不在锁住的范围内

    insert into t_lock_2 values(9, 6); -- 可以执行

    insert into t_lock_2 values(7, 6); -- 不可以执行

     二级索引锁住的范围是 (1, 3],(3, 6

     主键索引只锁住了a=5的这条记录 [5]

    1.1. 事务语法

    1.1.1. 开启事务

    1begin

    2START TRANSACTION(推荐)

    3begin work

    1.1.2. 事务回滚  

    rollback

    1.1.3. 事务提交

      commit

    1.1.4. 还原点

    savepoint

    show variables like '%autocommit%';  自动提交事务是开启的

    set autocommit=0;    //关闭事务自动提交

    insert into testdemo values(5,5,5);

    savepoint s1;

    insert into testdemo values(6,6,6);

    savepoint s2;

    insert into testdemo values(7,7,7);

    savepoint s3;

    select * from testdemo

    rollback to savepoint s2

    rollback

  • 相关阅读:
    9 Fizz Buzz 问题
    2 尾部的零
    1 A+B问题
    递归
    互斥同步
    垃圾收集器与内存分配策略---垃圾收集算法
    10.矩形覆盖
    9.变态跳台阶
    8.跳台阶
    9.path Sum III(路径和 III)
  • 原文地址:https://www.cnblogs.com/Soy-technology/p/11064382.html
Copyright © 2011-2022 走看看