什么是事务(摘自菜鸟教程)
MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你既需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!
在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。
事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行。
事务用来管理 insert,update,delete 语句
一般来说,事务是必须满足4个条件(ACID)::原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。
原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
在 MySQL 命令行的默认设置下,事务都是自动提交的,即执行 SQL 语句后就会马上执行 commit 操作。因此要显式地开启一个事务务须使用命令 begin 或 start transaction,或者执行命令 set autocommit=0,用来禁止使用当前会话的自动提交。
隔离级别
并发情况下事务引发的问题
一般情况下,多个单元操作(事务,这里的事务,并不是完美的事务)并发执行,会出现这么几个问题:
- 脏读:A事务还未提交,B事务就读到了A操作的结果。(破坏了隔离性)
- 不可重复读:A事务在本次事务中,对自己未操作过数据,进行多次读取,结果出现不一致或记录不存在的情况。(破坏了一致性,重点是update和delete)
- 幻读:A事务在本次事务中,先读取了一遍数据,发现数据不存在,过了一会,又读取了一遍,发现又有数据了。(破坏了一致性,重点是insert)
解决(制定标准)
为了权衡『隔离』和『并发』的矛盾,ISO定义了4个事务隔离级别,每个级别隔离程度不同,允许出现的副作用也不同。
- 未提交读(read-uncommitted):最低级别,基本只保证持久性;会出现脏读,不可重复读,幻读的问题。
- 已提交读(read-committed):语句级别;会出现不可重复读,幻读的问题。
- 可重复读(repeatable-read):事务级别;只会出现幻读问题。
- 串行化(serializable):最高级别,也就是事务与事务完全串行化执行,无并发可言,性能低;但不会出现任何问题。
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read-uncommitted) | 会 | 会 | 会 |
不可重复读(read-committed) | - | 会 | 会 |
可重复读(repeatable-read) | - | - | 会 |
串行化(serializable) | - | - | - |
注意:这四个级别只是一个标准,各个数据库厂商,并不完全按照标准做的。
实现(InnoDB)
-
锁机制:阻止其他事务对数据进行操作, 各个隔离级别主要体现在读取数据时加的锁的释放时机。
- RU:事务读取时不加锁
- RC:事务读取时加行级共享锁(读到才加锁),一旦读完,立刻释放(并不是事务结束)。
- RR:事务读取时加行级共享锁,直到事务结束时,才会释放。
- SE:事务读取时加表级共享锁,直到事务结束时,才会释放。
其他还有一些细节不同,主要就是这些
-
MVCC机制:生成一个数据快照,并用这个快照来提供一定级别的一致性读取,也称为多版本数据控制。
- 实际就是『版本控制』加『读写分离』思想,主要用作于RC和RR级别。
隔离性所相关的锁机制
InnoDB 默认是行锁。但是如果在事务操作过程中,没有使用索引,那么系统会自动全表检索数据,自动升级为表锁。
行锁:只有当前行被锁住,别的用户不能操作
表锁:整张表被锁住,别的用户都不能操作
MySQL手动处理事务
通俗来理解,就是身后事。
事务:一系列要发生的连续的操作
事务安全:一种保护连续操作同时满足(实现)的机制
事务安全的意义:保证数据操作的完整性
最经典的例子是银行转账
需求:有一张银行账户表,A用户给B用户转账;A账户减少,B账户增加。如果A转账操作之后断电或者服务器宕机,怎么办?打架打官司?
解决方案:A减少[但不是立即修改数据表],B增加之后,同时修改数据表,要么都成功,要么都失败。比如场景:转账名错误,退回;到商店买烟;到图书馆借书等
建数据表
create table if not exists t_account(
number char(16) not null unique comment'账户',
name varchar(20) not null comment '姓名',
balance decimal(7,2) not null default 0.0
)ENGINE=INNODB charset=utf8;
insert into t_account VALUES ('00001','张三',5000),('00002','李四',3000);
select * from t_account;
alter table t_account add id int auto_increment primary key first; # 新增一列
事务操作
-
开启事务 start transaction
告诉系统以下所有的操作(写)不要直接写入到数据表,先存放到事务日志。
事务日志在***C:\ProgramData\MySQL\MySQL Server 5.7\Data*** -
事务操作
A—操作1
B—操作2 -
关闭事务
选择性的将日志文件中操作的结果保存到数据表(同步)并清空或者说直接清空事务日志(原来操作全部清空)
A—提交事务:同步数据表(操作成功)commit
B—回滚事务:直接清空日志表(操作失败)rollback
跟钱有关的涉及到安全问题的基本都用事务解决,前提引擎是InnoDB
事务的原理
事务开启之后,所有的操作都会临时保存到事务日志,事务日志只有在得到commit命令才会同步打数据表,其他任何情况都会清空(rollback)
回滚点
在某个成功的操作完成之后,后续的操作有可能成功有可能失败,但是不管成功还是失败,前面操作都已经成功,可以在当前的位置设置一个点,可以供后续失败操作返回到该位置,而不是返回所有操作。
rollback 之前的操作都不要
rollback to 部分操作不要
事务管理常用命令
-
begin或 start transaction 显式地开启一个事务;
-
commit 也可以使用 commit work,不过二者是等价的。commit 会提交事务,并使已对数据库进行的所有修改成为永久性的;
-
rollback 也可以使用 rollback work,不过二者是等价的。回滚会结束用户的事务,并撤销正在进行的所有未提交的修改;
-
savepoint identifier,savepoint 允许在事务中创建一个保存点,一个事务中可以有多个 savepoint;
-
release savepoint identifier 删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;
-
rollback to identifier 把事务回滚到标记点;
-
set transaction 用来设置事务的隔离级别。InnoDB 存储引擎提供事务的隔离级别有read uncommitted、read committed、repeatable read 和 serializable。
自动事务处理
在mysql中,默认的都是自动事务处理,用户操作完会立即同步到数据表中
mysql服务通过autocommit变量控制
show variables like 'autocommit';
关闭自动提交
set autocommit=0;
或
set autocommit=off;
自动关闭之后,需要手动处理,即commit 或者rollback