事务及其并发问题

大家好,我是一只学弱狗,记录学习的点点滴滴!

优质文章

  • 一张黄图的故事
  • JavaSE练习项目-坦克大战
  • 我是菜鸟、我小试牛刀
  • linux指令太多记不住?小白看这篇就够了!

优质专栏

  • 数据库就该这样学
  • 爪哇外步篇

事务:事务是由一个或一组SQL语句组成的一个执行单元,这个执行单元要么全部执行,要么全部不执行

事务的ACID属性
  • 原子性(Atomicity):是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生
  • 一致性(Consistency):是指事务必须使数据库从一个一致性状态变换到另一个一致性状态
  • 隔离性(Isolation):是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰
  • 持久性(Durability):是指一个事务一旦被提交,它对数据库中的数据的改变就是永久性的,接下来的其它操作和数据库故障不应该对其有任何影响
事务的创建

事务分为隐式事务显式事务

  • 隐式事务:事务没有明显的开启和结束的标记,比如insert、update、delete语句
  • 显式事务:事务具有明显的开启和结束的标记

我们具体来说一下显式事务的创建,它一个前提:必须先设置自动提交功能为禁用,我们执行下面这条语句

SHOW VARIABLES LIKE 'autocommit';

出现下面的结果

可以看到自动提交(autocommit)的值为ON,为自动开启状态,这也是我们平时所写的的insert、update、delete语句可以代表一个事务,接下来我们先用下面的代码来创建一个表并插入数据

USE test;
DROP TABLE IF EXISTS account;
CREATE TABLE IF NOT EXISTS account(id INT,username VARCHAR(20),salary DOUBLE
);
INSERT INTO account VALUES(1,'Alice',1000);
INSERT INTO account VALUES(2,'Boily',1000);

我们开始创建事务,通过下面的一条语句设置自动提交为禁用

SET autocommit=0;

再看一下autocommit的值

已经关闭了自动提交,我们继续执行

SET autocommit=0;
UPDATE account SET salary=500 WHERE id=1;
UPDATE account SET salary=1500 WHERE id=2;
COMMIT;

上述代码即一个事务执行之后,我们查看表的内容

达到了预期的结果,我们再来执行下面的语句

SET autocommit=0;
UPDATE account SET salary=1000 WHERE id=1;
UPDATE account SET salary=1000 WHERE id=2;
ROLLBACK;

没有报错,我们再来看下结果

问题出现在COMMIT和ROLLBACK,COMMIT是提交事务,ROLLBACK意为回滚点,大家可以想一下这么一个场景:你双十一购物的时候,看上了一个东西,订单都提交了,当你付钱的时候,发现没钱了,于是呢,这个订单就会失败,而不会提交,大概就是这么一个意思。。。

事务的并发问题

事务的并发问题有下面这几类

  • 脏读:是指对于两个事务T1、T2,T1读取了已经被T2更新但还没有被提交的字段,之后,若T2回滚,T1读取的内容就是临时且无效的
  • 不可重复读:对于两个事务T1、T2,T1读取了一个字段,然后T2更新了该字段,之后,T1再次读取同一个字段,值就不同了
  • 幻读:对于两个事务T1、T2,T1从一个表中读取了一个字段,然后T2在该表插入了一些新的行,之后,如果T1再次读取同一个表,就会多出几行字段

接下来,我们将通过命令行的方式来解读一下上面的三个并发问题,当然,在这之前,我们需要了解一些知识:

在MySQL中,为了避免上面的并发问题,采用了隔离机制,即设置事务的隔离级别,在MySQL中,一共有四种隔离级别,如下

事务的隔离级别

  1. READ UNCOMMITTED
  2. READ COMMITTED
  3. REPEATABLE READ
  4. SERIALIZABLE

我们可以通过下面两条语句来查看隔离级别和设置隔离级别

select @@tx_isolation;#查看隔离级别
set session transaction isolation level 隔离级别;#设置隔离级别

好,我们开始通过命令行的方式,设置不同的隔离级别来了解三种并发问题

隔离级别:READ UNCOMMITTED

打开命令行窗口,查看MySQL默认的隔离级别,如下

可见,MySQL默认的隔离级别是REPEATABLE READ,现在,我们把它设置为READ UNCOMMITTED,如下
设置成功之后,我们查看下表account中的内容,如下

我们开始创建事务,同时,我们再打开一个命令行窗口,如图

这样,就演示了脏读的效果,接下来,我们来演示不可重复读
继续演示幻读

好,对于当隔离级别为READ UNCOMMITTED时的三种并发问题我们就演示到这里。

隔离级别:READ COMMITTED

和前面一样,恢复数据后,我们继续演示

可见,在这种隔离级别下,可以避免脏读问题,接下来,我们看下不可重复读和幻读


可见,在这种隔离,仍避免不了不可重复读和幻读

隔离级别:REPEATABLE READ

我们恢复数据,继续演示

避免了脏读问题,我们看一下不可重复读

这种隔离级别避免了不可重复读,再来看看它对幻读能否避免???

还是没能避免幻读!!!

隔离级别:SERIALIZABLE

终于,到了最后一个了
我们直接试下看它能否避免幻读
终于避免了,其实在这种隔离级别下,三种并行都能够避免

隔离级别总结
  • READ UNCOMMITTED:出现脏读,不可重复读,幻读
  • READ COMMITTED:避免脏读,出现不可重复读和幻读
  • REPEATABLE READ:避免脏读和不可重复读,避免幻读
  • SERIALIZABLE:避免脏读,不可重复读,幻读