---
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!

