如何理解数据库事务的一致性

总而言之,复习的时候发现了某些对事务一致性 (Consistency) 比较玄乎的中文解释,简单搜了下,发现大部分答案都是那么解释的……决定来个通俗版本?

简单搜到看到的版本。。。

版本1:事务执行前后数据库的状态保存一致。(某公众号复习资料)

感想: ???

版本2:几个并行执行的事务,其执行结果必须与按某一顺序串行执行的结果相一致。(百度百科)

感想:感觉这个解释更偏向隔离性?

版本3:一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态。

感想:听君一席话,如听一席话

版本4:数据库处理前后结果应与其所抽象的客观世界中真实状况保持一致。

感想:好像有点明白,有几个版本是从这个角度说的(很多都是银行账户存取款的例子,转账前后钱应该守恒,且不能转超出余额的钱让余额变成负数等等)。一致性有时也被称为正确性 (Correctness),即操作前后,数据库记录的数据是正确、符合期望的。

索性连英文的版本也一起查了:

Consistency ensures that a transaction can only bring the database from one valid state to another, maintaining database invariants: any data written to the database must be valid according to all defined rules, including constraints, cascades, triggers, and any combination thereof. This prevents database corruption by an illegal transaction, but does not guarantee that a transaction is correct. Referential integrity guarantees the primary keyforeign key relationship. (Wikipedia)

保障只会从一个有效/正确的状态,转变成另一个有效/正确的状态。

那么什么是不正确/无效呢?就是违反了任何已定义的规则的情况,包括违反约束条件、级联、触发器等不合法操作。如试图插入重复的主键(数据库不会让你这么做的),违反外键约束,违反unique等等。在干了这种事之后会发生什么呢?Commit是不会commit了,基本都是被catch、报错、rollback了。而既然非法操作被回滚,也就不会走向一个不正确/无效的状态,而是回到原先的有效状态。

另一个角度来说,只有操作全都合法,符合约束,才可能被提交,而在此情况下,新的状态也是符合约束、有效的。

而各种约束、级联、触发器、自定义的各种检查(if之类的,不通过就rollback之类的),也都是为了让数据更加“正确”,与数据要反映的事实相符合、一致。大概也就是这样了吧。

继续的复习……

事务 Transaction

经常以下面这种形式存在的,满足ACID的数据库操作(一系列操作)。

BEGIN TRY 
	BEGIN TRANSACTION 
		-- 事务的操作写这里 -- 
	COMMIT TRANSACTION 
END TRY 
BEGIN CATCH 
	IF (@@TRANCOUNT > 0) 
    	-- 处理错误、写错误日志等操作 -- 
 		ROLLBACK TRANSACTION 
    END IF 
END CATCH

只有顺利运行过commit才真正改动了数据库信息,rollback的话一切还原。

ACID

其中AID没什么争议,尤其是A和D。C上面解释了。

  • 原子性 (Atomicity):同一个事务里的操作不可分割,要么全部执行 (commit掉),要么全部不执行 (rollback掉)。不会出现一半执行了,一半没执行的情况,即便执行到半截断电了也不会。
  • 隔离性 (Isolation):每个事务独立执行,多个并发事务互不干扰。
  • 持久性 (Durability) : 事务提交后,对系统的影响是持久的。已经改动的数据不会丢失,即便数据库出现故障。

隔离性的话,还存在隔离等级:

  • 读未提交(Read Uncommitted): 一个事务读取了另一个事务还未提交的数据,而第二个事务之后可能回滚了并没执行这个更新,也就是脏读
  • 读已提交(Read Committed): 只会读取其他事务已经提交的数据。但是依然可能发生“不可重复读”。一个事务读取某数据后,另一个事务修改了该数据。那么第一个事务里,再次尝试读这个数据时就读不到原来的值了。
  • 可重复读 (Repeatable Read): 在一个事务中,无论读同一个数据几次 (且无论中途其他事务是否修改了它),读取到的值都一样。但是可能出现幻读,如A事务查询id=123,返回0行,B事务插入id=123,A查询id=123,依然没有结果,A插入id=123失败(A认为id=123不存在,但却无法插入)。
  • 可串行化(Serializable):把多个并发事务一个一个串行执行,不会有任何上述问题,但速度很慢……

Ref: