数据库事务特性、并行事务问题、事务隔离级别总结

一、数据库事务的四大特性(ACID)

包含:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。一个支持事务(Transaction)的数据库,必需要具有这四种特性,否则在事务过程(Transaction processing)当中无法保证数据的正确性,交易过程极可能达不到交易方的要求。
⑴ 原子性(Atomicity)
第一个原子性,这个是最简单的。说的是一个事务内所有操作共同组成一个原子包,要么全部成功,要么全部失败回滚。失败回滚的操作事务,将不能对事务有任何影响。
⑵ 一致性(Consistency)
原子性只保证了一个事务内的所有操作同一性,大家同生死,不会出现你死了,我还活着。但是,原子性并没有保证大家同一时刻一起生,一起死。计算机指令是有先后顺序的,这样就决定了一个事务的提交,会经历一个时间过程,那么如果事务提交进行到了一半,我读取了数据库,会不会读到中间结果?
为了防止这样的情况,数据库事务的一致性就规定了事务提交前后,永远只可能存在事务提交前的状态和事务提交后的状态,从一个一致性的状态到另一个一致性状态,而不可能出现中间的过程态。也就是说事务的执行结果是量子化状态,而不是线性状态。
⑶ 隔离性(Isolation)
事务的隔离性,基于原子性和一致性,因为事务是原子化,量子化的,所以,事务可以有多个原子包的形式并发执行,但是,每个事务之间互不干扰。由于多个事务可能操作同一个资源,不同的事务为了保证隔离性,会有很多锁方案,当然这是数据库的实现。
⑷ 持久性(Durability)
持久性,当一个事务提交之后,数据库状态永远的发生了改变,这个事务只要提交了,哪怕提交后宕机,他也确确实实的提交了,不会出现因为刚刚宕机了而让提交不生效,是要事务提交,他就像洗不掉的纹身,永远的固化了,除非你毁了硬盘。

二、并行事务的四大问题

1.更新丢失:和别的事务读到相同的东西,各自写,自己的写被覆盖了。(谁写的快谁的更新就丢失了)
第一类更新丢失(回滚丢失,Lost update):A事务撤销时,把已经提交的B事务的更新数据覆盖了。这是完全没有事务隔离级别造成的,通常数据库的实现是不允许发生这种情况。
第二类更新丢失(覆盖丢失,Second lost update):A事务覆盖B事务已经提交的数据,造成B事务所做操作丢失。
2.脏读:读到别的事务未提交的数据。(万一回滚,数据就是脏的无效的了)
3.不可重复读:两次读之间有别的事务修改。
4.幻读:两次读之间有别的事务增删。

三、对应隔离级别

1.READ UNCOMMITTED:读未提交,不处理。
2.READ COMMITTED:读已提交,只读提交的数据,无脏读;
3.REPEATABLE READ:可重复读,加行锁,两次读之间不会有修改,无脏读无重复读;
4.SERIALIZABLE: 串行化,加表锁,全部串行,无所有问题。

四、各问题发生情况

1.第一类更新丢失:A事务撤销时,把已经提交的B事务的更新数据覆盖了
事务1:开启事务
---------------->事务2:开启事务
事务1:查询账户余额为1000元
---------------->事务2:查询账户余额为1000元
---------------->事务2:汇入100元把余额改为1100元
---------------->事务2:提交事务
事务1:取出100元把余额改为900元
事务1:撤销事务
事务1:余额恢复为1000 元 (丢失更新)

2.第二类更新丢失:A事务覆盖B事务已经提交的数据,造成B事务所做操作丢失。
事务1:开启事务
------------>事务2:开启事务
事务1:查询账户余额为1000元
------------>事务2:查询账户余额为1000元
------------>事务2:取出100元把余额改为900元
------------>事务2:提交事务
事务1:汇入100元
事务1:提交事务
事务1:把余额改为1100 元 (丢失更新)

3.脏读:一个事务读取到了另外一个事务没有提交的数据(读取未提交数据)
事务1:更新一条数据
------------->事务2:读取事务1更新的记录
事务1:调用commit进行提交
事务1:开始事务
------------->事务2:开始事务
------------->事务2:查询账户余额为2000元
------------->事务2:取款1000元,余额被更改为1000元
事务1:查询账户余额为1000元(产生脏读)
------------->事务2:取款操作发生未知错误,事务回滚,余额变更为2000元
事务1:转入2000元,余额被更改为3000元(脏读的1000+2000)

事务1:提交事务
按照正确逻辑,此时账户余额应该为4000元

4.不可重复读:在同一事务中,两次读取同一数据,得到内容不同(即不能读到相同的数据内容,前后多次读取,数据内容不一致)
事务1:查询一条记录
-------------->事务2:更新事务1查询的记录
-------------->事务2:调用commit进行提交
事务1:再次查询上次的记录
***此时事务1对同一数据查询了两次,可得到的内容不同,称为不可重复读

5.幻读:同一事务中,用同样的操作读取两次,得到的记录数不相同(前后多次读取,数据总量不一致)
事务1:查询表中所有记录
-------------->事务2:插入一条记录
-------------->事务2:调用commit进行提交
事务1:再次查询表中所有记录
***此时事务1两次查询到的记录是不一样的,称为幻读

五、各问题解决方案

在这里插入图片描述
5.1.第二类更新丢失的问题,如果数据库用户使用方式不对,是有可能出现问题的。
通常有两种方式可以解决这个问题:

#悲观锁
#悲观锁就是锁定要更新的这一行,然后在事务提交之前不让其他事务对该行数据做任何操作
#直至释放行锁
select money from account where id=10 for update
money = money + 100
update account set money =  money where id =10
#乐观锁
#乐观锁是在并发的表上加一个version字段,更新的时候只有版本号大于当前版本号才能更新成功
select money,version from account where id=10 for update
money = money + 100
version = version + 1
update account set money =  money where id =10 and version > version

5.2.幻读
如何避免:实行序列化隔离模式,在任何一个低级别的隔离中都可能会发生。

5.3.不可重复读
有两个策略可以防止这个问题的发生:

  1. 推迟事务2的执行,直至事务1提交或者回退。这种策略在使用锁时应用。
  2. 而在多版本并行控制中,事务2可以被先提交。而事务1,继续执行在旧版本的数据上。当事务1终于尝试提交时,数据库会检验它的结果是否和事务1、事务2顺序执行时一样。如果是,则事务1提交成功。如果不是,事务1会被回退。

5.4.脏读

脏读发生在一个事务A读取了被另一个事务B修改,但是还未提交的数据。假如B回退,则事务A读取的是无效的数据。这跟不可重复读类似,但是第二个事务不需要执行提交。

不可重复读和幻读到底有什么区别呢?
(1)不可重复读是读取了其他事务更改的数据,针对insert与update操作
解决:使用行级锁,锁定该行,事务A多次读取操作完成后才释放该锁,这个时候才允许其他事务更改刚才的数据。
(2)幻读是读取了其他事务新增的数据,针对insert与delete操作
解决:使用表级锁,锁定整张表,事务A多次读取数据总量之后才释放该锁,这个时候才允许其他事务新增数据。

六、mysql、oracle中支持的事务隔离级别和默认事务隔离级别

MySQL
mysql数据库支持上面四种隔离级别,默认的事务处理级别是’REPEATABLE-READ’,也就是可重复读(因为MySQL采用了gap lock,所以实际上MySQL的RR隔离级别也解决了幻读的问题);
1.查看当前会话隔离级别
select @@tx_isolation;
2.查看系统当前隔离级别
select @@global.tx_isolation;
3.设置当前会话隔离级别
set session transaction isolatin level repeatable read;
4.设置系统当前隔离级别
set global transaction isolation level repeatable read;

Oracle
oracle数据库支持READ COMMITTED 和 SERIALIZABLE这两种事务隔离级别,默认系统事务隔离级别是READ COMMITTED,也就是读已提交;
1.查看系统默认事务隔离级别,也是当前会话隔离级别
–首先创建一个事务
declare
trans_id Varchar2(100);
begin
trans_id := dbms_transaction.local_transaction_id( TRUE );
end;
–查看事务隔离级别
SELECT s.sid, s.serial#,
  CASE BITAND(t.flag, POWER(2, 28))
    WHEN 0 THEN ‘READ COMMITTED’
    ELSE ‘SERIALIZABLE’
  END AS isolation_level
FROM v t r a n s a c t i o n t J O I N v transaction t JOIN v transactiontJOINvsession s ON t.addr = s.taddr AND s.sid = sys_context(‘USERENV’, ‘SID’);

参考:
https://blog.csdn.net/qq_33591903/article/details/81672260
https://blog.csdn.net/chenyiminnanjing/article/details/82714341
https://blog.csdn.net/chenyang1010/article/details/84425790
https://blog.csdn.net/gaoshan_820822/article/details/4582561

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值