事务(Transaction)是数据库管理系统(DBMS)中用于管理并确保操作可靠性的一种机制。事务的主要目的是保证数据的一致性,即一组数据库操作要么全部执行成功,要么全部回滚到操作前的状态,没有中间状态。
事务的四大特性(ACID)
事务具有四个主要特性,通常简称为 ACID:
-
原子性(Atomicity) :
- 事务中的所有操作是一个不可分割的整体,要么全部成功,要么全部失败。保证在发生故障时要么什么都不做,要么撤销到事务开始前的状态。
-
一致性(Consistency) :
- 事务在开始和结束时,数据库必须处于一致的状态,即事务的执行不能破坏数据库的完整性约束。
-
隔离性(Isolation) :
- 事务的执行是相互隔离的,一个事务的操作对其他事务是不可见的,直到该事务提交为止。隔离性可以通过不同的隔离级别来实现。
-
持久性(Durability) :
-
一旦事务提交,其对数据库的改变应该是永久性的,即使系统发生故障也能保持。
-
事务的使用场景
事务广泛应用于需要保证数据一致性的场景,如银行转账、预定系统、订单处理系统等。
Spring 中的事务管理
Spring 提供了强大的事务管理功能,支持声明式事务管理和编程式事务管理。最常用的是声明式事务管理,通过注解 @Transactional 实现。
声明式事务管理
1. 配置事务管理器
首先,配置一个事务管理器。常用的是 DataSourceTransactionManager 或者 JPA 的 JpaTransactionManager。
配置示例:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
import javax.persistence.EntityManagerFactory;
@Configuration
@EnableTransactionManagement
public class TransactionManagerConfig implements TransactionManagementConfigurer {
private final EntityManagerFactory entityManagerFactory;
public TransactionManagerConfig(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
}
@Bean
public PlatformTransactionManager transactionManager() {
return new JpaTransactionManager(entityManagerFactory);
}
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return transactionManager();
}
}
2. 使用 @Transactional 注解
在需要事务管理的方法或类上使用 @Transactional 注解。
示例:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class BankService {
@Autowired
private BankAccountRepository bankAccountRepository;
/**
* 转账方法,保证两个账户的资金变动是一个事务
*/
@Transactional
public void transfer(Long fromAccountId, Long toAccountId, Double amount) {
BankAccount fromAccount = bankAccountRepository.findById(fromAccountId).orElseThrow();
BankAccount toAccount = bankAccountRepository.findById(toAccountId).orElseThrow();
if (fromAccount.getBalance() < amount) {
throw new InsufficientFundsException("余额不足");
}
fromAccount.setBalance(fromAccount.getBalance() - amount);
toAccount.setBalance(toAccount.getBalance() + amount);
bankAccountRepository.save(fromAccount);
bankAccountRepository.save(toAccount);
}
}
事务传播行为
Spring 中的 @Transactional 注解还支持设置事务的传播行为(Propagation),用于指定当前事务方法的执行行为。
常用的传播行为:
-
REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
-
SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式继续运行。
-
MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
-
REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则将当前事务挂起。
-
NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则将当前事务挂起。
-
NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
-
NESTED:如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则按
REQUIRED属性执行。
示例:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateAccount(Long accountId, Double amount) {
// 更新账户余额
}
事务隔离级别
事务隔离级别用于解决并发时的读写冲突问题,常用的隔离级别有:
-
READ_UNCOMMITTED:允许读取未提交的数据,可能导致脏读、不可重复读和幻读。
-
READ_COMMITTED:只能读取已提交的数据,可以避免脏读,但可能导致不可重复读和幻读。
-
REPEATABLE_READ:在事务开始时锁定读取的数据,避免脏读和不可重复读,但可能导致幻读。
-
SERIALIZABLE:最严格的隔离级别,通过加锁避免脏读、不可重复读和幻读,但性能最差。
示例:
@Transactional(isolation = Isolation.REPEATABLE_READ)
public void performTransaction() {
// 执行业务逻辑
}
事务超时和只读
-
超时(timeout) :设置事务的超时时间,超时后事务将回滚。
-
只读(readOnly) :优化事务操作,告知数据库当前事务是只读的。
示例:
@Transactional(timeout = 30, readOnly = true)
public List<Account> getAllAccounts() {
// 查询所有账户信息
}
总结
-
事务的四大特性(ACID) :原子性、一致性、隔离性和持久性。
-
Spring 中的事务管理:通过
@Transactional注解实现声明式事务管理。 -
传播行为:指定事务方法的执行行为,如
REQUIRED、REQUIRES_NEW等。 -
隔离级别:解决并发时的读写冲突,如
READ_COMMITTED、SERIALIZABLE等。 -
事务超时和只读:优化事务操作,设置超时时间和只读属性。