众所周知,数据库中事务有4个特性,原子性、一致性、隔离性、持久性。
那我们就简单讲一下这4个特性吧!
原子性:指的是事务中包含的操作要么全部提交,要么全部回滚。也就是说如果这个事务中包含了100个操作,要么这100个操作全部提交进数据库,如果有1个操作失败,那么其他操作要全部回滚到之前的状态。
为什么叫原子性呢,因为原子是组成物质的最小单位,化学反应是不可分割也无法分割的(物理分割除外),事务的这个特性和原子是一样的,要么全部成功,要么全部失败,事务中的所有操作是不可分割的,顾名思义,这个特性叫原子性。
一致性:事务必须使数据库从一个一致性状态变换到另一个一致性状态。也就是说一个事务执行之前和执行之后都必须处于一致性状态。
很多人对一致性很难理解,确实是这样,有点虚。
其实一致性主要讲的是事务要按照预期的结果生效。打比方,库位这张表里有库存数据,库存这张表里也有库存数据。那你如果现在有东西从仓库中出库了,不仅库存这张表里数据要更改,库位这张表里库存数据也要更改。这个数据的更改有2个方面,第一个是事务必须满足原子性,第二个就是你的代码逻辑必须2张表都做修改,这样才能保证数据的准确一致性,也就是事务要按照你的预期达成效果,不能有逻辑或者其他方面的错误发生,不然你只更改了一张表的数据,那你2张表的数据就不一致了。
隔离性:事务之间是彼此独立的,每一个事务的操作不能影响其他事务,不能互相干扰,并发事务之间是隔离的。
假设我们不考虑事务的隔离性,那么会发生哪些情况呢?会发生下面三种情况:
脏读:一个事务读取了另一个事务还没提交的数据。比如事务A修改了一行数据,但是还没有提交,这时候事务B读取了被事务A修改后的数据,之后事务A因为某种原因Rollback了,那么事务B读取的数据就是脏的。
解决办法:把数据库的事务隔离级别调整到READ_COMMITTED
不可重复度:不可重复读是指在同一个事务内,两个相同的查询返回了不同的结果。 例如:事务T1读取某一数据,事务T2读取并修改了该数据,T1为了对读取值进行检验而再次读取该数据,便得到了不同的结果。
记住,不可重复读的重点是修改 ,同样的条件, 你读取过的数据, 再次读取出来发现值不一样了
解决办法:把数据库的事务隔离级别调整到REPEATABLE_READ
幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样。这就叫幻读。
记住,幻读的重点在于新增或者删除 ,同样的条件, 第1次和第2次读出来的记录数不一样
解决办法:把数据库的事务隔离级别调整到SERIALIZABLE_READ
MySQL数据库为我们提供的四种隔离级别:
① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
② Repeatable read (可重复读):可避免脏读、不可重复读的发生。
③ Read committed (读已提交):可避免脏读的发生。
④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。
以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然级别越高,执行效率就越低。像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。在MySQL数据库中默认的隔离级别为Repeatable read (可重复读)。而在Oracle数据库中,只支持Serializable (串行化)级别和Read committed (读已提交)这两种级别,其中默认的为Read committed级别。
持久性:数据一旦被提交了,那么对数据库中的数据改变是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
以上就是对事务4个特性的简析,笔者之前不是很明白,所以写了篇文章巩固一下。
每个一知半解,都是一个绊脚石,多了,就堆成了一座山,你就在也逾越不过去了。
—蝼蚁虽小,溃之千里
网友评论