当前位置: 代码迷 >> 综合 >> 数据库事务的四大特性(ACID)
  详细解决方案

数据库事务的四大特性(ACID)

热度:28   发布时间:2024-02-07 21:12:00.0

ACID,指数据库事务正确执行的四个基本要素的缩写。包含:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。一个支持事务(Transaction)的数据库,必需要具有这四种特性,否则在事务过程(Transaction processing)当中无法保证数据的正确性,交易过程极可能达不到交易方的要求。

一.事务

定义:所谓事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。

⑴ 原子性(Atomicity)

第一个原子性,这个是最简单的。说的是一个事务内所有操作共同组成一个原子包,要么全部成功,要么全部失败。这是最基本的特性,保证了因为一些其他因素导致数据库异常,或者宕机。

保证原子性的方法:

在数据库管理系统(DBMS)中,默认情况下一条SQL就是一个单独事务,事务是自动提交的。
只有显式的使用start transaction开启一个事务,才能将一个代码块放在事务中执行。
保障事务的原子性是数据库管理系统的责任,为此许多数据源采用日志机制。
例如,SQL Server使用一个预写事务日志,在将数据提交到实际数据页面前,先写在事务日志上。

⑵ 一致性(Consistency)

第二一致性,这个是大家误解最深的,很多博客都喜欢用银行转账的例子来讲一直性,所谓的一致性是基于原子性。

原子性只保证了一个事务内的所有操作同一性,大家同生死,不会出现你死了,我还活着。但是,原子性并没有保证大家同一时刻一起生,一起死。计算机指令是有先后顺序的,这样就决定了一个事物的提交,会经历一个时间过程,那么如果事物提交进行到了一半,我读取了数据库,会不会读到中间结果?

为了防止这样的情况,数据库事务的一致性就规定了事务提交前后,永远只可能存在事务提交前的状态和事物提交后的状态,从一个一致性的状态到另一个一致性状态,而不可能出现中间的过程态。也就是说事务的执行结果是量子化状态,而不是线性状态。

数据库提交事务会有一个过程,如果提交的时候,存在一个时间差,在提交的第一秒,一个删除过程还没完成到了第三秒才完成,会不会第一秒访问的人和第三秒访问的人得到不同的结果?出现不一致,状态的混沌?这就是一致性得保证的只会有前状态和后状态,绝不会出现中间态。

保证一致性的方法:

2.1数据库机制层面数据库层面的一致性是,在一个事务执行之前和之后,数据会符合你设置的约束(唯一约束,外键约束,Check约束等)和触发器设置。
这一点是由SQL SERVER进行保证的。比如转账,则可以使用CHECK约束两个账户之和等于2000来达到一致性目的2.2业务层面对于业务层面来说,一致性是保持业务的一致性。这个业务一致性需要由开发人员进行保证。
当然,很多业务方面的一致性,也可以通过转移到数据库机制层面进行保证。

⑶ 隔离性(Isolation)

事务的隔离性,基于原子性和一致性,因为事务是原子化,量子化的,所以,事务可以有多个原子包的形式并发执行,但是,每个事务互不干扰。

但是,由于多个事务可能操作同一个资源,不同的事务为了保证隔离性,会有很多锁方案,当然这是数据库的实现,他们怎么实现的,我们不必深究。

保证隔离性的方法:

 1.事务之间的相互影响

事务之间的相互影响分为几种,分别为:脏读,不可重复读,幻读,丢失更新

1.1脏读

脏读意味着一个事务读取了另一个事务未提交的数据,而这个数据是有可能回滚的;

1.2不可重复读

不可重复读意味着,在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。这是由于查询时系统中其他事务修改的提交而引起的。

1.3幻读(虚读)

幻读,是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样.

 1.4丢失更新

两个事务同时读取同一条记录,A先修改记录,B也修改记录(B是不知道A修改过),B提交数据后B的修改结果覆盖了A的修改结果。

理解SQL SERVER中的隔离级别

数据库的事务隔离级别(TRANSACTION ISOLATION LEVEL)是一个数据库上很基本的一个概念。为什么会有事务隔离级别,SQL Server上实现了哪些事务隔离级别?事务隔离级别的前提是一个多用户、多进程、多线程的并发系统,在这个系统中为了保证数据的一致性和完整性,我们引入了事务隔离级别这个概念,对一个单用户、单线程的应用来说则不存在这个问题。

为了避免上述几种事务之间的影响,SQL Server通过设置不同的隔离级别来进行不同程度的避免。因为高的隔离等级意味着更多的锁,从而牺牲性能。所以这个选项开放给了用户根据具体的需求进行设置。不过默认的隔离级别Read Commited符合了多数的实际需求.

Read UnCommitted 读取未提交内容

在这个隔离级别,所有事务都可以“看到”未提交事务的执行结果。在这种级别上,可能会产生很多问题,除非用户真的知道自己在做什么,并有很好的理由选择这样做。本隔离级别很少用于实际应用,因为它的性能也不必其他性能好多少,而别的级别还有其他更多的优点。读取未提交数据,也被称为“脏读”

Read Committed 读取提交内容

大多数数据库系统的默认隔离级别(但是不是MySQL的默认隔离级别),满足了隔离的早先简单定义:一个事务开始时,只能“看见”已经提交事务所做的改变,一个事务从开始到提交前,所做的任何数据改变都是不可见的,除非已经提交。这种隔离级别也支持所谓的“不可重复读”。这意味着用户运行同一个语句两次,看到的结果是不同的。

Repeatable Read 可重复读

MySQL数据库默认的隔离级别。该级别解决了READ UNCOMMITTED隔离级别导致的问题。它保证同一事务的多个实例在并发读取事务时,会“看到同样的”数据行。不过,这会导致另外一个棘手问题“幻读”。InnoDB和Falcon存储引擎通过多版本并发控制机制解决了幻读问题。

Serializable 可串行化

该级别是最高级别的隔离级。它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简而言之,SERIALIZABLE是在每个读的数据行上加锁。在这个级别,可能导致大量的超时Timeout和锁竞争Lock Contention现象,实际应用中很少使用到这个级别,但如果用户的应用为了数据的稳定性,需要强制减少并发的话,也可以选择这种隔离级

修改隔离级别的方法

全局修改

全局修改需要修改MySql的全局文件mysql.ini,修改内容如下:

1 #可选参数有:READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE.
2 [mysqld]
3 transaction-isolation = REPEATABLE-READ

语句修改

在命令行模式下连上MySql后,可以使用下列语句查看MySql当前隔离级别

mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.00 sec)

可以使用下面的命令修改当前会话Session的隔离级

mysql> set session transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)mysql> select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+
1 row in set (0.00 sec)

AutoCommit 事务自动提交

MySql中有AutoCommit参数,默认为on,也就是开启状态。它的作用是每一条单独的查询都是一个事务,自动开始,自动提交(语句执行完成就提交。如果你要适用select for update,而不手动调用 start transaction,这个for update的行锁机制等于没用,因为行锁在自动提交后就释放了)。所以事务隔离级别和锁机制即使你不显式调用start transaction,这种机制在单独一条语句查询中也是适用的。
在命令行模式下可以使用下面的命令查看当前MySql的autocommit是否开启

mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set (0.00 sec)

如果需要关闭autocommit,我们可以使用下面语句设置

mysql> set autocommit=0;

⑷ 持久性(Durability)

持久性,当一个事务提交之后,数据库状态永远的发生了改变,这个事务只要提交了,哪怕提交后宕机,他也确确实实的提交了,不会出现因为

刚刚宕机了而让提交不生效,是要事务提交,他就像洗不掉的纹身,永远的固化了,除非你毁了硬盘。

锁机制

共享锁

由读表操作加上的锁,加锁后其他用户只能获取该表或行的共享锁,不能获取排它锁,也就是说只能读不能写

排它锁

由写表操作加上的锁,加锁后其他用户不能获取该表或行的任何锁,典型是mysql事务

根据锁的范围,可以分为

表锁

给整张表加锁

行锁

给行数据加锁

因此锁可以分为表级共享锁行级共享锁表级排它锁行级排它锁