什么是事务
在编程中,事务(Transaction)是指一个包含了一组操作或步骤的程序单元,这些操作或步骤被封装在一起作为一个单独的执行单元来执行。更简单的说就是,一个有若干操作的集合。执行后,它们要么一起成功,要么一起失败。
事务的特性
事务有四大特性(ACID),原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)四个属性,这些属性被称为ACID属性。
- 原子性:事务被视为不可分割的最小单元,事务的所有操作要么全部提交成功,要么全部失败回滚。
- 隔离性:事务的执行不会影响其他事务的执行。
- 持久性:一旦事务提交,其修改的效果就是永久性的。
- 一致性:事务的执行不能破坏数据库数据的完整性和一致性(必须使数据库从一个一致性状态变换到另一个一致性状态)。
Spring中的事务
在简单的了解事务后,接下来看看在Spring中如何实现事务。
Spring 支持两种类型的事务:声明式事务和编程式事务。
编程式事务
它一种通过编程方式控制事务边界的方法,它提供了更加灵活的事务控制方式,允许开发人员根据业务需求自定义事务的边界——由开发人员手动控制事务的开启、提交和回滚,以实现对事务的精细控制。
Spring提供了PlatformTransactionManager接口
和TransactionTemplate类
来实现编程式事务管理。
开发人员可以通过注入TransactionTemplate
实例,并使用该实例的execute方法来执行包含事务操作的业务逻辑。
- 以下是通过
TransactionTemplate类
来实现事务管理的方法
@Autowired
private TransactionTemplate transactionTemplate;
public void updateUser(User user) {
try {
transactionTemplate.execute(status -> {
// 在事务中执行业务逻辑
// ...
return null;
});
} catch (Exception e) {
// 发生异常时回滚事务
transactionTemplate.rollback(status -> {
// 回滚事务
return null;
});
}
}
而PlatformTransactionManager
接口定义了3个基本的事务操作方法,具体的实现都是由不同的子类来实现的。它有众多实现,但是我们并不需要掌握这些具体实现类的用法,我们只需要掌握好 PlatformTransactionManager
的用法即可。例如:如果你使用的是 JDBC 那么可以将 DataSourceTransactionManager
作为事务管理器。
public interface PlatformTransactionManager extends TransactionManager {
TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
// 源码
- 以下是使用
PlatformTransactionManager
的实现类DataSourceTransactionManager
(springboot内置的)来实现编程式事务
@Autowired
private DataSourceTransactionManager transactionManager;
public void updateName(){
// 定义事务属性
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// 获取事务状态
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 在此处执行数据库操作或其他业务逻辑
String username = "ready to one+1";
Integer num = 1;
workersMapper.updateUserName(username, num);
int res = 1/0;
// 提交事务
transactionManager.commit(status);
} catch (Exception e) {
// 发生异常时回滚事务
transactionManager.rollback(status);
}
}
上述例子中,会发生异常ArithmeticException,从而导致事务回滚,不会对数据库进行更新。
以上就是编程式事务,可以发现——它将事务的控制跟业务代码混合在了一起,这一定程度上增加了代码的复杂性。且在每个操作前后都需要手动调用事务管理器的方法,这可能会增加出错的可能性。如果在一些业务复杂的情况下,该情况尤为明显。
因此,对于复杂的业务逻辑,通常建议使用声明式事务管理,因为它更简洁、更易于管理。
声明式事务
使用声明式事务——首先,需要在Spring的配置文件中配置一个PlatformTransactionManager
的实现,例如DataSourceTransactionManager
。然后,可以在需要使用事务的方法或类上添加注解,例如@Transactional
注解,来开启事务。
- 配置事务管理器
@Configuration
public class AppConfig {
@Autowired
private DataSource dataSource;
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource);
}
}
- 通过注解来开启事务
@Transactional
public void test(){
String username = "part+1";
Integer num = 1;
workersMapper.updateUserName(username, num);
int res = 1/0;
}
@Transactional
注解开启了事务,test
方法在事务的保护下执行,如果在执行过程中出现了异常,事务会被自动回滚。
以上就是spring中使用事务的两种方式
注意事项
@Transactional
只能应用到 public 方法上才会有效。其他类型(如:private)的方法虽然不报错,但不会生效。@Service
、@Component
等注解,这个类就不会被加载成一个Bean,这个类就不会被Spring管理了,事务就失效了。