MySql--事务

事务

一、概述

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 ;

可以是:

  • READ-UNCOMMITTED
  • READ-COMMITTED
  • REPEATABLE-READ
  • SERILIZABLE

隔离级别的作用范围分两种:

  • 全局级:对所有的会话有效(global)
  • 会话级:只对当前的会话有效(session或不写)

查看隔离级别:

查看当前会话的隔离级别
select @@tx_isolation; 
select @@session.tx_isolation;

查看全局的事务隔离级别
select @@global.tx_isolation;

你可能感兴趣的:(MySql--事务)