MYSQL——事务管理
什么是事务
在数据库使用者角度,事务就是完成一个事件。例如一个员工信息数据库,要完成员工离职的事件,可能需要很多操作,比如删除员工基本信息以及员工在公司的表现,薪资水平等。而这一系列的操作就是为了完成员工离职这一个事件,这就是事务。事务可以是一个sql语句,也可以是多个。但是,事务不仅仅是几个sql语句的简单集合,这些语句还要有如下属性:
- 原子性Atomicity:在处理事务这个操作上,只有两种状态:完成和未完成。绝对不可能存在正在完成这个状态。
- 持久性Durability:事务处理完之后,数据的修改是永久的,即使系统故障也不会影响
- 隔离性Isolation:由于事务是并发的,为了防止多个事务交叉执行产生错误,需要对事务间进行隔离。
- 一致性Consistence:在事务完成后,数据库的结构,规则等完整性没有被破坏。这一性质的实现是依赖前三个性质的。
为什么出现事务
事务是面向应用层的用户的,在完成一个事务时,应用者只需要关注完成结果,事务失败就回滚。不需要用户考虑出现的各种问题,简化了用户的使用。例如,银行的公务员,在进行转账操作时,如果转账失败就将金额退回原账户,不需要考虑是服务器出问题了还是网络出问题了。
事务的版本支持
show engines \G
事务的提交方式
手动提交
事务开始:
begin;
然后进行sql语句处理数据,处理结束后提交事务:
commit;
在事务未提交前,所有的数据操作都不会被其他mysql客户端访问到
自动提交
一般情况下,自动提交是开启状态,可以查询一下:
show variables like 'autocommit';
自动提交适用于我们直接使用sql语句的情景,即我们不使用手动提交的时候,autocommit变量对手动提交没有任何影响,手动提交必须手动commit。此时,单个sql语句会被看作一个事务,在执行这条语句后,自动提交。但是如果将autocommit关闭后,就需要手动提交:
事务的回滚
在事务中,可以设置回滚点。如果在某个时刻想要回到回滚点的状态,可以直接回滚到这个点:
--设置回滚点
savepoint 回滚点名字;
--回滚到回滚点
rollback to 回滚点名字;
--回滚到最开始
rollback;
- 当我们在处理事务时突然退出mysql,不能commit。事务会自动回滚到开始,相当于执行rollback。
- 事务一旦提交,就无法回滚。
事务属性的理解
原子性
事务commit前,所有的数据操作都不会更新到数据库中。如果中间的某个语句发生错误,就会回滚到事务开始;只有事务commit后才会更新数据库。这样的回滚机制就让事务只存在开始和完成两个状态,也就是所谓的原子性。
持久性
事务一旦commit,数据库就会更新,这时候即使系统崩溃突然关闭,数据也是修改后的。
隔离性
为了让并行的事务之间不同程度的避免干扰,就出现了隔离级别这个属性。
隔离级别有四种:
- 读未提交(Read Uncommitted):所有事务都可以看到其他事务未提交的执行结果,相当于没有隔离性,会造成脏读,幻读,不可重复读等问题
- 读提交(Read Committed):一个事务只能看到其他的已经提交的事务所做的改变。但是还是会造成不可重复读的问题
- 可重复读(Repeatable Read):一个事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的。
- 串行化(Seralizable):会对记录加上读写锁,在多个事务对这条记录进行读写操作时,如果发生了读写冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行
脏读(Dirty Read)是指一个事务读取到另一个事务未提交的数据。如果这个未提交的数据被回滚(Rollback),那么第一个事务读取的数据就是不正确的。
不可重复读是指在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据出现不一致的情况
查看与设置隔离性:
--查看全局隔离级别(新起一个会话会使用全局隔离级别)
select @@global.tx_isolation;
--查看会话隔离级别
select @@session.tx_isolation;
或者
select @@tx_isolation;
--设置全局隔离级别
set global transaction isolation level
read uncommitted/read committed/repeatable read/serializable;
--设置会话隔离级别
set (session) transaction isolation level
read uncommitted/read committed/repeatable read/serializable;
读未提交
读提交
可重复读
串行化
对所有操作全部加锁,进行串行化,不会有问题,但是只要串行化,效率很低,几乎完全不会被采用