数据库事物的四大特性(ACID)以及隔离级别

事物的性质

事务的特性通常被概括为“ACID”原则即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。

  • 原子性(Atomicity): 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
  • 一致性(Consistency): 执行事务前后,数据保持一致;一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。拿转账来说,小明和小红两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
  • 隔离性(Isolation): 并发访问数据库时,一个用户的事物不被其他事物所干扰,各并发事务之间数据库是独立的;当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
  • 持久性(Durability): 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。

事物的隔离级别

隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted) 发生 发生 发生
不可重复读(read-committed) 不发生 发生 发生
可重复读(repeatable-read) 不发生 不发生 发生
串行化(serializable) 不发生 不发生 不发生

    下面分别就脏读、不可重复读、幻读出现的情况用具体的例子说明。下面sql是例子中需要用到的。

mysql -uroot -psorry;#登录mysql
create schema test default character set utf8 collate utf8_general_ci;#创建数据库
grant select,insert,update,delete,create on test.* to root;#用户授权数据库
flush privileges;#立即启用配置
use test;
set global transaction isolation level read uncommitted; #最低级别隔离性
set global transaction isolation level read committed; #次低级别隔离性
set global transaction isolation level repeatable read; #设置全局隔离级别
set global transaction isolation level serializable; #最高级别隔离性
#建表
create table amount (
id int(10) primary key,
money int(8) NOT NULL
);

脏读

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

A客户端
在这里插入图片描述
B客户端
在这里插入图片描述
上面演示的示例中,可以发现A客户端STEP 5发生了脏读。这里仅仅演示脏读发生的过程,将事物隔离级别提高到不可重复读即可避免脏读的发生,具体操作将隔离级别提高之后再按照上述过程操作一遍即可。
关于上例举一个形象的例子:公司发工资了,领导把200元打到小明的账号上,但是该事务并未提交,而小明正好去查看账户,发现工资已经到账,是200元整,非常高兴。可是不幸的是,领导发现工资发错了,应该发给小张的,于是迅速回滚了事务,将事务提交,最后小明账户余额没有增长,小明空欢喜一场。

不可重复读

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

A客户端操作事物一
在这里插入图片描述
B客户端操作事物二
在这里插入图片描述
当隔离级别为不可重复读时,可以避免出现脏读的情况,却不能避免不可重复读的情况。客户端A中STEP3和STEP7前后两次查询因为客户端B更新了ID为1的那条记录导致查询结果不一致。

幻读:

事物一查询数据之后发现没有id为2的记录,说明可以插入一条id为2的记录。此时事物二麻利的插入了一条id为2的记录,并提交了事物。此时事物一无论如何也插入不了一条id为2的记录,然后在查询数据还是发现没有id为2的记录,此时出现幻读,具体示例如下。

客户端A
在这里插入图片描述
客户端B
在这里插入图片描述
关于幻读,还有一个更经典的例子,那就是小明的老婆查到小明的银行卡上有10000块钱,准备转出去时,正好小明此时正好在外面胡吃海塞后在收银台买单,消费了这10000块钱并且提交事物,小明的老婆转账时提示余额不足,不相信又查了一下账上余额,结果发现账上仍有10000块钱,就是转不出去,转账转到怀疑自己产生了幻读。

有个问题:当事物隔离级别达到串行化时,可以规避脏读,不可重复读,幻读等问题,为什么平常我们所用的数据不用这一隔离级别呢?比如oracle默认用的是read commit,mysql用的是repeatable-read,原因是串行化让事物一个一个的进行,不能并行从而大大降低了系统的效率。

关于数据库的知识很多,后面陆续会写索引、悲观锁、乐观锁等知识。

发布了80 篇原创文章 · 获赞 133 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/chekongfu/article/details/97646688