事务定义
事务是一组原子性的SQL查询,或者说是一个独立的工作单元。如果数据库引擎能够成功地对数据库应用该组查询的全部语句,那么就执行该组查询。如果其中有任何一跳语句因为崩溃或其他原因无法执行,那么所有的语句都不会执行。也就是说,事务内的语句,要么全部执行成功,要么全部执行失败。
事务的概念并不仅仅专属于Mysql。
事务的例子
关于银行账户转账操作,账户转账是一个完整的业务,最小的单元,不可再分———也就是说银行账户转账是一个事务
<>以下是银行账户表t_act(账号、余额),进行转账操作
update t_act set balance=400 where actno=1; update t_act set balance=200 where
actno=2;
以上两台DML语句必须同时成功或者同时失败。最小单元不可再分,当第一条DML语句执行成功后,并不能将底层数据库中的第一个账户的数据修改,只是将操作记录了一下;这个记录是在内存中完成的;当第二条DML语句执行成功后,和底层数据库文件中的数据完成同步。若第二条DML语句执行失败,则清空所有的历史操作记录,要完成以上的功能必须借助事务
事务的ACID性质
1、原子性(Atomicity):
事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
2、一致性(Consistency):数据库总是从一个一致性状态转换到另外一个一致性的状态。不会出现事务中的中间状态。总体来说一致性属于原子性的副产品。
3、隔离性(Isolation):
通常来说,一个事务所做的修改再最终提交以前,对其他事务是不可见的。为什么这里会说“通常来说”来进行修饰呢,后面我们会对隔离级别进行叙述,你就能知道一二。
4、持久性(Durability):
事务完成后,则其所作的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失。持久性是一个有点模糊的概念,因为实际上持久性也分很多不同的级别。有些持久性策略能够提供非常强的安全保障,而有些则未必。而且不可能有做到100%的持久性保证的策略(如果数据库本身就能做到真正的持久性,那么备份又怎么能增加持久性呢?对吧!)。
事务的ACID特性可以确保银行不会弄丢你的钱。在应用逻辑中要实现类似的功能相当复杂。因此数据库中做了很多用户没有察觉的工作,才保证了ACID的实现。
但同时,像数据过锁粒度以及其他一些保障功能一样,事务也会增加系统的开销,一个实现了ACID的数据库,相比没有实现ACID的数据库,通常会需要更强的CPU处理能力,更大的内存以及更多的磁盘空间。
事务的隔离级别
* READ UNCOMMITTED(读未提交):事务中的修改,即使没有提交,对其他事务也是可见的。事务可以读取未提交的数据,这也被称为脏读(Dirty
Read)。这个级别会导致很多问题,从性能上来说 Read
UNCOMMITED不会比其他的级别好太多,但却缺乏其他级别的很多好处,除非真的有非常必要的理由,在实际应用中一般很少使用
* READ COMMITTED(读已提交):大多数数据库系统的默认隔离级别都是READ COMMITTED(但Mysql不是)。READ
COMMITTED满足前面提到的隔离性的简单定义:一个事务开始时,只能“看见”已经提交的事务所做的修改。换句话说,一个事务从开始知道提交之前,所做的任何修改对其他事务都是不可见的。这个级别有时候也可以叫做不可重复度(nonrepeatable
read),因为两次执行同样的查询,可能会得到不一样的结果。
* REPEATABLE READ(可重复读):REPEATABLE
READ解决了脏读的问题。该级别保证了再同一个事务中多次读取同样记录的结果是一致的。但理论上,可重复读级别还是无法解决另外一个幻读(Phantom
Read)的问题。所谓幻读,指的是当前某个事务再读取某个范围的记录时,会产生幻行(Phantom Row)。InnoDB
存储引擎通过多版本并发控制(MVCC。Multiversion Concurrency Control)解决了幻读的问题。可重复读是Mysql的默认事务隔离级别
* SERIALIZABLE(可串行化):
SERIALIZABLE是最高的隔离级别。它通过强制事务串行执行,避免了恰面说德幻读问题。简单来说,SERIALIZABLE会在读取的每一行数据上加锁,所以可能导致大量的超市和锁竞争的问题。实际应用中也很用到这个隔离级别,只有再非常需要确保数据的一致性而且可以接收没有并发的情况下,才考虑采用该级别。
事务的一些术语
* 开启事务:Start Transaction
* 事务结束:End Transaction
* 提交事务:Commit Transaction
* 回滚事务:Rollback Transaction mysql> start transaction;#手动开启事务 mysql> insert
into t_user(name) values('pp'); mysql> commit;#commit之后即可改变底层数据库数据 mysql>
select * from t_user; +----+------+ | id | name | +----+------+ | 1 | jay | | 2
| man | | 3 | pp | +----+------+ 3 rows in set (0.00 sec)
设置事务隔离级别
方式一
可以在my.ini文件中使用transaction-isolation选项来设置服务器的缺省事务隔离级别。
该选项值可以是:
– READ-UNCOMMITTED – READ-COMMITTED – REPEATABLE-READ – SERIALIZABLE • 例如:
[mysqld] transaction-isolation = READ-COMMITTED
方式二
通过命令动态设置隔离级别
• 隔离级别也可以在运行的服务器中动态设置,应使用SET TRANSACTION ISOLATION LEVEL语句。
• 其语法模式为:
SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL <isolation-level>
其中的<isolation-level>可以是: – READ UNCOMMITTED – READ COMMITTED – REPEATABLE READ
– SERIALIZABLE • 例如: SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
隔离级别的作用范围
• 事务隔离级别的作用范围分为两种: – 全局级:对所有的会话有效 – 会话级:只对当前的会话有效 • 例如,设置会话级隔离级别为READ
COMMITTED : mysql> SET TRANSACTION ISOLATION LEVEL READ COMMITTED; 或: mysql>
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; • 设置全局级隔离级别为READ
COMMITTED : mysql> SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
查看隔离级别
• 事务隔离级别的作用范围分为两种: – 全局级:对所有的会话有效 – 会话级:只对当前的会话有效 • 例如,设置会话级隔离级别为READ
COMMITTED : mysql> SET TRANSACTION ISOLATION LEVEL READ COMMITTED; 或: mysql>
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; • 设置全局级隔离级别为READ
COMMITTED : mysql> SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;