浅析mysql事务-----ACID特性

概念

事务就是一组原子性的 SQL 查询,或者说一个独立的工作单元。如果数据库引擎能够成功地对数据库应用该组查询的全部语句,那么就执行该组查询。如果其中有任何一条语句因为崩溃或其他原因无法执行,那么所有的语句都不会执行。也就是说,事务内的语句,要么全部执行成功,要么全部执行失败。

生活例子说明

我们转账的一般都是:从你的账户扣除 100 元,然后再到其他人的账户中增加 100 元。但是如果在这中间,因为某些原因(网络问题),导致在你的账户中扣除了,但是没有在你朋友的账户中增加,那我们是不是直接损失了一百元,是不是找银行了。

所以,一般这种情况,就可以把这两个步骤放到一个事务里面。要么全部成功,自己的账户扣除一百,朋友的账户新增一百;要么全部失败,已经进行的操作退回去,恢复到最开始的状态,我的账户没有扣100,朋友的账户也没有加100。

mysql架构

注意: 事务是由存储引擎实现的,以下没有特殊说明默认innodb

提交回滚

mysql> start transaction;#手动开启事务
mysql> update t21 set b = 77 where b = 7;
Query OK, 3 rows affected (0.00 sec)
mysql> commit;#commit之后即可改变底层数据库数据
mysql> select * from t_user;
| id | a | b  |
+----+---+----+
|  1 | 1 |  1 |
|  2 | 2 |  2 |
|  3 | 3 | 33 |
|  4 | 4 |  4 |
|  6 | 5 |  5 |
|  7 | 7 |  7 |
|  8 | 8 |  8 |
|  9 | 8 |  7 |
| 10 | 2 |  7 |
+----+---+----+
9 rows in set (0.00 sec)


mysql> start transaction;
mysql> insert into t21(a,b) values(3,3);
mysql> rollback;
mysql> select * from t_user;
| id | a | b  |
+----+---+----+
|  1 | 1 |  1 |
|  2 | 2 |  2 |
|  3 | 3 | 33 |
|  4 | 4 |  4 |
|  6 | 5 |  5 |
|  7 | 7 |  7 |
|  8 | 8 |  8 |
|  9 | 8 |  7 |
| 10 | 2 |  7 |
+----+---+----+
9 rows in set (0.00 sec)

在mysql中默认支持自动提交,在自动提交模式下,如果没有start transaction显式地开始一个事务,那么每个sql语句都会被当做一个事务执行提交操作。

事务四大特性

  1. ​ atomicity(原子性) :要么全执行,要么全都不执行;
  2. ​ consistency(一致性):在事务开始和完成时,数据都必须保持一致状态;
  3. ​ isolation(隔离性) :事务处理过程中的中间状态对外部是不可见的;
  4. ​ durability(持久性) :事务完成之后,它对于数据的修改是永久性的。

原子性(atomicity)

定义

原子性是指一个事务是一个不可分割的工作单位,其中的操作要么都做,要么都不做;如果事务中一个sql语句执行失败,则已执行的语句也必须回滚,数据库退回到事务前的状态。

实现原理

mysql的原子性是通过undo日志实现的,接下来我们简单说下undo日志。

Undo log 是逻辑日志,将数据库逻辑地恢复到原来的样子,所有修改都被逻辑的取消了。

也就是如果是 insert 操作,其对应的回滚操作就是 delete;

如果是 delete,则对应的回滚操作是 insert;

如果是 update,则对应的回滚操作是一个反向的 update 操作。

持久性(durability)

定义

持久性是指事务一旦提交,它对数据库的改变就应该是永久性的。

实现原理

事务的持久性是通过redo日志实现的,我们下面简单介绍下redo日志。

与undo日志相反,redo日志是对新数据的备份。在事务提交前,只要将redo日志进行持久化,不需要将数据持久化。当系统崩溃时,只要根据redo日志的内容,将数据恢复到最新的状态。redo日志具体内容可以参考:mysql日志文件总结,这里我就不再说了

隔离性(isolation)

定义

与原子性、持久性侧重于研究事务本身不同,隔离性研究的是不同事务之间的相互影响。隔离性是指,事务内部的操作与其他事务是隔离的,并发执行的各个事务之间不能互相干扰。严格的隔离性,对应了事务隔离级别中的Serializable (可串行化),但实际应用中出于性能方面的考虑很少会使用可串行化。

实现原理

锁机制的基本原理可以概括为:事务在修改数据之前,需要先获得相应的锁;获得锁之后,事务便可以修改数据;该事务操作期间,这部分数据是锁定的,其他事务如果需要修改数据,需要等待当前事务提交或回滚后释放锁。

行锁与表锁

按照粒度,锁可以分为表锁、行锁以及其他位于二者之间的锁。表锁在操作数据时会锁定整张表,并发性能较差;行锁则只锁定需要操作的数据,并发性能好。但是由于加锁本身需要消耗资源(获得锁、检查锁、释放锁等都需要消耗资源),因此在锁定数据较多情况下使用表锁可以节省大量资源。MySQL中不同的存储引擎支持的锁是不一样的,例如MyIsam只支持表锁,而InnoDB同时支持表锁和行锁,且出于性能考虑,绝大多数情况下使用的都是行锁。

如何查看锁信息

有多种方法可以查看InnoDB中锁的情况,例如:

select * from information_schema.innodb_locks; #锁的概况
show engine innodb status; #InnoDB整体状态,其中包括锁的情况

下面举个例子:

# 第一个客户端
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> update t21 set b = 77 where b = 7;
Query OK, 3 rows affected (0.00 sec)
Rows matched: 3  Changed: 3  Warnings: 0


# 第二个客户端
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> update t21 set b = 77 where b = 7;

# 查询锁的情况
mysql> select * from information_schema.innodb_locks; 
+--------------+-------------+-----------+-----------+--------------+------------+------------+-----------+----------+-----------+
| lock_id      | lock_trx_id | lock_mode | lock_type | lock_table   | lock_index | lock_space | lock_page | lock_rec | lock_data |
+--------------+-------------+-----------+-----------+--------------+------------+------------+-----------+----------+-----------+
| 33048:41:3:2 | 33048       | X         | RECORD    | `muke`.`t21` | PRIMARY    |         41 |         3 |        2 | 1         |
| 33047:41:3:2 | 33047       | X         | RECORD    | `muke`.`t21` | PRIMARY    |         41 |         3 |        2 | 1         |
+--------------+-------------+-----------+-----------+--------------+------------+------------+-----------+----------+-----------+
2 rows in set, 1 warning (0.00 sec)

通过上述命令可以查看事务33048和33047占用锁的情况;其中lock_type为RECORD,代表锁为行锁(记录锁);lock_mode为X,代表排它锁(写锁)。

除了排它锁(写锁)之外,MySQL中还有共享锁(读锁)的概念

一致性(consistency)

定义

一致性是指事务执行结束后,数据库的完整性约束没有被破坏,事务执行的前后都是合法的数据状态。数据库的完整性约束包括但不限于:实体完整性(如行的主键存在且唯一)、列完整性(如字段的类型、大小、长度要符合要求)、外键约束、用户自定义完整性(如转账前后,两个账户余额的和应该不变)

实现原理

可以说,一致性是事务追求的最终目标:前面提到的原子性、持久性和隔离性,都是为了保证数据库状态的一致性。此外,除了数据库层面的保障,一致性的实现也需要应用层面进行保障。

实现一致性的措施包括:

  • 保证原子性、持久性和隔离性,如果这些特性无法保证,事务的一致性也无法保证
  • 数据库本身提供保障,例如不允许向整形列插入字符串值、字符串长度不能超过列的限制等
  • 应用层面进行保障,例如如果转账操作只扣除转账者的余额,而没有增加接收者的余额,无论数据库实现的多么完美,也无法保证状态的一致

学习链接

mysql日志可以看下这个地址:mysql日志文件总结

mysql事务隔离级别可以看下这个地址: mysql事务-----四种隔离级别

书籍是在时代波涛中航行的思想之船,它小心翼翼地把珍贵的货物运送给一代又一代。   ----培根

猜你喜欢

转载自blog.csdn.net/lin_keys/article/details/108902819