说起数据库,可以不知道SQL,但一定不能不知道ACID。
数据库事务ACID四大原则:
原子性简单,也最常用。即在事务中所有操作都被视为一个不可分割的整体,要么全成功,要么全失败。
原子性经典的例子是A给B转账,不能A扣了钱,但B却没收到(因为网络等原因)。
事务的一种实现方法是在执行的时候,先不将最终的结果更新到数据库,而是先写在事务日志上,等整个事务执行成功后,再将事务日志上的内容同步到数据库中。如果失败了,事务日志删除,完成回滚。
持久性是指,在事务完成了之后,这个事务对数据库所做的修改就被持久地保存进了数据库中,不会再被回滚操作影响。即使出现机房断电等意外情况,数据库中的数据也不会丢失。
那么,怎样做到数据库中的数据不丢呢?假设数据库中的数据丢了,那么只要根据事务日志重新执行一遍对应的操作,就可以恢复数据库当中的数据,维持数据库的持久性。实际上,现在的数据库默认会将所有的操作都当做事务来执行,因此基本不用担心数据丢失的情况。
在多个事务一起执行的时候,如果隔离性做的不好,那么可能会导致很多问题。
以下四种问题最常见:
脏读指一个事务读到了另一个事务的中间结果,还用转账举例:
当A给B转账的事务没有执行完,另一个事务就读取了它的中间结果,就有可能造成脏读。因为万一之前的事务回滚,那么新读取到的结果就是错的,和A账号回滚之后的余额就不一致了。
不可重复读的意思是说,在一个事务中,我们读取了某个数据两次。刚好在这两次中间,有另一个事务修改了这条数据,那么同样会引起数据错误,因为这两次读取到的结果不一致。
比如我们对A账户的一个事务还没有结束,这时它的结果就被另一个事务修改了,那么程序就会发生错乱,因为读到了它没有预料到的修改。
解决方法就是针对当前修改的数据进行隔离,同一时刻只允许一个事务对该条数据进行修改,以保证数据的一致性。
幻读就是一个事务读取两次,读到的数据条数不一致。这点和不可重复读非常类似,不过不同的是不可重复读是确定的某一条数据,而幻读是指整个数据库或者整个表而言。
要解决也很简单,因为幻读是其他事务修改其他数据产生的,所以要排除掉这种情况,只针对我们修改的数据进行加锁和隔离是不够的,我们需要将整个数据库,或者是分区进行隔离,同一时刻,只允许一个事务对一个分片或数据库表进行修改。
更新丢失的定义很直观,当我们修改一条数据的时候,另一个事务也在修改这条数据,导致后者的修改覆盖了前者修改的内容。
解决的办法是做好隔离操作,在一个事务写入完成之前,禁止其他事务写入。即更新丢失是在并发场景下出现的错误。
解决办法就是设置不同的隔离级别,不同的隔离级别对应不同的隔离策略,可以保证不同级别下的隔离性。
不同的隔离级别,意味着使用不同级别的锁,显然隔离级别越高,性能越差。这就需要DBA根据业务场景,在性能和隔离安全性之间做一个权衡:
从上到下,对应四种隔离级别,越往下隔离级别越高,能够解决的隔离性问题也就越多,同样的,用到的锁也就越多,系统的性能也就越差。
现在分别看下数据库的四种隔离级别:
1)未提交读:在读时不会判断是否可能会读到没有提交的数据,所以他的隔离性最差,连最简单的脏读都无法解决。
2)已提交读:通过锁限制了只会读取已经提交的数据,读数据的时候使用共享锁,在读取完成后立即释放。已提交读级别可解决脏读问题,也是SQL Server的默认隔离级别。
3)可重复读:读取过程和已提交读级别一样,但在读取时会保持共享锁,直到事务结束。跟已提交读不同的是,只要一个事务没有结束,锁就不会释放,其他事务无法更新数据,保证了不会出现不可重复读。
4)可串行读:在事务进行中,不仅会锁定受影响的数据本身,还会锁定整个范围。这就组织了其他事务影响整体的情况出现。
数据库的一致性表示数据的状态是正确的,即和程序员预期的状态一致。
虽然一致性是数据库的四大原则之一,但数据库系统当中并没有专门针对一致性的部分,只要满足了其他三原则,那么自然就达成了一致性。
举例说明,A向B转帐100,前提条件是A的账号中钱大于等于100,如小于100,如果在开发程序时没有校验,还强行转账成功,那么这个结果就跟我们预期不一致,就是这个问题并不是因为书刊没有做到一致性,而是开发人员忽略了限制条件。
所以,教材上写“Ensuring the consistency is the responsibility of user, not DBMS.", "DBMS assumes that consistency holds for each transaction”。
保证一致性是开发的责任,不是数据库的责任,数据库假设每一个事务都符合一致性。
信息加载中,请等待
微信客服(速回)
微信客服(慢回)