事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。
- 原子性(atomicity)
一个事务是一个不可分割的工作单位,事务中包括的所有操作要么全部提交成功,要么全部失败回滚。对于一个事务来说,不可能只执行其中的一部分操作。
最经典的例子:我给你转了10000RMB(大方点hh),你的账号会多10000块,我的账户会少10000块。
(这是个资金的流转,要么同时成功,要么同时失败)
begin; -- 开始一个事务 update table set A = A - 100; update table set B = B + 100; -- 其他操作 commit; -- 提交事务
begin和commit之间所有操作完成后,才能成功保存到数据库 只要有一条操作失败,就撤销之前的操作,这要就保证了同生共死
- 一致性(consistency)
一 个或多个事务执行后,原来一致的数据和数据库仍然是一致的。 数据库总是从一个一致性的状态转换到另外一个一致性的状态。在前面的例子中,一致性确保了,即使在执行第三、四条语句之间时系统崩溃,CMBC账户中也不会损失100万,不然因为事务最终没有提交会导致很严重的影响,所以事务中所做的修改也不会保存到数据库中。
- 持久性(durability)
持久性是个有点模糊的概念,因为实际上持久性也分很多不同的级别。有些持久性策略能够提供非常强的安全保障,而有些则未必。而且「不可能有能做到100%的持久性保证的策略」否则还需要备份做什么。
- 隔离性(isolation)
通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的。在前面的例子中,当执行完第三条语句、第四条语句还未开始时,此时如果有其他人也准备给lemon的CMBC账户存钱,那他看到的CMBC账户里还是有100万的。
拓
脏读
在事务A修改数据之后提交数据之前,这时另一个事务B来读取数据,如果不加控制,事务B读取到A修改过数据,之后A又对数据做了修改再提交,则B读到的数据是脏数据,此过程称为脏读Dirty Read。
不可重复读
一个事务内在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了变更、或者某些记录已经被删除了。
幻读
事务A在按查询条件读取某个范围的记录时,事务B又在该范围内插入了新的满足条件的记录,当事务A再次按条件查询记录时,会产生新的满足条件的记录(幻行 Phantom Row)
不可重复读:第一次读的数据和第二次读的「数据不一样」。(因为中间有其他事务提交了修改)
幻读:第一次和第二次读出来的「记录数不一样」。(因为中间有其他事务提交了插入/删除)
如何保证隔离性(Isolation):
有多个事务同时进行,最后结束时,最终的结果应该是相同的
原子性的问题解决了,但是在另外的事务中同时修改数据,数据的一致性就会被破坏,所以要有隔离机制,一个事务完成后,另一个事务才能开始,要加上互斥锁。
具体步骤:
1.先获得锁,然后才能修改数据A
2.修改并提交事务之后释放锁,给下一个要修改数据A的事务
3.然后第二个事务开始修改数据并提交。
对于同一个数据,只有一个事务能持有互斥锁,没有锁的事务,需要等待其他事务释放锁
只有当事务提交或者回滚后,才能释放锁。在这期间,其他事务只能读取数据
隔离级别:
1.串行化:最高的隔离级别,两个事务百分百隔离,串行执行。
2.可重复读(MySQL默认模式):这些数据对其他正在执行的事务是可见的。如果成功修改了一条数据,修改结果对于正在运行的事务仍然不可见。所以只是对于新数据产生了新隔离,旧数据还是旧隔离。
3.读取已提交(Read committed,Oracle、PostgreSQL、SQL Server默认模式):可重复读+新的隔离突破,A事务在读取D数据时,B事务对D数据进行了删除或者修改操作并提交,A重新读取时就会看到B事务修改以后的数据。A事务在第一次读取的数据和第二次数据不一样,这叫幻读
4.读取未提交:读取已提交+新的隔离突破:A事务在读取D数据时,B事务对D数据进行了删除或者修改操作并提交,A重新读取时就会看到B事务修改以后的数据。但是此时B事务出错回滚了,A还是会看到B事务修改的数据结果,看到的数据是毫无用处的,这叫脏读
此部分原文链接:https://blog.csdn.net/weixin_43326401/article/details/104003945
这篇文章不错自己看吧,懒得写了
网址:https://www.zhihu.com/question/31346392