technology-note/java/springboot系列/2.springboot事务处理(自动或手动).md
2022-01-20 16:33:50 +08:00

130 lines
4.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
id: "20190619"
date: "2019/06/19 10:38:00"
title: "springboot事务处理自动/手动事务)"
tags: ["java", "springboot", "transaction"]
categories:
- "java"
- "spring boot学习"
---
![缇娜](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190619175857.png)
今天写代码的时候遇到了这样的一个问题:通过`this.saveData()`调用`saveData`方法,这个方法被`@Transactional`注解,期望在 saveData 抛出错误时能够回滚数据库,结果事务并没有生效。然后便对 spring boot 的事务进行了一次更深入的学习。
学习笔记如下:
要使用事务首先需要开启事务,在启动类中加入注解:`@EnableTransactionManagement`
主要内容如下:
- 自动事务及其原理
- 手动事务的使用
# 自动事务
通过`@Transactional`开启事务。在`UserService`中定义一个事务方法`save`.然后在`UserController`中注入`UserDao`,并调用`save`方法。
<!-- more -->
```java
@Service
public class UserService{
@Autowired
private UserDao dao;
@Transactional(rollbackFor = Exception.class)
public void save(){
//一些数据库操作
}
}
@RestController
public class UserController{
@Autowired
private UserService service;
@GetMapping("/")
public String getInfo(){
service.save();
return "OK";
}
}
```
如上是一个典型的自动事务调用过程。但是如果是这样一种情况呢?现在`UserService`中增加一个方法`saveAll`,并在该方法中循环调用`save`方法,然后想让每一次的`save`方法都有事务支持,且相互不影响。`saveAll`代码如下:
```java
public void saveAll(){
for(int i=0;i<10;i++){
this.save();
}
}
```
通常会想当然的认为 save 方法被`@Transactional`注解了,那么它就是支持事务的了,这种写法能够实现我们想要的效果。然而实际是不行的。
## 为什么 this 调用就不行呢?
原因就在**Spring**.spring 是一个 IOC 容器,它来统一管理所有的类,然后你想要用某个类的时候,它就会把这个类注入进入。关键就在这里:注入的这个类并**不是这个类本身**,然后这个类的**代理**。以代码来举例:
```java
class UserController{
@Autowired
UserService userService;
public void doSomeThing(){
userService.save();
}
}
```
通过`@Autowired`注入的 userService 实际上并不是 UserService 的实例userService 指向地址和这个类实例中`this`所指向的并不相同。实际调用`save`方法的并不是`UserController`类,而是`Spring`,这也就能解释为什么 Spring 能够帮我进行进行很多操作,比如自动事务,错误处理等。
如果我们通过 this 来调用 save 方法,显然是直接调用,不经过 spring 的代理,也就没有自动事务了。
那么如何才能实现上面想要的效果呢?
很简单,通过`AopContext.currentProxy()`来获取当前类的代理对象,这样调用`save`方法时就有自动事务了。使用该方法需要在启动类中加入如下注解:`@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)`,然后 pom 依赖中加入如下依赖:
```xml
<!--aop依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
```
或者使用手动事务
# 手动事务
手动事务就是通过代码来显式的进行事务操作。使用方法如下:
```java
// 需要先注入如下两个类
@Autowired
DataSourceTransactionManager dataSourceTransactionManager;
@Autowired
TransactionDefinition transactionDefinition;
public void saveAll(){
//开启事务
TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
try{
this.save();
//提交事务
dataSourceTransactionManager.commit(transactionStatus);
}catch(Exception e){
//回滚事务
dataSourceTransactionManager.rollback(transactionStatus);
}
}
```
OK!