天天看点

数据库事务(MySQL)

1、什么是事务

* 事务(transaction)是一个最小的不可再分的工作单元

* 通常一个事务对应了一个完整的业务

* 而一个完整的业务,需要批量的DML语句(insert、update、delete)共同联合完成

* 事务只和DML语句有关系,即DML语句才有事务

典型实例: 银行账户转账业务

银行账户转账业务,该业务就是一个最小的工作单元,不可再分,即该业务是一个事务

t_act 账户表

actno balance
act-001 50000.0
act-002 20000.0

执行转账操作(10000):

update t_act set balance=40000.0 where actno='act-001';

update t_act set balance=30000.0 where actno='act-002';

以上的两条DML语句要求必须同时成功或者同时失败,最小单元,不可再分

当第一条DML语句执行成功之后,并不能将底层数据库中第一个账户的数据修改;只是将操作记录了一下,这个记录是在内存中完成的,若第二条DML语句执行成功,和底层数据库文件中的数据完成同步;若第二条DML语句执行失败,清空所有的历史操作记录。

要完成以上的功能,必须借助事务

2、事务的四大特性(ACID)

原子性(A):事务是最小的工作单元,不可再分

一致性(C):事务要求所有的DML语句操作的时候,必须保证同时成功或者同时失败

隔离性(I):多事务并发执行时,事务之间互不影响

持久性(D):一旦事务提交,对数据的改变就是永久的(内存中的数据持久到硬盘文件中)

3、与事务有关的术语

开始事务:Start Transaction

结束事务:End Transaction

提交事务:Commit Transaction

回滚事务:Rollback Transaction

4、事务控制语句

手动开启事务:begin/start transaction;

创建一个保存点:savepoint 保存点名; 

回滚:rollback to 保存点名;  或  rollback;

手动提交:commit;

5、事务开启的标志与结束的标志

(1)开启的标志

任何一条DML语句(insert、update、delete)执行,标志事务的开启

(2)结束的标志

提交或者回滚

提交:成功的结束,将所有的DML语句操作历史记录和底层硬盘文件中的数据来一次同步

回滚:失败的结束,将所有的DML语句操作历史记录全部清空

6、事务的隔离级别

(1)read uncommitted 读未提交

* 事务A和事务B,事务A未提交的数据,事务B可以读取到

* 这里读取到的数据叫做"脏数据"或"Dirty Read"

* 这种隔离界别是最低级别,一般都是在理论上存在的,数据库默认的隔离级别一般高于该隔离级别

(2)read committed 读已提交

* 事务A和事务B,事务A提交的数据,事务B才能读取到(对于事务提交之后的数据,当前事务才能读取到)

* 该隔离级别高于读未提交,可以避免脏数据,但会导致"不可重复读"

(3)repeatable read 可重复读

* 事务A和事务B,事务A提交之后的数据,事务B读取不到(对方提交之后的数据当前事务还是读取不到)

* 事务B是可重复读取数据

* 该隔离界别高于读已提交,可避免"脏读"和"不可重复读",达到可重复读取,但会导致"幻读"

* MySQL数据库管理系统默认的隔离级别就是可重复读

(4)serializable 串行化

* 事务A和事务B,事务A在操作数据库表中数据的时候,事务B只能排队等待(等待队列)

* 该隔离级别一般很少使用,吞吐量太低,用户体验不好

* 可以避免"幻读",每一次读取的都是数据库表中真实的记录

* 事务A和事务B不再并发

若无事务隔离级别,那么多个事务在同一时间间隔内对同一事务的操作可能会影响最终的结果,通常会出现以下几种问题:

(1)脏读

事务A读取了事务B还没有提交的数据

解决办法:将数据库隔离级别修改为read committed

(2)不可重复读

同一事务内,两次相同的查询返回了不同结果

解决办法:将数据库隔离级别修改为repeatable read

(3)幻读

事务A修改全部数据,事务B插入(或删除)数据;操作A事务的用户在修改结束后发现表中还有未修改的行

解决办法:将数据库隔离级别修改为serializable

注:不可重复读重点是修改;同样的条件,读取过的数据,再次读取发现值不一样了

       幻读重点是新增或删除;同样的条件,第一次和第二次读出来的记录数不同

7、隔离级别与一致性问题的关系

隔离级别 脏读 不可重复读 幻读 加锁读
读未提交 可能 可能 可能 不加锁
读已提交 不可能 可能 可能 不加锁
可重复读 不可能 不可能 对InnoDB不可能 不加锁
串行化 不可能 不可能 不可能 加锁

8、其他 

  • 查看当前隔离级别
select @@tx_isolation;
  • 设置事务的隔离级别

方式一:修改my.ini配置文件

[mysqld]

transaction-isolation = READ-COMMITTED

方式二:使用命令方式

设置事务的隔离级别作用于全局

set global transaction isolation level read uncommitted;

设置事务的隔离级别作用于当前会话

set [session] transaction isolation level read uncommitted;

注:在事务进行过程中,未结束之前,DML语句是不会更改底层数据库文件中的数据的,只是将历史操作记录一下,在内存中完成记录,只有在事务结束的时候,而且是成功的结束的时候才会修改底层硬盘文件中的数据;在MySQL数据库管理系统中,默认情况下,事务是自动提交的,即只要执行一条DML语句,开启了事务,并且提交了事务

关闭自动提交的方式:

第一种:手动开启事务

第二种:set autocommit=off; 或 set session autocommit=on;

以上打开和关闭自动提交机制只针对当前会话