事务
一、概述
1.什么是事务
事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部不成功。
- 一个最小的不可再分的工作单元
- 通常一个事务对应了一个完整的业务
- 而一个完整的业务需要批量的DML语句共同联合完成
- 事务只和DML语句有关系,或者说DML语句才有事务
例如:A——B转帐,对应于如下两条sql语句
update account set money=money-100 where name=‘a’;
update account set money=money+100 where name=‘b’;
以上的两条DML语句要求必须同时成功或者同时失败,最小单元,不可再分。当第一条DML语句执行成功之后,并不能将底层数据库中第一个账户的数据修改,只是将操作记录了,这个记录是在内存中完成的,当第二条DML语句执行成功之后,和底层数据库文件中的数据完成同步。若第二条DML语句执行失败,清空所有的历史操作记录。要完成以上的功能,必须借助事务。
2.事务的四个特征(ACID)
- 原子性(Atomicity):
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。 - 一致性(Consistency):事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
- 隔离性(Isolation):事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
- 持久性(Durability):持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。
3.关于一些术语:
- 开启事务:start transaction
- 结束事务:end transaction
- 提交事务:commit transaction
- 回滚事务:rollback transaction
二、事务的提交与回滚
和事务有关的两条SQL语句(TCL):
commit; 提交
rollback; 回滚
事务开启的标志:
任何一条DML语句(insert,update,delete)执行,标志事务的开启
事务结束的标志:
提交或回滚
提交:成功的结束,将所有的DML语句操作历史记录和底层硬盘文件中的数据来一次同步。
回滚:失败的时候,将所有的DML语句操作历史全部清空
注意:在事务进行过程中,未结束之前,DML语句不会更改底层数据库文件中的数据,只是将历史操作记录下来,在内存中完成记录。只有在事务结束的时候,而且是成功的结束的时候才会修改底层硬盘文件中的数据。
三、自动提交模式
演示提交与回滚:
在mysql数据库管理系统中,默认情况下,事务是自动提交的
即,执行一条DML语句,开启事务,并提交事务。
自动提交机制可以关闭:
方式一:
start transaction; //手动开启事务
DML语句...
commit; //手动提交事务(事务成功地结束)
start transaction; //手动开启事务
DML语句...
rollback; //手动回滚事务(事务失败地结束)
方式二:
关闭自动提交:
set autocommit=off;
或:set session autocommit=off;
打开自动提交
set autocommit=on;
或:set session autocommit=on;
以上打开和关闭自动提交机制,只对当前会话有效
四、事务的隔离级别
多个线程开启各自事务操作数据库中数据时,数据库系统要负责隔离操作,以保证各个线程在获取数据时的准确性。
如果不考虑隔离性,可能会引发如下问题:
1.脏读:指一个事务读取了另外一个事务未提交的数据。这是非常危险的
假设A向B转帐100元,对应sql语句如下所示:
1.update account set money=money-100 while name=‘a’;
2.update account set money=money+100 while name=‘b’;
当第1条执行完,第2条还没执行(A未提交时),
如果此时B查询自己的帐户,就会发现自己多了100元钱。
如果A等B走后再回滚,B就会损失100元。
2.不可重复读(针对一条记录的,同一条记录前后不一样)
在一个事务内读取表中的某一行数据,多次读取结果不同。
例如银行想查询A帐户余额,第一次查询A帐户为200元,此时A向帐户内存了100元并提交了,银行接着又进行了一次查询,此时A帐户为300元了。银行两次查询不一致,可能就会很困惑,不知道哪次查询是准的。
和脏读的区别是,脏读是读取前一事务未提交的脏数据,不可重复读是重新读取了前一事务已提交的数据。
很多人认为这种情况就对了,无须困惑,当然是后面的为准。我们可以考虑这样一种情况,比如银行程序需要将查询结果分别输出到电脑屏幕和写到文件中,结果在一个事务中针对输出的目的地,进行的两次查询不一致,导致文件和屏幕中的结果不一致,银行工作人员就不知道以哪个为准了。
3.虚读(幻读,同一张表前后不一样记录数)
是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。
如丙存款100元未提交,这时银行做报表统计account表中所有用户的总额为500元,然后丙提交了,这时银行再统计发现帐户为600元了,造成虚读同样会使银行不知所措,到底以哪个为准。
数据库共定义了四种隔离级别:
Serializable(串行化):可避免脏读、不可重复读、虚读情况的发生。
Repeatable read(可重复读):可避免脏读、不可重复读情况的发生。
Read committed(读已提交):可避免脏读情况发生。
Read uncommitted(读未提交):最低级别,以上情况均无法保证。
- mysql数据库管理系统默认的隔离级别:repeatable read
- oracle数据库管理系统默认的隔离级别:read committed
隔离级别的设置
1.通过修改配置文件设置
在my.ini文件中使用transaction-isolation选项来设置服务器的缺省隔离界别,该选项值可以是:
- READ-UNCOMMITTED
- READ-COMMITTED
- REPEATABLE-READ
- SERILIZABLE
例:
[mysqld]
transaction-isolation=READ-COMMITTED
2.通过命令动态设置
命令格式:
set [无/session/global] transaction isolation level <isolation-level>;
<isolation-level>可以是:
- READ-UNCOMMITTED
- READ-COMMITTED
- REPEATABLE-READ
- SERILIZABLE
隔离级别的作用范围分两种:
- 全局级:对所有的会话有效(global)
- 会话级:只对当前的会话有效(session或不写)
查看隔离级别:
查看当前会话的隔离级别
select @@tx_isolation;
select @@session.tx_isolation;
查看全局的事务隔离级别
select @@global.tx_isolation;