springboot事务管理

目录

事务管理概述

如何使用@Transactional注解

事务管理的传播行为

事务隔离级别

事务的嵌套

手动提交事务

手动回滚事务

注解方式嵌套事务

事务管理的异常处理

在@Transactional注解中指定回滚策略

使用try-catch

自定义异常处理器

创建自定义异常类

编写自定义异常处理器类

在@Transactional注解中指定自定义异常处理器


事务管理概述

在关系型数据库中,事务是指一组相关的操作,这些操作被看作单个逻辑单元并且要么全部执行成功,要么全部回滚。事务管理就是保证所有操作都能够原子性地进行,即要么全部成功,要么全部失败。

在Spring Boot中,我们可以使用@Transactional注解来启用事务管理。当使用@Transactional注解时,Spring会将方法包装在一个事务中,并在方法执行期间自动处理事务提交或回滚。

如何使用@Transactional注解

在Spring Boot中使用@Transactional注解非常简单。只需将@Transactional注解添加到要进行事务管理的方法上即可。例如:

@Service
public class MyService {

    @Autowired
    private SomeRepository someRepository;

    @Transactional
    public void doSomething() {
        // 执行一些业务逻辑
        someRepository.save(entity1);
        someRepository.save(entity2);
        // 如果任何一个保存操作失败,则整个事务都会回滚。
    }
}

在上面的示例中,当方法doSomething()被调用时,Spring将自动为该方法创建一个事务。如果该方法执行过程中有任何异常抛出,那么整个事务都将被回滚,所有已经执行的保存操作也会被回滚。

事务管理的传播行为

Spring Boot中的@Transactional注解有一个非常强大的特性,即可以控制事务的传播行为。传播行为定义了事务如何在嵌套的方法调用中进行传递。

  • REQUIRED:默认值。如果当前没有事务,则创建一个新事务。如果当前已经有事务,则加入该事务。
  • SUPPORTS:如果当前有事务,则加入该事务;否则以非事务方式执行。
  • MANDATORY:如果当前有事务,则加入该事务;否则抛出异常。
  • REQUIRES_NEW:创建一个新事务,如果当前已经有事务,则将当前事务挂起。
  • NOT_SUPPORTED:以非事务方式执行操作,如果当前有事务,则将当前事务挂起。
  • NEVER:以非事务方式执行操作,如果当前有事务,则抛出异常。
  • NESTED:如果当前有事务,则在嵌套事务内执行;否则像REQUIRED一样执行。

事务隔离级别

除了传播行为之外,事务还有一个重要的概念,即隔离级别。隔离级别定义了多个并发事务之间应该如何相互隔离。Spring Boot支持以下五种隔离级别:

  • DEFAULT:使用数据库的默认隔离级别
  • READ_UNCOMMITTED:最低的隔离级别,允许读取未提交的数据
  • READ_COMMITTED:允许读取已提交的数据
  • REPEATABLE_READ:在同一事务中多次读取相同的数据会产生一致的结果
  • SERIALIZABLE:最高的隔离级别,所有并发事务按顺序逐个执行

可以使用@Transactional注解的isolation属性指定要使用的隔离级别。例如:

@Service
public class MyService {

    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void doSomething() {
        // 执行业务逻辑
    }
}

事务的嵌套

当一个方法内部调用另一个被@Transactional注解标记的方法时,会发生事务的嵌套。如果在内部方法中启动了新事务,则新事务将成为当前事务的子事务。

在子事务完成后,可以选择回滚该子事务或将其提交到父事务中。如果父事务成功提交,则所有子事务都将一起提交;如果父事务失败回滚,则所有子事务也将一起回滚。

下面是一个示例代码:

@Service
public class MyService {

    @Autowired
    private SomeRepository someRepository;

    // 外层事务
    @Transactional
    public void doSomething() {
        someRepository.save(entity1);
        try {
            // 内层事务
            doSomeOtherThing();
        } catch (Exception e) {
            // 内层事务抛出异常,外层事务回滚
        }
    }

    // 内层事务
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void doSomeOtherThing() {
        someRepository.save(entity2);
        // 如果这里抛出异常,则整个内嵌事务会被回滚
    }
}

在上面的示例中,doSomething()方法使用REQUIRED事务传播行为启用了一个外层事务,然后调用了doSomeOtherThing()方法,doSomeOtherThing()方法使用REQUIRES_NEW事务传播行为启用了一个内层事务。

如果在doSomething()方法中发生异常,则整个外层事务将被回滚,包括所有的子事务。如果在doSomeOtherThing()方法中发生异常,则只会回滚内层事务,而外层事务不受影响。

需要注意的是,在使用嵌套事务时,仅有@Transactional注解标记的方法才会产生事务。如果内部方法没有被@Transactional注解标记,则不会启动新的事务,事务的传播行为也就失去了意义。

手动提交事务

下面是一个示例代码:

@Service
public class MyService {

    @Autowired
    private SomeRepository someRepository;

    @Autowired
    private PlatformTransactionManager transactionManager;

    // 外层事务
    public void doSomething() {
        TransactionTemplate template = new TransactionTemplate(transactionManager);
        template.execute(new TransactionCallbackWithoutResult() {
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                someRepository.save(entity1);
                try {
                    // 内层事务
                    doSomeOtherThing();
                    // 如果内层事务成功,则手动提交外层事务
                    status.flush();
                } catch (Exception e) {
                    // 内层事务抛出异常,外层事务回滚
                    status.setRollbackOnly();
                }
            }
        });
    }

    // 内层事务
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void doSomeOtherThing() {
        someRepository.save(entity2);
        // 如果这里抛出异常,则整个内嵌事务会被回滚
    }
}

在上面的示例中,doSomething()方法使用TransactionTemplate对象手动执行事务操作,对于内层事务,再次使用@Transactional注解进行管理。如果内层事务成功,则手动提交外层事务;如果内层事务失败,则手动回滚外层事务。

手动回滚事务

下面是一个手动回滚事务的示例代码:

@Service
public class MyService {

    @Autowired
    private SomeRepository someRepository;

    @Autowired
    private PlatformTransactionManager transactionManager;

    // 外层事务
    public void doSomething() {
        TransactionTemplate template = new TransactionTemplate(transactionManager);
        template.execute(new TransactionCallbackWithoutResult() {
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                someRepository.save(entity1);
                try {
                    // 内层事务
                    doSomeOtherThing();
                    // 如果内层事务成功,则手动提交外层事务
                    status.flush();
                } catch (Exception e) {
                    // 内层事务抛出异常,手动回滚所有事务
                    status.setRollbackOnly();
                    throw e;
                }
            }
        });
    }

    // 内层事务
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void doSomeOtherThing() {
        someRepository.save(entity2);
        // 如果这里抛出异常,则整个内嵌事务会被回滚
    }
}

在上面的示例中,如果发生了任何异常,则手动回滚所有事务。在回滚时,需要将事务状态设置为rollback-only,以便Spring自动回滚所有连接的事务。

需要注意的是,手动提交和回滚事务通常不是必要的,只有在特殊情况下才使用。在大多数情况下,应该让Spring自动管理事务,以便实现更好的性能和可维护性。

注解方式嵌套事务

@Service
public class MyService {

    @Autowired
    private SomeRepository someRepository;

    // 外层事务
    @Transactional
    public void doSomething() {
        someRepository.save(entity1);
        try {
            // 内层事务
            doSomeOtherThing();
        } catch (Exception e) {
            // 内层事务抛出异常,外层事务回滚
        }
    }

    // 内层事务
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void doSomeOtherThing() {
        someRepository.save(entity2);
        // 如果这里抛出异常,则整个内嵌事务会被回滚
    }
}

在上面的示例中,doSomething()方法使用@Transactional注解标记外层事务,然后调用了doSomeOtherThing()方法,doSomeOtherThing()方法使用REQUIRES_NEW事务传播行为启用了一个内层事务。

如果在doSomething()方法中发生异常,则整个外层事务将被回滚,包括所有的子事务。如果在doSomeOtherThing()方法中发生异常,则只会回滚内层事务,而外层事务不受影响。

事务管理的异常处理

@Transactional注解中指定回滚策略

可以在@Transactional注解中使用rollbackFor属性指定需要回滚的异常类型。例如,如果希望在发生任何RuntimeException时回滚事务,则可以添加以下代码:

@Transactional(rollbackFor = RuntimeException.class)

使用try-catch

在Spring Boot中,可以使用try-catch块来处理业务逻辑中可能出现的异常。当抛出异常时,可以手动回滚事务以确保数据的一致性。例如,以下代码演示了如何在发生异常时回滚事务:

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    @Transactional
    public void save(User user) {
        try {
            // 保存用户信息
            userRepository.save(user);
        } catch (Exception e) {
            // 回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw e;
        }
    }
}

自定义异常处理器

在Spring Boot的事务管理中,可以使用自定义异常处理器来处理特定类型的异常。自定义异常处理器是实现org.springframework.transaction.interceptor.TransactionAspectSupport.TransactionExceptionHandler接口的类。在该接口中,只有一个方法handleException(),用于处理发生的异常。

下面是在Spring Boot中使用自定义异常处理器进行事务管理的步骤:

创建自定义异常类

首先,需要创建一个自定义异常类来处理特定类型的异常。例如,以下代码演示了如何创建一个UserNotFoundException异常类:

public class UserNotFoundException extends RuntimeException {
     public UserNotFoundException(String message) { 
        super(message); 
    } 
}
  1. 编写自定义异常处理器类

接下来,需要编写一个实现TransactionExceptionHandler接口的类来处理自定义异常。在该类中,需要实现handleException()方法,用于根据异常类型执行相应的回滚或提交操作。例如,以下代码演示了如何创建一个自定义异常处理器:

@Component 
public class CustomTransactionExceptionHandler implements TransactionExceptionHandler {                 
 @Override 
 public void handleException(Throwable ex) throws Throwable { 
     if (ex instanceof UserNotFoundException) { 
     // 如果抛出的异常是UserNotFoundException,则回滚事务     
    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
     throw ex; 
    } else {
      // 对其他异常进行默认的处理 
      TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 
     throw new RuntimeException(ex); 
   } 
 } 
}

在这个例子中,我们判断了抛出的异常是否是UserNotFoundException,如果是,则回滚事务并重新抛出此异常。否则,我们将使用默认的处理方式(即回滚事务并重新抛出RuntimeException)。

  1. @Transactional注解中指定自定义异常处理器

最后,在使用@Transactional注解时,需要在该注解中指定自定义异常处理器。例如,以下代码演示了如何在UserService类中使用自定义异常处理器:

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    @Transactional(rollbackFor = RuntimeException.class, exceptionHandler = CustomTransactionExceptionHandler.class)
    public void save(User user) {
        // 保存用户信息
        userRepository.save(user);
    
        if (user.getId() == null) {
            throw new UserNotFoundException("User not found!");
        }
    }
}

在这个例子中,我们在@Transactional注解中指定了自定义异常处理器CustomTransactionExceptionHandler.class。当抛出UserNotFoundException异常时,将会执行自定义异常处理器中指定的操作。

通过以上步骤,可以在Spring Boot应用程序中使用自定义异常处理器来进行事务管理,并针对特定类型的异常进行相应的处理。

你可能感兴趣的:(spring,boot,spring,java)