解决的问题:
事务的一个典型应用 — 转账:
例: 数据表,保存了一些人的银行账户余额
接下来需要进行一个操作:A 转账 3000 给 B
转账操作分两步:
1.给 A 的账户余额 -3000
2.给 B 的账户余额 +3000
如果第一步执行成功了,执行2的时候,出问题了,(假如:B 的用户被冻结了),此时 A 的钱减少了,B 的钱没有增加,那3000块钱就凭空消失了嘛?
把一组操作封装到一起,成为了一个共同的执行单元,此时执行整个事务就能避免上面的问题
事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败
在不同的环境中,都可以有事务。对应在数据库中,就是数据库事务
ACID
1.原子性
食物中的若干个操作,要么全部执行成功,要么全部不执行(并不是真的没执行,而是一旦中间某个步骤执行出错,就把前边已经执行完毕的操作回滚(rollback) 回去)
例如: 上边那个问题,若 2 执行出错,回滚,即:借助逆向操作,再给 A +3000 即可
2.一致性
执行事务前后,数据要始终处于一个合法的状态
例如: 转账操作,减账户余额的时候,不能把账务余额减成负数
3.持久性
事务一旦执行完毕,此时对于数据的修改就是持久生效的了(写入磁盘了)
数据存到磁盘中就是持久的,存到内存中,就是不持久的(重启就没了~)
4.隔离性(很复杂)
设计到并发执行事务
并发: 一台计算机,同时运行着多个应用程序,对于一个CPU来说,同一时刻只能执行一个程序的代码,CPU会先执行程序1一小会,保存程序1的上下文,切换到执行程序2,执行一小会之后执行程序3,执行一小会之后再执行程序1…
从微观上看CPU上的程序都是串行执行的,但是由于切换速度 极快,从宏观上看,感觉多个程序好像是“同时”执行这就是并发
多线程是解决并发编程的方式之一,还有多进程,多协成,actor模型…
并行: 如果你有两个CPU微观上看,CPU1执行画图板,CPU2执行IDEA两个程序也是“同时”执行的,实际编程中,一般不太严格区分并行和并发,都用“并发”来描述
当第一次转账的时候,计算5000-1000在这个计算生效之前,并发式的执行了第二个事务,第二个事务也需要读取A的账户余额,余额还是5000,两次事务建完,A的余额还是4000
为啥并发会出现这样的效果:
本质原因在于多个任务并发执行的时候,执行A到底执行多少代码切换到B,是未知的,B执行多少,切换到A也是未知的,都是由操作系统底层的调度器实现(万恶之源)=> 抢占式执行
由于并发编程编程太难了,有些语言压根就不支持并发,或者说搞一个“假的”并发
并发能提高程序的执行效率,如果在不影响数据正确性的情况下,我们还是希望能够尽可能的让多个操作 (事务) 并发执行
隔离性就是描述并发执行过程中所对应到的一些问题的
并发操作数据库可能带来的问题
不仅仅是数据库中会出现,只要是并发编程中都可能会涉及
1)脏读
A事务读取到了B事务未提交的内容,而B事务后面进行了回滚
2)幻读
A事务读取了一个范围的内容,而同时B事务在此期间插入了一条数据,造成幻觉
3)不可重复读
当设置A事务只能读取B事务已经提交的部分,会造成在A事务内的两次查询,结果竟然不一样,因为在此期间B事务进行了提交操作
怎么解决这些问题呢
MySQL的四种隔离级别如下:
a)未提交读(READ UNCOMMITTED)
允许读取未提交的数据,并行最大,隔离最低,会产生脏读问题
b)已提交读(READ COMMITTED)
只允许读取提交的数据,相当于写加锁,并行降低了一点,能够避免脏读问题,但是存在不可重复读
c)REPEATABLE READ(可重复读)
读写的时候都加锁,此时并行进一步降低,隔离进一步提高了,能够避免不可重复读问题,存在幻读问题(默认隔离级别)
4)SERIALIZABLE(可串行化)
严格串行执行,隔离程度最高,并行程度降低,能够避免幻读问题
(1)开启事务:start transaction;
(2)执行多条SQL语句
(3)回滚或提交:rollback/commit;
说明:rollback即是全部失败,commit即是全部成功
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/m0_47988201/article/details/121012997
内容来源于网络,如有侵权,请联系作者删除!