标签:
当多个用户访问同一份数据时候,一个用户在更改数据的过程中可能有其他用户同时发起更改请求,为保证数据的更改从一个一致性状态更改为另外一个一致性状态,从而引入事务。
MySQL提供了多种存储引擎支持事务,支持事务的存储引擎有InnoDB和BDB。InnoDB存储引擎事务主要通过UNDO日志和REDO日志实现。MyISAM和MEMORY存储引擎则不支持事务。
1. 事务概述事务的四个特性:
a. 原子性(Atomicity):事务中所有的操作视为一个原子单元,即对于事务所进行的数据修改等操作只能是完全提交或者完全回滚。
b. 一致性(Consistency):事务在完成时,必须使所有的数据从一种一致性状态变更为另外一种一致性状态,所有的变更都必须应用于事务的修改,以确保数据的完整性。
c. 隔离性(Isolation):一个事务中的操作语句所做的修改必须与其他事物所做的修改相隔离。在进行事务查看数据时数据所处的状态,要么是被另一并发事务修改之前的状态,要么是被另一并发事务修改之后的状态,即当前事务不会查看由另一个并发事务正在修改的数据,这种特性通过锁机制实现。
d. 持久性(Durability):事务完成之后,所做的修改对数据的影响是永久的,即使系统重启,或者出现系统故障数据仍可以恢复。
MySQL提供了多种事务型存储引擎支持,如InnoDB和BDB等,而MyISAM不支持事务,InnoDB支持ACID事务,行级锁和高并发。为支持事务,InnoDB存储引擎引入了与事务相关的UNDO日志和REDO日志,同时事务依赖于MySQL提供的锁机制。
1.1 REDO日志
事务执行时需要将执行的事务日志写入到日志文件里,对应的日志文件为REDO日志。当每条SQL进行数据库更新操作时,首先将REDO日志写入到日志缓冲区。当客户端执行COMMIT命令提交时,日志缓冲区的内容将被刷新到磁盘,日志缓冲区的刷新方式或者时间间隔可以通过参数innidb_flush_log_at_trx_commit控制。
REDO日志对应于磁盘上的ib_logfileN文件,该文件默认为5MB,建议设置成512MB以便容纳较大的事务。在MySQL崩溃恢复时会重新执行REDO日志中的记录。
1.2 UNDO日志
UNDO日志与 REDO日志相反,UNDO日志主要用于事务异常时的数据回滚,具体内容就是复制事务前的数据库内容到UNDO缓冲区,然后在合适的时间将内容刷新到磁盘。
与REDO日志不同的是,磁盘上不存在单独的UNDO日志文件,所有的UNDO日志均存放在表空间对应的.ibd数据文件中,即使MySQL服务启用了独立表空间,依然如此。UNDO日志又称为回滚段。
2. MySQL事务控制语句
MySQL中使用事务BEGIN事务,事务OMMIT结束事务,中间可以使用ROLLBACK回滚事务。MySQL通过SET AUTOCOMMIT,START TRANSACTION,COMMIT和ROLLBACK等语句支持本地事务。语法如下:
START TRANSACTION | BEGIN [WORK] COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE] ROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE] SET AUTOCOMMIT = {0 | 1}
在默认设置下,MySQL中的事务是默认提交的。如需对某些语句进行事务控制则使用START TRANSACTION或者BEGIN开始一个事务比较方便。这样事务结束之后可以自动回到自动提交的方式。
下面示例演示一个简单的事务,功能为更新表中的一条记录,为保证数据从一个一致性状态更新到另外一种一致性状态,因此采用事务完成更新过程,如果更新失败或者其他原因可以使用回滚。此实例执行时对应的MySQL默认隔离级别为REPEATABLE-READ。
#查看MySQL隔离级别 mysql> show variables like ‘tx_isolation‘; +---------------+-----------------+ | Variable_name | Value | +---------------+-----------------+ | tx_isolation | REPEATABLE-READ | +---------------+-----------------+ 1 row in set (0.33 sec) #创建测试需要的表,主要存储引擎为InnoB mysql> use company; Database changed mysql> create table test_1(id int,username varchar(20)) engine=InnoDB; Query OK, 0 rows affected (0.67 sec) mysql> insert into test_1 values(1,‘petter‘),(2,‘bob‘),(3,‘allen‘),(4,‘aron‘); Query OK, 4 rows affected (0.17 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql> select * from test_1; +------+----------+ | id | username | +------+----------+ | 1 | petter | | 2 | bob | | 3 | allen | | 4 | aron | +------+----------+ 4 rows in set (0.00 sec) #开启一个事务 mysql> begin; Query OK, 0 rows affected (0.02 sec) #更新一条记录 mysql> update test_1 set username=‘test‘ where id = 1; Query OK, 1 row affected (0.06 sec) Rows matched: 1 Changed: 1 Warnings: 0 #提交事务 mysql> commit; Query OK, 0 rows affected (0.06 sec) #发现记录已经更改生效 mysql> select * from test_1; +------+----------+ | id | username | +------+----------+ | 1 | test | | 2 | bob | | 3 | allen | | 4 | aron | +------+----------+ 4 rows in set (0.00 sec) #开启另外一个事务 mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> update test_1 set username=‘petter‘ where id = 1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from test_1; +------+----------+ | id | username | +------+----------+ | 1 | petter | | 2 | bob | | 3 | allen | | 4 | aron | +------+----------+ 4 rows in set (0.00 sec) #回滚事务 mysql> rollback; Query OK, 0 rows affected (0.13 sec) #此时发现数据已经回滚 mysql> select * from test_1; +------+----------+ | id | username | +------+----------+ | 1 | test | | 2 | bob | | 3 | allen | | 4 | aron | +------+----------+ 4 rows in set (0.00 sec)
3. MySQL事务隔离级别
SQL标准定义了四种隔离级别,指定了事务中哪些数据改变其他事务可见,哪些数据改变其他事务不可见,低级别的隔离级别可以支持更高的并发处理,同时占用的系统资源更少。
查看MySQL隔离级别:
SHOW VARIABLES LIKE ‘tx_isolation‘;
事务隔离级别可以使用以下语句设置:
#未提交读 SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; #提交读 SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED; #可重复读 SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ; #可串行化 SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
3.1 READ-UNCOMMITTED(读取未提交内容)
在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。因为其性能也不比其他级别高很多,因此此隔离级别实际应用中很少使用,读取未提交的数据被称为脏读(Dirty Read)。
脏读示例如下:
3.2 READ-COMMITTED(读取提交内容)
这是大多数数据库系统的默认隔离级别,但并不是MySQL默认的隔离级别。其满足了隔离的简单定义,一个事务从开始到提交前所做的任何改变都是不可见的,事务只能看见已经提交事务所做的改变。这种隔离级别也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理期间可能会有新的数据提交导致数据改变,所以同一查询可能返回不同的结果。此级别导致的不可重复读示例如下所示:
3.3 REPEATABLE -READ(可重读)
这是MySQL的默认事务隔离级别,能确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。理论上会导致幻读(Phantom Read)。例如第一个事务对一个表中 的数据进行了修改,这种修改涉及表中的全部数据行。同时第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行。InnoDB和Falcon存储引擎通过多版本并发控制(Multi_Version Concurrency Control,MVCC)机制解决了该问题。
InnoDB存储引擎MVCC机制:
3.3 SERIALIZABLE(可串行化)
标签:
原文地址:http://www.cnblogs.com/longshiyVip/p/4657342.html