- 事务 (transaction)的特性 ACID
Atomicity
Transactions are atomic units of work that can be committed or rolled back.
Consistency
Isolation
支持并发操作,事务间互不干扰
MySQL:支持多事务并发工作的系统
Durability
Commit命令执行成功后,此次事务操作石锤
事务的生命周期管理
标准的事务控制语句(显式)
-
开启事务
begin / start transaction; -
提交事务
commit -
回滚事务
rollback
begin;
DML1
DML2
DML3
rollback; / commit;
标准的事务语句
insert
update
delete
select
//case 1
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> use world
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> delete from city where id > 10;
Query OK, 4069 rows affected (0.06 sec)
mysql> rollback;
Query OK, 0 rows affected (0.05 sec)
// case 2
mysql> begin ;
Query OK, 0 rows affected (0.00 sec)
mysql> delete from city where id > 10;
Query OK, 4069 rows affected (0.06 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
- DDL语句无法回滚:删库 trancake
自动提交功能
mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
| 1 |
+--------------+
1 row in set (0.00 sec)
//重新导入world.sql
mysql> source /root/world.sql;
mysql> delete from city where id > 10;
Query OK, 4069 rows affected (0.09 sec)
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)
//失效!
autocommit = 1 时,没有加begin(没有显式开启事务)
执行结束后自动添加commit;
每条语句都是一个事务 --> 非交易类场景
交易类业务:
plan a: 将autocommit = 0
plan b: 每次发生事务时,显式声明begin, commit;
设置方法:
(1)临时生效
mysql> set global autocommit=0;
Query OK, 0 rows affected (0.00 sec)
(2) 永久生效
在my.cnf内添加:autocommit=0
重启mySQL:
[root@localhost ~]# /etc/init.d/mysqld restart
Shutting down MySQL.... SUCCESS!
Starting MySQL. SUCCESS!
隐式事务控制语句
- 设置了autocommit=1
- 执行了非DML语句(DDL,DCL),自动提交上面的语句
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> delete from city where id=1;
Query OK, 1 row affected (0.00 sec)
mysql> create table t1(id int);
Query OK, 0 rows affected (0.02 sec)
mysql> select * from city;
+----+----------------+-------------+---------------+------------+
| ID | Name | CountryCode | District | Population |
+----+----------------+-------------+---------------+------------+
| 2 | Qandahar | AFG | Qandahar | 237500 |
| 3 | Herat | AFG | Herat | 186800 |
| 4 | Mazar-e-Sharif | AFG | Balkh | 127800 |
| 5 | Amsterdam | NLD | Noord-Holland | 731200 |
| 6 | Rotterdam | NLD | Zuid-Holland | 593321 |
| 7 | Haag | NLD | Zuid-Holland | 440900 |
| 8 | Utrecht | NLD | Utrecht | 234323 |
| 9 | Eindhoven | NLD | Noord-Brabant | 201843 |
| 10 | Tilburg | NLD | Noord-Brabant | 193238 |
+----+----------------+-------------+---------------+------------+
9 rows in set (0.00 sec)
mysql> rollback;
Query OK, 0 rows affected (0.01 sec)
mysql> select * from city;
+----+----------------+-------------+---------------+------------+
| ID | Name | CountryCode | District | Population |
+----+----------------+-------------+---------------+------------+
| 2 | Qandahar | AFG | Qandahar | 237500 |
| 3 | Herat | AFG | Herat | 186800 |
| 4 | Mazar-e-Sharif | AFG | Balkh | 127800 |
| 5 | Amsterdam | NLD | Noord-Holland | 731200 |
| 6 | Rotterdam | NLD | Zuid-Holland | 593321 |
| 7 | Haag | NLD | Zuid-Holland | 440900 |
| 8 | Utrecht | NLD | Utrecht | 234323 |
| 9 | Eindhoven | NLD | Noord-Brabant | 201843 |
| 10 | Tilburg | NLD | Noord-Brabant | 193238 |
+----+----------------+-------------+---------------+------------+
9 rows in set (0.00 sec)
- 隐式回滚:
中途出事了,系统自动回滚
InnoDB 事务的ACID
名词认识
(1)重做日志
redo log : ib_logfile0~N 48M, 0~N
轮询使用,记录数据页的变化
redo log buffer: redo 内存区域
(2)数据页存储位置
ibd : 存储数据行和索引
buffer pool: 缓冲区池,数据页和索引的缓冲
(3)LSN: 日志序列号
保证数据一致性
磁盘数据页,redo文件,buffer pool,redo buffer
MySQL每次启动,必须:磁盘数据页和redo log的LSN一致
(4)WAL:Write ahead log
日志优先写的方式实现持久化(日志写更加高效)
异步写
(5)脏页
(6)检查点
将脏页刷写到磁盘的动作
(7)TXID:事务号
(8)undo:ibdata1
存储了事务工作过程中的回滚信息
-
CSR = redo + undo
-
一致性快照(SnapShot)
-
隔离级别和锁机制
- transaction_isolation 事务隔离性
1》 RU(Read Uncommited): 读未提交
问题: 脏页读,不可重复读,幻读
2》RC(Read Commited): 读已提交
问题:不可重复读,幻读
3》RR(Repeatable Read): 可重复读 (默认)
问题:幻读
利用Undo的一致性快照读
4》SR(Serializable ): 可串行化
问题:串行化事务,但是不利于事务的并发
读指的是:page的读取(存储引擎的读(物理读),不是SQL层面的读)
脏读:别人的修改导致我的操作不正确
不可重复读,别人的修改导致我一个事务中同样操作不结果不一致
幻读:别人的修改,导致我的事务结果和预期不一致
RR 通过加入 GAP锁(间隙锁),next-lock避免幻读(基于辅助索引,在索引上加锁)