今天是刘小爱自学Java的第71天。
感谢你的观看,谢谢你。
话不多说,继续数据库事务的学习:
昨天写了一个银行转账的案例,通过该案例引出了对于数据库事务这个概念的学习。
但是在代码编写过程中我发现了一个问题。
一、对于事务回滚的疑惑
怎么感觉事务的回滚可有可无的样子?
这是我昨天接触到事务这个概念后的一个感触。
当然毕竟才刚开始接触事务,所以我给自己留了条后路,说明自己学识有限,肯定有忽视的地方,还得多多学习。
至于我为什么会产生这样的疑惑?是源于我对代码进行了修改测试。其中代码如下:
①开启事务
将事务设置成手动提交。
②转出账户
用户A给用户B转账,用户A账户余额减少。
③自己创造一个异常
用这段代码来模拟有异常和没有异常。
④转入账户
用户B收到了用户A的转账,其账户余额增加。
如果将③中的异常注释掉,那么代码没有异常,顺利执行,事务提交,数据库对应数据发生改变。
⑤如果发生了异常
也就是利用③来制造异常,事务回滚,回到事务开启时的状态。
但是现在问题来了:
我将⑤中的事务回滚代码删除掉,③中有异常,执行代码发现数据库中的数据并没有改变。
因为出现了异常,事务提交的代码也没有执行到,那么事务没有提交,就算没有回滚,对结局并没有什么改变。
既然如此,那怎么感觉事务回滚可有可无的样子?
昨天我在每天的学习打卡中提出了自己的疑惑,也有很多小伙伴给出了回答:
①②③没有理解我想表达的意思,大部分都是像这样尝试给我说明事务回滚的作用以及重要性。
但这不是我的问题,看来是我没有将疑惑表达清楚,果然学会提问题也是一名程序员应该具备的能力。
所以我仔细捋了捋我的思路,提出疑问:
事务不提交和事务回滚就结果而言是一样的?那么回滚的作用是啥?它们的区别又是什么?
而④和⑤解决了我对其的困惑。
事务开启后,想要结束事务,要么提交,要么回滚,不然资源都被占用了。
就相当于开启了一个线程,用完后不主动关闭,它就会一直运行着占用资源,直到程序本身结束。
资源占用,是这个问题的核心关键,也是我昨天完全没想到的一个问题。
而⑥中提出了一个问题:没有提交是怎么实现数据回到事务开始之前的呢?
也就是事务不提交和事务回滚的区别?
这个问题经过今天的学习,在我心中也有了答案:
1.事务提交,才会对数据库本身数据产生修改。
2.事务开启后,对于数据库的修改可以将其理解成是存放在临时库上面的。(脏读就是读取了临时库上的数据)
3.事务回滚,就相当于取消了这个临时库,对数据库中的实际数据并未影响。
4.事务不提交,和事务回滚一样的效果,但是回滚是即时生效的,而不提交会持续到连接结束才会实现回滚。以上便是我对昨天疑惑的反思以及找寻到的答案。,接下来开始新知识点的学习。
二、事务的特性 ACID
emm……这一块都是概念性的知识点,学起来很枯燥,但是面试可能会被问到,不知道还不行。
①原子性(Atomicity)
为何叫它原子?
因为原子是化学反应不可再分的基本微粒,是化学中最小的存在,事务中的操作是不可分割的。也就是说事务中的操作是一个整体,要么全部成功,要么全部失败。
不能这几个操作成功,另外几个操作失败(这就是在分割事务了)。
②一致性(Consistency)
这个是什么意思呢?
用转账的案例来理解就是:用户A和用户B一共一万块钱,他们之间不管转账多少次,转账多少钱,事务结束后,这两个用户的钱加起来还是一万块。
这就是事务的一致性,就有点类似于能量守恒原则。
③持久性:(Durability)
事务成功提交之后,对于数据库的改变是永久的。
哪怕数据库发生异常,重启之后数据亦然存在。
④隔离性(Isolation)
比如说在操作同一张表时,数据库为每个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
三、事务的隔离级别
安全级别越低,效率越高,但是不安全,从安全级别由低到高逐个说明:
1.安全级别最低(read uncommitter)
在这种级别下就会出现一个问题,脏读。
什么叫脏读?
一个事务读取到另一个事务未提交的数据,也就是一开始说的临时库中的数据。
显而易见,这种情况极其不安全的,是不被允许的。
①设置隔离级别
set session transaction isolation level read uncommitted;
read uncommitted,翻译就是读未提交的数据,非常地好理解。
②开启事务A
修改了数据库中的数据,但是还未提交事务,也就是说数据库的数据还未改变。
③开启事务B
在隔离级别最低的情况下。
事务B能够读取到事务A中还未提交的数据。
④用现实里发消息作为理解
2安全级别:read committed
read committed,读已提交的数据。
在这个安全级别下,不会发生脏读的问题,但是又会出现不可重复读的问题。
什么叫不可重复读?
通俗地理解就是:
数据更新,事务提交,数据库数据被修改,读取到了一些数据。
数据再次更新,事务提交,数据库数据被修改,再次读取时读取到的数据不一样了。
那这不是很正常么?没有问题呀。
但是在某种特定的情况下是有问题的。
一般情况下是没问题的,Oracle默认就是这种级别。
3安全级别:repeatable read
可重复读,在一个事务中读到的数据始终保持一致,无论另一个事务是否提交。
也就是哪怕数据库里的数据发生修改了,读取到的还是以前读到的数据。
①设置可重复读级别
set session transaction isolation level repeatable read;
MySQL数据库默认就是这种级别。
②事务A
A中修改了数据,并提交,那么数据库中本身的数据发生了变化。
③事务B
因为事务B设置了可重复读级别,所以就算数据库中的数据发生了多少变化,读取的数据都是一致的。
当然如果提交了事务再查询,读取到的数据就是变化后的数据了。
④财务报表实例说明
但是其又会出现一个问题,就是幻读。
什么叫幻读呢?
一个事务在前后两次查询同一范围的时候,后一次查询看到了前一次查询没有看到的行。
说白了就是读取到的数据突然多了一个或多个(被另外的事务进行了增加操作),仿佛出现了幻觉一般,所以就叫幻读 。
其中,幻读在MySQL中被优化掉了,也就是说不会出现幻读的问题,所以也没法演示看看幻读到底是个什么回事。
4安全级别:serializableml
serializableml,可串行化的意思。
串行化锁定了整张表,所以幻读不存在的。
怎么可以理解可串行化呢?就是相当于将事务像羊肉串一样串起来了。
所以一次只能执行一个事务,没法并发执行事务了。
这种情况下是最安全的,但是效率也就最低了。
最后
谢谢你的观看。
如果可以的话,麻烦帮忙点个赞,谢谢你。