一、事务概述
事务(transaction):最小的不可再分的工作单元;
通常一个事务对应一个完整的业务(例如银行账户转账业务,该业务就是一个最小的工作单元)
比如:银行账户转账,从a账户向=账户转账10000.需要执行两条update语句。 update t_act set balance =balance - 10000 where actno = ‘act-001’ ;
update t_act set balance =balance + 10000 where actno = 'act-002 ';
以上两条DM语句必须同时成功,或者同时失败,不允许出现一条成功,一条失败。
事务只和DML(insert,delete,update)语句有关,或者说只有DML语句才有事务。
在事物进行过程中,未结束之前,DML语句不会更改底层数据,它只是将历史操作记录一下,在内存中完成记录。只有在事物结束的时候,而且是成功的结束的时候,才会修改底层硬盘文件中的数据。
在MySQL中,默认情况下事务是自动提交的。
事务的存在是为了保证数据的完整性,安全性。
二、事务特性(ACID)
-
原子性(Atomicity):原子性是指事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败。
-
一致性(Consistency):事务必须使数据库从一个一致性状态变换到另外一个一致性状态
-
隔离性(Isolation):事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
-
持久性(Durability): 持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
三、事务的隔离级别
多个线程开启各自事务操作数据库中数据时,数据库系统要负责隔离操作,以保证各个线程在获取数据时的准确性。
3.1、第一级别:脏读(Read uncommited)
读未提交:一个线程中的事务读取到了另外一个线程中未提交的数据。
问题:读未提交存在脏读(Dirty Read)现象:表示读到了脏的数据。
3.2、第二级别:不可重复读(Read commited)
读已提交:对方事务提交之后的数据我方可以读取到。
解决:可避免脏读情况发生
问题:不可重复读指在一个事务内读取表中的某一行数据,多次读取结果不同。
不可重复读和脏读的区别是,脏读是读取前一事务未提交的脏数据,不可重复读是重新读取了前一事务已提交的数据。
3.3、第三级别:可重复读(Repeatable read)
——mysql默认隔离级别
解决:可避免脏读、不可重复读情况的发生。
问题:虚读(幻读)现象指在一个事务内读取到了别的事务插入的数据
导致前后读取不一致。
比如:第一个事务对表中的数据进行了全表update,同时,第二个事务向表中插入一行新数据。执行后,第一个事务的用户发现表中还有一条记录没有更新成功,就好象发生了幻觉一样,这是幻读。
注意:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表。
3.4、第四级别:序列化读/串行化读(Serializable)
解决所有问题:可避免脏读、不可重复读、虚读情况的发生。
但是效率低,需要事务排队。(比如:提交一条数据,需要这边事务提交过后才可以查询到数据)
四、Mysql常用的事务命令
注:表的引擎类型必须是innodb类型才可以使用事务,这是mysql表的默认引擎
4.1、开启事务
start transaction
开启事务后执行修改命令,变更会维护到本地缓存中,而不维护到物理表中
4.2、提交事务
commit
将缓存中的数据变更维护到物理表中
4.3、回滚事务
rollback
通过手动回滚事务,让所有的操作都失效,这样数据就会回到最初的初始状态!
4.4、关闭自动提交
set autocommit = 0
4.5、开启自动提交
set autocommit = 1
4.6、创建保存点
savepoint identifier
4.7、删除保存点
release savepoint identifier
4.8、回滚保存点
rollback to identifier
4.8、设置事务的隔离级别
# 设置全局隔离级别
set global transaction isolation level REPEATABLE READ;
set global transaction isolation level READ COMMITTED;
set global transaction isolation level READ UNCOMMITTED;
set global transaction isolation level SERIALIZABLE;
#设置会话隔离级别
set session transaction isolation level REPEATABLE READ;
set session transaction isolation level READ COMMITTED;
set session transaction isolation level READ UNCOMMITTED;
set session transaction isolation level SERIALIZABLE;
也可以通过配置文件设置隔离级别
[mysqld]
transaction-isolation = REPEATABLE-READ
transaction-isolation = READ-COMMITTED
transaction-isolation = READ-UNCOMMITTED
transaction-isolation = SERIALIZABLE
4.9、查看隔离级别
#提示:在MySQL 8.0.3 中,tx_isolation 变量被 transaction_isolation 变量替换了。
在 MySQL 8.0.3 版本中查询事务隔离级别,只要把上述查询语句中的 tx_isolation 变量替换成 transaction_isolation 变量即可。
#查看当前全局事务隔离级别
#MySQL 老版本
select @@global.tx_isolation;
#MySQL 8.0.3及更高版本
SELECT @@GLOBAL.transaction_isolation;
#会话的事务隔离级别
#MySQL 老版本
SELECT @@SESSION.tx_isolation;
#MySQL 8.0.3及更高版本
SELECT @@SESSION.transaction_isolation;
#查看当前事务隔离级别。
show variables like 'transaction_isolation';#MySQL 8.0.3及更高版本
show variables like 'tx_isolation';#老版本
InnoDB提供的级别有read uncommitted,read committed,repeatable read,serializable
注意:
-
修改数据的命令会自动的触发事务,包括insert、update、delete
-
而在SQL语句中有手动开启事务的原因是:可以进行多次数据的修改,如果成功一起成功,否则一起会滚到之前的数据
五、锁
- 悲观锁:假定所有不同事务的处理一定会出现干扰,数据库中最严格的并发控制策略,如果一个事务正在对数据处理,那么在整个事务过程中,其他事务都无法对这个数据进行更新操作,直到该事务释放了这个锁。
- 乐观锁:假定所有不同事务的处理不一定会出现干扰,所以在大部分操作里不许加锁,但是既然是并发就有出现干扰的可能。在乐观锁中当提交更新请求之前,要先去检查读取这个数据之后该数据是否发生了变化,如果有变化,那么你此次的提交就要放弃,如果没有变化就可以提交。