目录
事务的四大特性
事务(Transaction)是数据库操作的基本单位,具有以下四个核心特性(通常称为ACID特性):
1. 原子性(Atomicity)
原子性是指事务作为一个不可分割的工作单位,事务中的操作要么全部执行成功,要么全部不执行。如果事务在执行过程中发生错误,已经执行的操作会被回滚(Rollback),数据库将恢复到事务开始前的状态。
应用示例:银行转账操作中,必须保证从一个账户扣款和向另一个账户加款这两个操作要么都成功,要么都不执行。如果只执行其中一个操作,就会导致数据不一致。
2. 一致性(Consistency)
一致性确保事务执行前后,数据库从一个一致状态转变为另一个一致状态。事务的执行不会破坏数据库的完整性约束,如主键、外键、数据类型等约束条件。
实现机制:通过数据库的完整性约束、触发器、业务逻辑检查等来保证。例如,转账前后两个账户的总金额应该保持不变。
3. 隔离性(Isolation)
隔离性是指多个事务并发执行时,一个事务的执行不应影响其他事务的执行。数据库系统通过并发控制机制(如锁机制或多版本并发控制MVCC)来实现隔离性,防止出现脏读、不可重复读和幻读等问题。
隔离级别:
- 读未提交(Read Uncommitted)
- 读已提交(Read Committed)
- 可重复读(Repeatable Read)
- 串行化(Serializable)
4. 持久性(Durability)
持久性保证一旦事务提交成功,其对数据库的修改就是永久性的,即使发生系统故障也不会丢失。数据库系统通常通过预写式日志(WAL)和定期备份等机制来确保持久性。
实现方式:事务提交前,所有修改都会先写入事务日志(Transaction Log),即使系统崩溃,也可以通过日志恢复数据。
事务传播行为(Propagation)
事务传播行为定义了多个事务方法相互调用时,事务如何传递和管理的规则。在分布式系统或复杂业务逻辑中,理解传播行为对保证数据一致性至关重要。以下是核心传播行为类型及其应用场景:
1. REQUIRED(默认)
- 行为:如果当前存在事务,则加入该事务;否则新建一个事务。
- 场景:适用于大多数业务方法,确保操作在同一个事务中执行。
- 示例:
@Transactional(propagation = Propagation.REQUIRED) public void methodA() { // 若methodB调用时已有事务,则共用当前事务 methodB(); }
2. REQUIRES_NEW
- 行为:始终新建事务,并挂起当前事务(如果存在)。
- 场景:独立操作(如日志记录),避免因主事务回滚影响子操作。
- 示例:
@Transactional(propagation = Propagation.REQUIRES_NEW) public void auditLog() { // 即使主事务回滚,此日志仍会提交 }
3. SUPPORTS
- 行为:如果当前存在事务,则加入;否则以非事务方式运行。
- 场景:查询方法,可灵活适应有无事务的环境。
- 示例:
@Transactional(propagation = Propagation.SUPPORTS) public Data readData() { // 有事务则受事务管理,无事务则直接执行 }
4. NOT_SUPPORTED
- 行为:以非事务方式执行,并挂起当前事务(如果存在)。
- 场景:需绕过事务管理的操作(如调用外部API)。
- 示例:
@Transactional(propagation = Propagation.NOT_SUPPORTED) public void callExternalService() { // 暂停当前事务,避免长事务阻塞 }
5. MANDATORY
- 行为:必须在已有事务中执行,否则抛出异常。
- 场景:强制要求事务上下文的敏感操作。
- 示例:
@Transactional(propagation = Propagation.MANDATORY) public void updateBalance() { // 无事务时直接报错,防止数据不一致 }
6. NEVER
- 行为:必须在非事务环境下执行,否则抛出异常。
- 场景:禁止事务干扰的操作(如批量读取)。
- 示例:
@Transactional(propagation = Propagation.NEVER) public List<Data> bulkFetch() { // 存在事务时报错,确保无锁读取 }
7. NESTED
- 行为:在当前事务中创建嵌套子事务,子事务可独立回滚。
- 场景:部分操作可回滚的复杂流程(如订单创建+库存扣减)。
- 示例:
@Transactional(propagation = Propagation.NESTED) public void deductStock() { // 失败时仅回滚此操作,不影响外层事务 }
关键注意事项
事务失效场景:
- 同类内方法直接调用(需通过代理对象调用)。
- 异常类型未配置回滚(默认仅回滚
RuntimeException
)。
选择原则:
- 默认使用
REQUIRED
保证原子性。 - 需要隔离操作时用
REQUIRES_NEW
或NESTED
。 - 避免滥用
NOT_SUPPORTED
导致数据不一致。
- 默认使用
嵌套事务实现:
- 数据库需支持保存点(如MySQL的
SAVEPOINT
)。 - 嵌套事务回滚时,外层事务可选择提交或回滚。
- 数据库需支持保存点(如MySQL的
通过合理配置传播行为,可优化事务边界控制,平衡数据一致性与系统性能。