【持久层】数据库事务基础

内容导读:

前三节数据库事务、并发带来的风险以及数据库锁都是为了铺垫事务的隔离性。

事务的隔离性不是无缘无故就存在的,他的存在是为了解决某一类问题,带来某一些操作的便捷;解决的问题是指数据库并发操作中数据一致性保证,带来的便捷是指定义好隔离级别之后,数据库会为操作自动加锁(不同的隔离级别拥有不同的自动锁粒度),而不用每次操作都手动的加锁。

写着写着觉得没什么可写的,本文已沦为简单的笔记····

一、数据库事务

将一组数据库操作看作一个具备特殊数据库语义的执行单元,该执行单元具备ACID的事务属性。在数据库事务的ACID属性中,原子性、隔离性和持久性都是为了保证数据的一致性。ACID的数据库语义如下所示。

1. atomic(原子性)

该执行单元中的所有操作,要么全部执行成功,要么全部不执行。

2. consistency(一致性)

执行单元执行完成前后的状态是一致的。一个转账的例子加以说明。

转账前状态:A账户1000块,B账户1000块,转账前的状态是A+B=2000块;

执行单元操作:A向B转账200块;

转账后状态:A账户800块,B账户1200块,转账后的状态是A+B=2000块;

结论:转账前和转账后的状态一致,都是2000块;并没有发生状态不一致情况导致账户A、账户B或银行中任何一方受损或受益。

3. isolation(隔离性)

隔离性描述的是数据库对待并发操作的态度,即在并发操作数据库的环境下,不同事务之间对彼此造成影响的程度。根据用户对数据一致性环境的需求,数据库支持不同的隔离级别。

千万要注意,在数据库并发环境下讨论隔离性才有意义,本质上数据库的隔离级别就是自动事务的代名词。更多细节,下文详细讨论。

4. durability(持久性)

持久性描述的是当事务成功提交之后,提交数据会被持久化到数据库中,即使数据库立即崩溃,也能够在重启的时候恢复。持久性基于操作日志,简单来说,就是记录数据库操作语句,一条数据库语句包含了数据库的操作和数据,因此只要日志不受损,即使数据库存储介质损坏,也能够通过日志恢复。

二、并发带来的风险

并发操作数据库会导致一些风险,这些风险可以归类为三类读问题和两类更新问题。

1. 脏读

一个事务中读到另一个事务未提交的update。如下图所示,事务A中读到了事务B中未提交的操作,从而导致出现数据不一致的状况。

2. 不可重复度

一个事务中读到另一个事务提交的update。和脏读的区别是,读到的update事务是否已被提交。

读到另一个事务提交的update在大多数情况下无伤大雅,但是如果是在月底做报表的时候,这种情况就出问题了。你需要统计上一个月的数据,但是在统计过程中不断有update,即便你在准确的时间点开启了事务,但是统计的数据依然不准确。解决的办法是为数据库加锁,但是如果你觉得每次统计都重复相同的动作会很麻烦,可以设置隔离级别,让数据库为你自动加锁。

3. 虚读

一个事务中读到另一个事务提交的insert。和不可重复读的区别是,一个是读到提交的update,一个是读到提交的insert。

借用不可重复读中月底报表的例子,读到提交的update,这意味着数据库中原来就存在该条记录,这是修改了字段;而读到insert,则意味着数据库中原来是不存在这条记录的。虽然在统计的sql中添加了where的时间条件,但是读到存在此前的记录和不存在的记录,显然事务之间的影响程度是不一样的。

4. 第一类丢失更新

一个事务的回滚覆盖了另一个事务提交的update。这类丢失更新对数据库造成的影响是很严重的,除非数据库不支持事务,否则无论哪一种隔离级别都必须防止该风险。

5. 第二类丢失更新

一个事务提交的update覆盖了另一个事务提交的update。

三、数据库锁

锁不外乎独占锁和共享锁,放在数据库环境中有行锁和表锁,再细粒度分下来,行共享锁、行独占锁、表共享锁、表独占锁、表共享行独占锁。数据库锁和程序中的锁作用相似,都是为了解决并发环境中的风险——安全性、活跃性和性能问题。

我们什么都没有,唯一的本钱就是青春。

【持久层】数据库事务基础

相关文章:

你感兴趣的文章:

标签云: