一.Spring 编程式事务(了解)
- 开启事务(获取事务)
- 提交事务
- 回滚事务
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/user")
@RestController
public class UserController {
// JDBC 事务管理器
@Autowired
private DataSourceTransactionManager dataSourceTransactionManager;
// 定义事务属性
@Autowired
private TransactionDefinition transactionDefinition;
@Autowired
private UserService userService;
@RequestMapping("/registry")
public String registry(String name,String password){
// 开启事务
TransactionStatus transactionStatus = dataSourceTransactionManager
.getTransaction(transactionDefinition);
//⽤⼾注册
userService.registryUser(name,password);
//提交事务
dataSourceTransactionManager.commit(transactionStatus);
//回滚事务
//dataSourceTransactionManager.rollback(transactionStatus);
return "注册成功";
}
}
UserController
,它包含了一个用于用户注册的方法
registry
。在
registry
方法中,通过编程式事务管理,手动开启了数据库事务,调用了
UserService
的
registryUser
方法进行用户注册,如果注册成功则提交事务,如果在注册过程中遇到异常则回滚事务。
//提交事务
dataSourceTransactionManager.commit(transactionStatus);
//回滚事务
dataSourceTransactionManager.rollback(transactionStatus);
运⾏程序:
观察数据库, 虽然程序返回"注册成功", 但数据库并没有新增数据.
二.Spring 声明式事务 @Transactional
以下是@Transactional注解的一些关键特性和用法:
-
方法级别的事务管理:@Transactional可以注解在方法上,表示该方法将运行在事务的上下文中。如果方法执行成功,则自动提交事务;如果方法抛出运行时异常(RuntimeException 或其子类),则自动回滚事务。
-
类级别的事务管理:@Transactional 也可以注解在类上,表示该类中的所有公共方法都将启用事务管理。但是,如果类中的某个方法不希望使用事务管理,可以在该方法上使用
@Transactional(propagation = Propagation.NOT_SUPPORTED)
来声明。 -
事务属性:@Transactional,注解提供了多个属性来定义事务的行为,包括传播行为(
propagation
)、隔离级别(isolation
)、超时时间(timeout
)、只读标志(readOnly
)以及回滚规则(rollbackFor
、noRollbackFor
)等。 -
代理机制:Spring 通过代理机制来实现声明式事务管理。对于基于接口的代理(JDK 动态代理),Spring 会为目标接口创建一个代理接口实现;对于类代理(CGLIB 代理),Spring 会为目标类创建一个子类。事务管理的逻辑被嵌入到这些代理对象中。
-
异常回滚:默认情况下,@Transactional 注解的事务会在遇到运行时异常时回滚。但是,开发者可以通过
rollbackFor
和noRollbackFor
属性来自定义回滚规则。 -
事务的传播行为@Transactional的
propagation
属性定义了事务的传播行为,即当前事务方法应该如何与存在的事务进行交互。例如,Propagation.REQUIRED
表示如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
使用 @Transactional注解可以极大地简化事务管理的代码,使开发者能够更专注于业务逻辑的实现,而不是事务管理的细节。然而,也需要注意,由于事务管理是通过代理实现的,因此有些情况下(如类内部的方法调用)可能无法触发事务管理逻辑。此外,还需要合理配置 Spring 的事务管理器(如 DataSourceTransactionManager
)和数据源,以确保事务能够正常工作。
@RequestMapping("/trans")
@RestController
public class TransactionalController {
@Autowired
private UserService userService;
@Transactional
@RequestMapping("/registry")
public String registry(String name,String password){
//⽤⼾注册
userService.registryUser(name,password);
return "注册成功";
}
}
@Slf4j
@RequestMapping("/trans")
@RestController
public class TransactionalController {
@Autowired
private UserService userService;
@Transactional
@RequestMapping("/registry")
public String registry(String name,String password){
//⽤⼾注册
userService.registryUser(name,password);
log.info("⽤⼾数据插⼊成功");
//强制程序抛出异常
int a = 10/0;
return "注册成功";
}
}
@Transactional 作⽤
@Transactional
@RequestMapping("/registry")
public String registry(String name,String password){
//⽤⼾注册
userService.registryUser(name,password);
log.info("⽤⼾数据插⼊成功");
//对异常进⾏捕获
try {
//强制程序抛出异常
int a = 10/0;
}catch (Exception e){
e.printStackTrace();
}
return "注册成功";
}
@Transactional
@RequestMapping("/registry")
public String registry(String name,String password){
//⽤⼾注册
userService.registryUser(name,password);
log.info("⽤⼾数据插⼊成功");
//对异常进⾏捕获
try {
//强制程序抛出异常
int a = 10/0;
}catch (Exception e){
//将异常重新抛出去
throw e;
}
return "注册成功";
}
@Transactional
@RequestMapping("/registry")
public String registry(String name,String password){
//⽤⼾注册
userService.registryUser(name,password);
log.info("⽤⼾数据插⼊成功");
//对异常进⾏捕获
try {
//强制程序抛出异常
int a = 10/0;
}catch (Exception e){
// ⼿动回滚事务
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
return "注册成功";
}
2.1@Transactional 详解
2.1.1 rollbackFor
我们上⾯为了演⽰事务回滚, ⼿动设置了程序异常
int a = 10/0;
@Transactional
@RequestMapping("/r2")
public String r2(String name,String password) throws IOException {
//⽤⼾注册
userService.registryUser(name,password);
log.info("⽤⼾数据插⼊成功");
if (true){throw new IOException();
}
return "r2";
}
发现虽然程序抛出了异常, 但是事务依然进⾏了提交
@Transactional(rollbackFor = Exception.class)
@RequestMapping("/r2")
public String r2(String name,String password) throws IOException {
//⽤⼾注册
userService.registryUser(name,password);
log.info("⽤⼾数据插⼊成功");if (true){
throw new IOException();
}
return "r2";
}
发现虽然程序抛出了异常, 但是事务依然进⾏了提交