事物
如果要执行一系列的操作,而这些操作最终是以整体的原子操作的形式完成的话,事物就是必须的。
关于事物的理论中,银行转账就是最经典的例子;当把钱从一个银行账号转至另外一个银行账号的时候,这个操作要由两个步骤来完成,首先要将资金从一个银行账号取出,然后再将其存入另一个银行账号。如果资金已经从一个银行账号取出了,在将资金存入另一个银行账号之前或者进行当中发生异常情况(包括程序内部异常、服务器当机、目标帐号被冻结),如果没有事务保护就会出现源帐号中的资金已 经减少了,但是目标帐号中的资金并没有增加的状况。
事务是关键业务系统开发中非常关键性的服务,对于关键性业务系统如果没有采用事 务,那么这个系统可以说是不可用的。
事物具有4个基本特性,简称ACID
-
原子性:一个事物中所有的数据操作,是一个不可分割的整体,这些操作要么全部执行,要么全部无效果。
-
一致性:一个事物独立执行的结果,将保持数据库的一致性,即数据不会因事物的执行而被破坏。在事务执行过程中,可以违反一致性原则,并产生一个临时的不一致状态。 比如在转账过程中,会出现暂时的数据不一致的情况。当事务结束后,系统又回到一致 的状态。不过临时的一致性不会导致问题,因为原子性会使得系统始终保持一致性。
-
隔离性:在多个事物并发执行的时候,系统应该保证与这些事物先后单独执行时的结果一样,即并发执行的任务不必关心其他事物。对于每一个事物来讲,那一刻看起来就好像只有它在修改数据库一样。事务系统是通过对后台数据库数据使用同步协议来实现隔离 性的。同步协议使一个事务与另外一个事务相分离。如果事务对数据进行了锁定,可以 使并发的事务无法影响该数据,直到锁定解除为止。
-
持久性:一个事物一旦完成全部操作以后,它对数据库的所有操作将永久地反映在数据库中。持久性保证了系统在操作的时候免遭破坏。持久性主要是为了解决机器 故障、突然断电、硬盘损坏等问题而出现的。为了达到持久性,系统一般都保留了 一份日志。一旦出现故障,就可以通过日志将数据重建。
事物的隔离
事物的隔离级别
由于隔离性是通过加锁的方式获得的,而锁会降低系统的性能,所以事物提供了控制隔离程度的机制。如果使用较高的隔离级别,则事物会比较好的与其他事物相隔离,当然也会带来大量的系统开销;如果使用较低的隔离级别,则事物的隔离性会比较查,但是能获得更好的 性能。
需先搞清楚如下几个概念:
- 脏读:一个事物中访问到了另外一个事物未提交的数据
- 不可重复读:在一个事物内根据同一个条件对行记录进行多次查询,但是查出来的结果却不一致。原因是在多次查询期间查询条件覆盖的数据被其他事物修改了
- 幻读:所谓幻读是指同一个事务内多次查询返回的结果集不一样(比如增加了或者减少了行记录)
eg:假设同一个A和B两个同时并发操作数据库,A和B执行的任务如下:从数据库中读取整数N,将N加上10,将新的N更新回数据库。这两个并发执行的实例可能发生下面的执行顺序。
(1) A 从数据库中读取整数N,当前数据库中N=0;
(2) N 加上10,并将其更新到数据库中,当前数据库中N=10。然而由于A 的事务还没有提 交,所以数据库更新还没有称为持久性的;
(3) B 从数据库中读取整数N,当前数据库中N=10;
(4) A 回滚了事务,所以N 恢复到了N=0;
(5) B 将N 加上10,并将其更新到数据库中,当前数据库中N=20;
这里出现了B 在A 提交之前读取了A 所更新的数据,由于A 回滚了事务,所以数据库 中出现了错误的数据20。尽管A 回滚了事务,但是A 更新的数据还是间接的通过B 被更新 到了数据库中。这种读取了未提交的数据的方法就脏(dirty)读问题
分为四种: - READ_UNCOMMITED:会导致脏读问题、幻读和不可重复读问题。在需要敏感计算任务的事物中,这样的模式是不太合适的;
- READ_COMMITED:会有幻读和不可重复读问题。这种级别一般用于制作报表,这种模式是大多数系统的默认级别。
- REPEATABLE_READ:可以解决脏读和不可重读问题
- SERIALIZABLE:都可以解决