事务是一组逻辑处理单位,可以是执行一条SQL语句,也可以是执行几个SQL语句。
事务用来保证数据由一种存储情况变为另一种情况,组成事务的各个单元要么都执行成功,要么都执行失败。
1.2 为什么使用事务如果只是简单的一条SQL语句的执行,那么是不需要事务的,但在一些复杂的情况下,一个操作会涉及到多条SQL语句的执行,这种情况下就有必要保证所有的操作全部成功或者全部失败。
比如,小明给小红转账的一个操作,就会涉及到从小明账户扣钱和给小红账户充钱的两个操作。只有两个操作都成功执行了整个操作才算成功,这时就可以提交整个事务,可以说状态由转账前变到了转账后。否则有任何一个操作执行失败的话整个操作都要算做失败,这时就需要恢复事务,保证两个账户上的金额和转账前是一样的,表示恢复到了转账前的状态。
所以事务是为了保证一组操作的完整性而出现的,也是为了保证数据操作的安全。
1.3 支持使用事务的引擎使用“show engines;”命令查看数据库支持的存储引擎,以及存储引擎是否支持事务:
mysql> show engines; +--------------------+---------+--------------+------+------------+ | Engine | Support | Transactions | XA | Savepoints | +--------------------+---------+--------------+------+------------+ | FEDERATED | NO | NULL | NULL | NULL | | MRG_MYISAM | YES | NO | NO | NO | | MyISAM | YES | NO | NO | NO | | BLACKHOLE | YES | NO | NO | NO | | CSV | YES | NO | NO | NO | | MEMORY | YES | NO | NO | NO | | ARCHIVE | YES | NO | NO | NO | | InnoDB | DEFAULT | YES | YES | YES | | PERFORMANCE_SCHEMA | YES | NO | NO | NO | +--------------------+---------+--------------+------+------------+ 9 rows in set (0.00 sec) mysql>
发现默认的是InnoDB引擎,并且也支持事务。
1.4 基本术语保存点(savepoint):指在事务执行前,或者事务执行后,数据在数据库里的一个存储情况,有时也会被称为状态。
回退(rollback):指撤销事务的操作,事务执行期间执行的操作都将失效,事务会恢复到上一个状态。
提交(commit):值提交事务的操作,事务期间执行的操作全部生效,事务进入一个新的状态。
1.5 事务的特性(ACID)原子性(Atomicity):指事务包含的所有操作要么全部成功提交,要么全部失败回滚。
一致性(Consistency):指事务必须使数据库的数据和资源从一个一致性状态变换到另一个一致性状态。
隔离性(Isolation):指当多个用户并发访问数据库并且操作同一张表的时候,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
持久性(Durability):指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,哪怕是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
1.6 多事务并发操作产生的问题对数据库事务的操作其实可以分为两类:一种是读取事务(Select),另一种是修改事务(Insert、Update、Delete)。
单个事务的情况下,事务操作不会产生并发问题,但是如果多个事务在同一时刻操作同一数据可能会影响最终期望的结果,产生并发问题。
主要的问题有四种:
1)更新丢失:更新时更新。两个更新事务同时更新一个数据,就会导致一个事务的更新操作丢失。
2)脏读:更新时读取。一个更新事务更新一条数据时,另一个读取事务读取了还没提交的数据,这时如果更新事务进行回滚,就会导致读到脏数据。
3)不可重复读:读取时更新。一个读取事务多次读取一条数据时,另一个更新事务修改并提交了这条数据,就会导致在更新事务提交的前后读取到了不同的数据。
4)幻读:读取时插入或删除。一个读取事务读取时,另一个插入事务插入了一条数据,或者另一个删除任务删除了一条数据,这样就可能多读或者少读出一条数据,出现幻读。
1.7 事务的隔离级别因为多事务的并发问题的严重程度和解决问题产生的系统开销不同,为了解决不同程度的问题,SQL标准定义了隔离级别,每个级别都有各自的具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。
主要的隔离级别有四种:
1)Read Uncommitted(读未提交):最低的隔离级别,所有事务都可以看到其他未提交事务的执行结果。可避免更新丢失的发生。
2)Read Committed(读已提交):大多数数据库系统的默认隔离级别,但不是MySQL默认的,一个事务只能看见已提交事务所做的改变。可避免更新丢失、脏读的发生。
3)Repeatable Read(可重复读):MySQL的默认事务隔离级别,确保同一事务的多个实例在并发读取数据时,会看到同样的数据。可避免更新丢失、脏读、不可重复读的发生。
4)Serializable(串行化):最高的隔离级别,通过强制事务排序解决多事务的并发问题。简言之,它是在每个读的数据行上加上共享锁,但这么做可能导致大量的超时现象和锁竞争。可避免更新丢失、脏读、不可重复读、幻读的发生。
以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然级别越高,执行效率就越低。
像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。
MySQL的默认事务隔离级别是Repeatable Read级别,相比较其他存储引擎,InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了幻读的问题。
2 事务自动提交 2.1 语法查询事务自动提交:
select @@autocommit;
开启自动提交:
set autocommit = 1;
关闭自动提交:
set autocommit = 0;2.2 实例
mysql> set autocommit = 0; Query OK, 0 rows affected (0.00 sec) mysql> select @@autocommit; +--------------+ | @@autocommit | +--------------+ | 0 | +--------------+ 1 row in set (0.00 sec) mysql>3 初始化事务 3.1 语法
首先声明初始化MySQL事务后所有的SQL语句为一个单元。语法如下:
start transaction
另外,用户也可以使用“begin;”或者“begin work;”命令初始化事务,通常“start transaction;”命令后面跟随的是组成事务的SQL语句。
3.2 实例mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql>4 提交事务 4.1 语法
在用户没有提交事务之前,其他用户查询的结果不会显示没有提交的事务。只有用户成功提交事务后,其他用户才可能查询到事务结果。语法如下:
commit;
也可以使用“commit work;”提交事务。
4.2 实例mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> update student set sex = '女' where id = 904; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> commit; Query OK, 0 rows affected (0.01 sec) mysql>5 回滚事务 5.1 语法
如果用户想要回滚未提交的事务操作,可使用回滚事务。语法如下:
rollback;
也可以使用“rollback work;”回滚事务。
5.2 实例mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> update student set sex = '女' where id = 904; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> rollback; Query OK, 0 rows affected (0.00 sec) mysql>6 设置还原点
还原点必须要在事务内才能使用,否则会产生错误。
6.1 语法创建还原点:
savepoint 名称;
回滚还原点:
rollback to 名称;
删除还原点:
release savepoint 名称;7 事务的隔离级别 7.1 语法
查看当前事务的隔离级别:
select @@tx_isolation;
设置隔离级别:
set tx_isolation = "隔离级别名称";8 多事务并发问题 8.1 更新丢失
即便是在最低隔离级别Read Uncommitted的事务里,也能避免更新丢失问题:
当两个事务同时更新同一数据时,左侧事务执行成功,右侧事务执行被阻塞,直到左侧事务进行了提交或者回滚,或者右侧事务因为阻塞超时而报错,才能结束阻塞。
8.2 脏读在最低隔离级别Read Uncommitted的事务里,不能避免脏读的问题:
在隔离级别Read Committed以及高于这个级别的事务里,可以避免脏读的问题:
8.3 不可重复读在隔离级别Read Committed以及低于这个级别的事务里,不能避免不可重复读的问题:
在隔离级别Repeatable Read以及高于这个级别的事务里,可以避免不可重复读的问题:
8.4 幻读在隔离级别Repeatable Read以及低于这个级别的事务里,不能避免幻读的问题,但如果MySQL数据库使用的存储引擎是InnoDB则可以避免幻读的问题。
在隔离级别Read Committed的事务里,出现幻读的问题:
在隔离级别Repeatable Read的事务里,如果MySQL数据库使用的存储引擎是InnoDB则可以避免幻读的问题:
在最高级别Serializable的事务里,也可以避免幻读的问题,不过最高级别的系统开销很大,一般不会使用。



