3.事务测试
3.事务测试
3.1.定义
旨在验证系统在处理事务时能否正确地维护数据的一致性、完整性和可靠性。事务测试主要关注事务的四个基本属性,即ACID属性(原子性、一致性、隔离性、持久性),并通过一系列测试用例来确保这些属性在各种情况下都能得到满足。
原子性
事务的不可分割,即保证事务的操作要么全部完成,要不什么都不做。主要是通过数据库系统的事务日志实现的。如果事务失败则系统利用日志来回滚所有的操作,恢复到事务执行前的状态。
持久性
保证一旦事务被提交,其对数据库的更改将永久保存,不会因为系统故障而丢失。意味着事务的提交时不可逆的,一旦事务提交,即使系统崩溃,事务的结果依旧能被持久化到磁盘上。
事务回滚机制:
在事务开始执行时,系统在事务日志中记录事务每个操作的详细信息,包括操作类型、操作对象、操作前后的数据状态。事务日志的主要作用是 记录事务操作、支持回滚、支持恢复。通过已经记录的每个操作的详细信息及前后数据状态来对事务日志中的记录进行逐步撤销操作;如果系统崩溃,则可以根据事务日志恢复没有完成的事务。
InnoDB引擎在事务修改数据前,会将修改前的数据备份到UNDO日志中(通常用“回滚段”机制来管理,此时UNDO日志存储在内存中,方便快速读取)。当事务执行遇到错误或用户执行ROLLBACK操作时,系统可以通过UNDO日志中的数据备份将数据回滚,从而保证原子性要求。
REDO日志会记录每个事务操作的详细信息,操作类型、操作对象和修改后的数据状态,当数据提交时系统将REDO日志写入磁盘保证事务的持久性,然后将内存中的数据写入磁盘,完成事务提交,并清理REDO日志中的相关记录。
当系统在事务提交后发生崩溃时,系统重启后读取REDO日志,并从最后一个检查点开始逐条读取REDO日志记录,根据记录重做未完成的事务,将没有完成的事务恢复到磁盘上。(“前滚”操作)
当系统在事务提交前发生崩溃时,此时事务的部分操作可能已经写入REDO日志,但是事务没有提交,就没有写入磁盘。系统重启后读取REDO日志,并从最后一个检查点开始重复“前滚”操作。然后读取UNDO日志,确认哪些事务是没有提交的,并按逆序撤销已执行的操作,将数据库恢复到事务未执行的状态,确保没有提交的事务不会对数据库造成影响。(“后滚”操作)
总结一下,即无论系统在事务提交前还是事务提交完成后崩溃,InnoDB都能灵活地通过UNDO和REDO日志来执行“前滚”和“后滚”操作,而“前滚”保证了已经提交的事务一定对数据库造成影响,而“后滚”操作保证了未提交的事务不会对数据库造成影响。
通过事务回滚机制,数据库管理系统能在系统崩溃后将数据库恢复到一致状态,保持事务的原子性和持久性。
一致性
事务的一致性,指事务执行前后数据库必须从一个一致状态转换成另一个一致状态。事务不会破坏数据库的完整性约束,比如外键约束、唯一性约束等。事务的一致性保证了数据的完整性和准确性。
一致状态指数据库中数据在任何时间点都满足预定义的完整性约束和业务规则,数据库中的数据在一致状态下是合法的、完整的,并符合所有相关的业务逻辑和数据完整性要求。
数据完整性:实体完整性,确保每一张表中的每一行都有唯一标识符;域完整性,字段的数据类型、长度、格式等约束,确保数据合法性;参照完整性,外键约束,确保引用关系的完整性,防止出现孤立的记录(例如构建外键约束后,B表插入数据时必须能在A表用外键查到关联数据)。
业务规则:逻辑一致性,确保数据符合业务逻辑,例如账户余额不能为负数等;操作约束,确保特定的操作符合业务规则,例如转账操作必须确保资金从一个账户转移到另一个账户,而不仅仅是减少一个账户的余额。
隔离性
事务的隔离性指多个并发事务间相互隔离,每个事务的执行不受其他事务的影响。确保事务中间状态不会被其他事务看到,避免各种并发问题例如脏读、幻读、不可重复读。
数据库的隔离级别
读未提交:最低隔离级别,允许一个事务读另一个事务未提交的数据,可能导致脏读、不可重复读和幻读。
读已提交:允许一个事务读另一个事务已提交的数据,避免脏读,但可能出现不可重复读和幻读。
可重复读:在一个事务中多次读取同一个数据时结果是一致的,避免脏读和不可重复读,但存在幻读。
序列化:最高的隔离级别,事务按顺序执行,完全避免脏读、不可重复读和幻读,性能开销最大。
3.2.测试场景
原子性测试
验证插入多个记录时,如果有一个记录插入失败,则整个事务应回滚。
例如在银行转账时,A向B转100元,必须要减少A的余额100元且让B的余额增加100元,这两步要么全部失败,要么全部成功,不可以存在部分成功的情况。
持久性测试
验证系统崩溃后,已提交的事务依旧存在且未损坏。
例如在订单系统中,已提交的订单即使在系统发生故障,订单信息依旧能被恢复。
一致性测试
验证事务执行前后数据处于一致状态,事务的执行不会破坏数据库的完整性约束。
例如在购买商品时,系统需要减少库存数量并记录销售信息。确保购买操作完成后,库存数量减少并且销售记录正确,库存数量不为负数。
隔离性测试
验证并发事务执行时事务间互不干扰,每个事务都像在独立的环境中运行一样。
例如在银行转账时,两个用户同时操作进行转账操作,确保每笔转账操作独立性和一致性,避免并发问题导致数据不一致。
3.3.测试步骤
测试人员一般不会直接写SQL去改库数据,而是去验证研发的接口是否按逻辑正常工作,且对异常情况有正确的处理。
原子性测试
以银行转账为例,用户A向用户B转账100元。这个操作涉及两个账户的更新:减少用户A的账户余额并增加用户B的账户余额。
1.正常调用转账接口,令A用户向B用户转账100元,并调用查询接口观察两者账户数据是否正常,转账记录是否正确生成,数据是否正确无误。
2.调用转账接口时,在某些条件下故意引发错误。令A用户向不存在的C用户转账100元,并调用查询接口观察A账户余额不变,转账操作回滚,保持数据为初始状态。
持久性测试
以用户下单为例,用户下单后系统确保订单信息被永久存入数据库中,即使系统故障后依然可用。
1.正常调用下单接口,传入必要参数,调用订单查询接口验证订单信息能否被查询到。
2.调用下单接口,提交订单后立即模拟系统故障(比如重启服务,重启数据库等),系统恢复后调用订单查询接口验证订单信息能否被查询到。
一致性测试
以购买商品为例,用户在购买后系统需要确保库存减少,增加商品订单,且库存数量不能变为负数。在商品操作事务执行前后,数据库状态始终保持一致,不会出现库存数量为负或其他违反约束的情况。
1.正常调用一次购买接口,调用查询接口查看订单是否正常生成结算,用户账户余额扣减是否正常,商品库存是否正常扣减并不为负数,确保扣减数量与购买数量一致。
2.调用一次购买接口购买超过库存的商品,观察返回结果是否有拦截和异常提示,商品库存不变,用户账户余额不变,确保购买操作正确回滚。
3.多线程模拟多并发购买请求,每一个线程购买不同数量的商品,同时购买不同类型的商品,超过库存和库存内的情况混杂以模拟复杂环境,检查各个商品最终库存数量是否正确,用户账户余额扣减是否正确,每笔订单与商品的扣减记录和用户的付款记录是否一致,购买失败是否正常回滚操作等。
隔离性测试
以银行转账为例,多个用户同时转账的时候保证每个用户的转账交易都是独立的,不会收到其他用户交易的影响。
1.调用转账接口实现A用户对B用户的一次转账,观察返回结果提示和两个用户余额变化,及转账记录等是否正确。
2.同时发起A,B用户对用户C的转账,观察返回结果提示和AB用户扣减情况,及C用户余额的增加情况,及AB与C的转账记录等是否正确。
3.同时发起A->C ,B->D的转账,观察返回结果提示和AB用户扣减情况,及C,D用户余额的增加情况,及AB与C,D的转账记录等是否正确,是否存在数据错误或串味的情况。
4.调用转账接口实现A对B的一次转账,观察返回结果是否提示余额不足,不生成转账记录或生成失败的转账记录,用户余额不变。
5.同时发起A->C的一次转账(足额),B->C的一次转账(不足),观察B->C的失败转账是否对A->C的正常转账产生影响,并观察两者生成的转账记录是否正常,A与C的余额变动是否正确。
6.发起A->C C->D的同时转账,观察账户的最终余额变化是否符合预期,且三者转账数据是否正确。
7.同时发起AB之间的互转,观察账户的最终余额变化是否符合预期,且两者转账数据是否正确。
8.发起A->B的转账,同时转账时故意触发一个系统错误(中断服务),观察两者账户余额没有变化,转账操作有没有被正确回滚。
根据具体业务需求进行更细致的隔离性测试用例设计。

浙公网安备 33010602011771号