bitscn.com
mysql事务的学习整理
事务是数据库区别文件系统的重要特征之一。在文件系统中,如果你正在写文件,但是操作系统突然崩溃了,这个时候文件有可能会被损坏的,当然也会有一些机制让文件恢复到某一个时间点,比如依靠原有的备份等。
1 引入事务的目的
数据库系统引入事务的主要目的:事务会把数据库从一种一致状态转换成另外一种状态。在数据库提交工作时,可以确保其要么所有修改都已经保存了,要么所有修改都不保存。
2 acid简介
innodb存储引擎中的事务完全符合acid的特性。acid是如下:
原子性 (atomicity)
原子性是指一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。只有使事务中所有的数据库操作执行都成功,才算整个事务成功。只要有一个sql语句执行失败,那么在这个事务中已经执行的sql语句都必须撤销,数据库状态应该退回到执行事务前的状态。
一致性(consistency)
事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。在事务开始之前和结束之后,数据库的完整性约束没有被破坏。
隔离性 (isolation)
一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰,这些通过锁来实现。
持久性(durability)
持续性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障(比如说宕机等)不应该对其有任何影响。
3 事务的实现
隔离性 (isolation)通过锁来实现,其他3个原子性atomicity,一致性consistency,持久性durability通过数据库的redo和undo来完成。
3.1 redo
在innodb存储引擎中,事务日志通过redo日至文件和innodb存储引擎的日志缓冲(innodblog buffer)来实现。当开始一个事务时候,会纪录该事务的一个lsn(log sequence number日志序列号);当事务执行时候,会往innodb存储引擎的日志缓冲里插入事务日志;当事务提交时,必须将innodb存储引擎的日志缓冲写入disk(默认的实现,即innodb_flush_log_at_trx_commit=1)。也就是在写数据之前,需要先写日志,这种方式称为预写日志方式wal(write-ahead logging)。
innodb存储引擎通过预写日志的方式来保证事务的完整性。这意味着disk上存储的数据页和内存缓冲池中的页是不同步的,对于内存缓冲池中页的修改,先是写入redo日志文件,然后再写入磁盘,因此是一种异步的方式,可以通过show engine innodb status;来观察当前disk和log的差距:
create table z (a int,primary key(a))engine=innodb;delimiter $$use test $$drop procedure if exists`test`.`load_test`$$create procedure load_test(count int)begin declare i int unsigned default 0; start transaction; while i show variables like 'autocommit'; +---------------+-------+ | variable_name | value | +---------------+-------+ | autocommit | on | +---------------+-------+ 1 row in set (0.00 sec) mysql> mysql> show global status like'com_commit'; +---------------+-------+ | variable_name | value | +---------------+-------+ | com_commit | 0 | +---------------+-------+ 1 row in set (0.00 sec) mysql> use test; database changed mysql> show tables; +----------------+ | tables_in_test | +----------------+ | t | | t1 | | t3 | | z | +----------------+ 4 rows in set (0.00 sec) mysql> insert into z select 1; query ok, 1 row affected (0.00 sec) records: 1 duplicates: 0 warnings: 0 mysql> select * from z; +---+ | a | +---+ | 1 | +---+ 1 row in set (0.00 sec) mysql> show global status like'com_commit'; +---------------+-------+ | variable_name | value | +---------------+-------+ | com_commit | 0 | +---------------+-------+ 1 row in set (0.00 sec) mysql>
可以看出来com_commit 始终为0 ,这就是隐式提交的时候,不计入com_commit和com_rollback中的。
另外mysql还有2个参数 handler_commit和handler_rollback,这2个参数在mysql5.1种可以很好的统计innodb的显示和隐式的事务提交操作,而在innodb plugin中这2个参数的统计值有些怪异,不能很好的统计事务的次数。
[sql] mysql> show global status like'handler_commit'; +----------------+-------+ | variable_name | value | +----------------+-------+ | handler_commit | 17 | +----------------+-------+ 1 row in set (0.00 sec) mysql> show global status like'handler_rollback'; +------------------+-------+ | variable_name | value | +------------------+-------+ | handler_rollback | 0 | +------------------+-------+ 1 row in set (0.00 sec) mysql>
因此如果都是显示控制事务的提交和会滚得话,可以用com_commit com和rollback这2个参数,否则情况就有些复杂。
bitscn.com