数据库事务的四大特性以及事务的隔离级别整理

事务的四大特性

  • 原子性(atomicity)
    我们经常说,一个事务执行失败了,就得回滚,其实这就是事务的原子性,一个完整事务,要么全部执行成功,如果有一个或者多个失败,那么就要回滚,其实这也是另一个特性即一致性的基础
  • 一致性(consistency)
    一致性,先举个栗子,最容易理解的栗子,本来刘备有200元,关羽没有钱,那么刘备给关羽转账100元,现在需要两步执行这个操作,先减去刘备账户里面的100元,第二步,给关羽账号增加100元,那么这两步算是一个事务。在事务发生前,关羽0 +刘备200=200元,事务结束后,关羽100+刘备100=200,数据没有平白增加或者减少。而且不管这兄弟俩怎么转,这个总和不会发生变化,这就是事务的一致性。一致性就是说事务必须使用数据库从一个一致性状态变换到另一个一致性状态。想想我们讲的第一个原子性,如果一半成功,一半失败而没有回滚,还会有数据的一致性吗?
  • 隔离性(isolation)
    隔离性主要是针对并发访问来讲的,当多个用户修改数据表时,数据库为每一个用户开启的事务,不能被其他的事务干扰,多个并发要互相隔离,即对于同一个资源,在同一个时间段只能有一个事务可以修改
  • 持久性(durability)
    持久性就是说一旦事务成功提交,那么对于数据库来说,这种改变是持久的

事务的隔离级别

在mysql中,支持四种隔离级别,即ru,rc,rr,serializealbe,后面我们会一一讲解,mysql默认支持的的rr,

  • 此处给大家推荐一款好用的数据库管理工具,jetbrains出品的datagrip;好用哇哇!,下面的sql语句都是在datagrip中运行的

    image.png

  • READ UNCOMMITTED(未提交读)

  • ru是指在一个事务执行未完成的时候,数据对其他事务也是可见的,而且读取的是已经更改但是还没有commit的数据,这种保证不了数据准确的隔离级别几乎是不用的。也正如此,所以它的性能是最优的

    • 创建相关的数据库和数据表
create schema test;
use test;
CREATE TABLE `t` (
                     `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
                     `point` int(11) DEFAULT NULL,
                     PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

  • 下面粘贴sql语句,注意在同一行的代码先左后右执行,是在两个sql窗口执行的,在执行到第6行的时候发现,console2开启了事务,但是还没有commit,但是console1已经查询到未提交的结果了。这就是读未提交


    image.png
  • READ COMMITTED(读已提交)
    大部分的数据库默认隔离级别就是rc,就是说一个事务只能看见已经提交的修改结果,如果没有提交,那么只能看见原来的结果,而不会看到修改未提交的结果,但是这会出现一个问题,什么问题呢?就是 在一个事务中,如果另一个事务修改了数据并且提交,那么在第一个事务中针对同一个查询,就会查询出来两个不同的数据,即不可重复读


    image.png
  • 新增一条如果没有提交也是读取不到的


    image.png
  • 这个时候,如果两个窗口同时对一条数据更改会发生什么情况呢?第二条更新命令会一直等第一条命令的提交,未提交就处于等待状态


    image.png
  • REPEATABLE READ(可重复读)
    可重复读是mysql默认的隔离级别,rr解决了脏读的问题,但是可能会出现幻读,下面先来演示一下幻读的实现
  • 看一下已经解决了读未提交的问题和不可重复读的问题


    image.png
  • 幻读其实是解决不可重复读的一个缺点,为什么?首先事务1已经执行了一个插入操作,新增id3,但是为了可重复读,事务2看不到新增的数据,所以当事务2增加id3的时候报错,因为id3在数据表中已经切切实实的存在了。可重复读,有点像把某一个时刻的数据作为快照写入了缓存,在commit之前所有的读取都是源自缓存,而非真实的表


    image.png

SERIALIZABLE(可串行化)

其实我们可以先自己想一下,如何在解决重复读的时候还能解决幻读呢?是不是感觉有点不可能,既然不幻读,那就实现不了可重复读,然鹅,但是,前面的操作都是基于两个事务,但是如我们把两个事务再关联一下呢,是不是就可以解决了,这就是串行的意思,可串行化解决了脏读,幻读,可重复读等问题,但是,势必会影响效率,"可串行化"会在读取的每一行数据上都加锁,所以可能会导致大量的锁等待和超时问题,所以在实际的生产环境中也很少会用到这个隔离级别,只有在非常需要确保数据的一致性切可以接受没有并发的情况下,才会考虑使用这个隔离级别。

  • 演示一下,先看一下目前的情况


    image.png
    • 怎么实现串行化呢,说起来有点恶心,这次不是缓存快照了,让你读实时数据,但是更新操作我给你停了。我让你等到没有事务了,或者其他事务都提交了,才让你这个写操作执行,嗯,就是这样。感觉有点不太高明


      image.png
  • 用了锁,有人读也上锁,有人写也上锁,效率能没有影响吗,写之前先看有没有读锁,有读锁就等待。这种方式就是 简单,粗暴


    image.png
  • 综合下来,还是看使用的业务场景选择不同的隔离级别,个人感觉大部分业务还是用rc比较好。你觉得呢?
    附sql脚本
    console1.sql
use test;
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
#READ UNCOMMITTED(未提交读)
start transaction ;
select * from t where id =1;
update t set point=50 where id =1;
commit ;
#READ COMMITTED(读已提交)
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
select * from t where id =1;
start transaction ;
update t set point=80 where id =1;
insert into t values (null,200);
select * from t where id =2;
commit ;

#REPEATABLE READ(可重复读)
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ ;
select * from t ;
start transaction ;
update t set point=100 where id=1;
commit ;

start transaction ;
select * from t ;
insert into t values (null,300);
select * from t ;
commit


## SERIALIZABLE(可串行化)
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE ;
start transaction ;
select * from t;
insert into t values (null,123);

console2.sql

use test;
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
#READ UNCOMMITTED(未提交读)
start transaction ;
select * from t where id =1;
select * from t where id =1;
commit ;
#READ COMMITTED(读已提交)
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
select * from t where id =1;
start transaction ;
update t set point=10 where id =1;
select * from t where id =1;
select * from t where id =2;
commit ;

#REPEATABLE READ(可重复读)
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ ;
select * from t ;
start transaction ;
select * from t where id=1;
select * from t where id=1;

start transaction ;
select * from t ;
select * from t ;
insert into t values (3,300);
commit


## SERIALIZABLE(可串行化)
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE ;
start transaction ;
select * from t;
commit;
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352