作者:郭倩尔偏执起来不是人_ | 来源:互联网 | 2023-10-10 19:34
long time no see!!
距离上一次写东西已经已经是上一次了,是有写一些东西的必要了。
特别是在遇到数据库的时候,脑子里歪歪斜斜的冒出两个字“事务”,我横竖睡不着,想要好好把事务这个小石子从鞋里翻出来。
事务很重要,有多重要。
互联网大数据时代,数据是最基本的,没有数据,互联网就是空谈。
那么保证数据操作的安全,就是互联网的核心。
操作数据就需要操作数据库,而事务就成了保证数据库数据安全的护城河。
一、什么是事务?
事务是操作数据库的基本单位,操作数据库一次,也就进行了一次事务。
在我的理解,事务由一个,或多个sql语句构成。
一次数据库事务的执行有成功有失败,就会存在一个问题。
例如有A,B两条sql语句同时对100块进行操作,A执行成功,100-100=0。
异常示例
而B需要实现100-100+100=100的操作时,出现异常,导致,B执行失败。
如果发生在银行,银行损失100块,如果发生在用户,用户损失一百块。
事务的存在解决了这个问题,AB两个sql都存在于一个事务中。
事务中的sql要么都执行成功,要么都失败。
回滚示例
B失败,A也不会成功,0元会回滚到100块,也就是没有操作的原始状态。
数据库不能没有事务, 就像西方不能没有耶路撒冷。
二、事务的特性
事务的特性可以理解为事务的特点,以下四点。
1.原子性:原子是万事万物最小的单位,所以对数据库而言,事务就是最小的操作单位,不可再拆分。事务中的sql语句要么一起失败,即事务提交(commit)和事务回滚(rollback)。
2.隔离性:不允许多个线程同时操作一个session的数据。例如a,b两个人,a在操作数据的时候还未提交,b就不能操作。a和b同时处在两个不同的事务。
3.持久性:事务一旦提交,就不能回滚。
4.一致性:和能量守恒一样,事务提交前后需要保证数据守恒,增加的和减少的需要一致。
事务的这四个特性,保证了操作数据库数据的安全性。
三、事务的并发问题
只有一个线程操作数据,肯定没有什么问题。而一旦线程变多,就需要考虑并发问题。
何为并发问题?
例如还是100块,C线程进行了+5的操作,此时,C还没有提交,而D线程做了-5的操作,并且提交了。
最后提交过后的C看到还是100块。
并发会造成数据覆盖,所以要解决并发问题,并发问题有以下几种。
AB线程,A负责写,B负责读。
脏读:A正在修改数据,还没有提交,此时B读取了该数据。A如果回滚,B读到的就是一个不存在的数据。脏读也就是读取到了别人还未提交的数据。
脏读示例
不可重复读:B第一次读到了原始数据,接着A开始修改数据,B再次读取,则读到了修改后的数据,前后两次数据不一致。
不可重复读示例
幻读:AB线程同时对某个资源进行操作。A插入一个数字1,此时B线程删除了数字1。最后A发现数字1不见了,像是产生了幻觉,什么鬼!!
幻读读示例
需要知道:不可重复读侧重 读-读,幻读侧重 读-写
四、事务的隔离等级
为了解决以上的问题,事务有应对的措施,也就是隔离等级,隔离等级如下:
读未提交(Read Uncommitted):最低的隔离等级,顾名思义,该隔离等级下,线程可以读到其他线程还没有提交的数据。虽然支持超高并发操作,但数据库操作一般不用这个等级,没什么用。
读已提交(Read-commited):这是大部分数据库正在使用的隔离等级(oracle),只能读到其他线程提交了的数据,避免了脏读,但仍然会出现不可重复度和幻读问题。
可重复读(Repeatable Read):mysql默认的事务隔离等级。处在该隔离等级,读到的数据都是一致的。原理是事务执行期间,会锁定该事务引用的所有行,其他事务不能做修改。但仍然存在幻读。
串行化(serializable):最高级别的隔离等级,解决了所有并发问题,但速度极慢。
事务的隔离等级不是越高越好,也不是越低越好。越高,虽然数据安全,但是牺牲了性能,越低,性能好了,数据的安全性得不到保证。
应针对不同的环境应该设置不同的隔离等级,例如对于银行系统和其他后台管理系统事务隔离等级肯定有出入。
此外,不同的数据库隔离等级是不同的,oracle和mysql一个是Read-commited,一个是Repeatable Read。oracle抛弃了一些安全性能,但提高了操作性能。
作为程序从业人员,一般我们不去修改数据库默认的隔离等级。因为数据库的隔离等级一定是设计者经过了多方的考虑,得到的一个最优解。