SpringBoot 注解事务声明式事务的方式

下面是详细讲解SpringBoot注解事务声明式事务的方式的完整攻略。

什么是事务

在数据库的操作中,当多条SQL语句同时执行时,为了保证数据的一致性和完整性,我们需要让这些SQL语句在一个整体中完成,有且只有所有语句都执行成功时才提交到数据库里,而任一条语句执行失败时则所有语句都不会被提交。这个整体操作就是“事务”。

Java中,事务可以通过编程式、声明式两种方式来实现。其中,声明式事务更加方便、简洁,不需要像编程式事务那样手动管理事务,而是通过注解自动实现。

SpringBoot注解事务的声明方式

在SpringBoot中,声明式事务的方式有两种,一种是基于AOP的方式,即通过在方法上添加@Transactional注解来开启事务;另一种是基于AspectJ的方式,即通过XML配置或@AspectJ注解来开启事务。这里我们主要讲解基于AOP的方式。

基于AOP的声明式事务

1.配置数据源

首先通过application.properties将数据源配置好:

spring.datasource.url=jdbc:mysql://localhost:3306/test_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

2.添加依赖

在pom.xml中添加SpringBoot的jdbc、MySQL连接驱动、事务等依赖。

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <scope>runtime</scope>
</dependency>

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
</dependency>

3.添加注解

在需要使用事务的方法上添加@Transactional注解。这里我们用一个简单的例子来说明:

@Service
public class UserServiceImpl implements UserService {

  @Autowired
  private JdbcTemplate jdbcTemplate;

  @Override
  @Transactional
  public void add(User user) {
    jdbcTemplate.update("insert into user(name, age) values(?, ?)", user.getName(), user.getAge());
  }

  @Override
  public User find(int id) {
    return jdbcTemplate.queryForObject("select * from user where id=?", new BeanPropertyRowMapper<>(User.class), id);
  }
}

在add方法上添加了@Transactional注解,表示此方法需要开启事务。如果在add方法执行过程中抛出异常,事务将会自动回滚。

4.测试

可以通过JUnit测试来验证事务是否正常工作。

@SpringBootTest
class UserServiceTest {

  @Autowired
  private UserService userService;

  @Test
  public void test_add() {
    User user = new User("test", 18);
    userService.add(user);
    User result = userService.find(user.getId());
    assertNotNull(result);
    assertEquals(user.getId(), result.getId());
  }

  @Test
  public void test_exception() {
    User user = new User("test", 18);
    userService.add(user);
    assertThrows(DataIntegrityViolationException.class, () -> {
      userService.add(user);
    });
  }
}

test_add方法测试了正常情况下的插入操作,test_exception方法测试了在插入数据时出现异常的情况,如果事务正常工作则会回滚整个事务。

通过以上步骤,我们就可以轻松地使用基于AOP的声明式事务了。

基于AspectJ的声明式事务

基于AOP的方式声明事务需要使用@Transactional注解,而基于AspectJ的方式需要通过XML配置或@AspectJ注解来实现。

这里我们以@AspectJ注解的方式为例,步骤如下:

1.添加依赖

在pom.xml中添加SpringBoot和AspectJ的依赖。

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
</dependency>

<dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjweaver</artifactId>
</dependency>

2.添加注解

在SpringBoot的启动类上添加@EnableAspectJAutoProxy注解,表示启用AspectJ自动代理。

@SpringBootApplication
@EnableAspectJAutoProxy
public class Application {

  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
}

然后在需要使用事务的方法上添加@Transational注解,并在配置类上添加@Aspect注解。

@Service
public class UserServiceImpl implements UserService {

  @Autowired
  private JdbcTemplate jdbcTemplate;

  @Override
  public User find(int id) {
    return jdbcTemplate.queryForObject("select * from user where id=?", new BeanPropertyRowMapper<>(User.class), id);
  }

  @Override
  @Transactional
  public void add(User user) {
    jdbcTemplate.update("insert into user(name, age) values(?, ?)", user.getName(), user.getAge());
  }
}
@Aspect
@Configuration
public class TransactionAspect {

  @Autowired
  private DataSource dataSource;

  @Bean
  public PlatformTransactionManager transactionManager() {
    return new DataSourceTransactionManager(dataSource);
  }

  @Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
  public void transactionPointcut() {}

  @Around("transactionPointcut()")
  public void transactional(ProceedingJoinPoint joinPoint) {
    TransactionStatus transactionStatus = null;
    try {
      DefaultTransactionDefinition def = new DefaultTransactionDefinition();
      def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
      transactionStatus = transactionManager().getTransaction(def);
      joinPoint.proceed();
      transactionManager().commit(transactionStatus);
    } catch (Throwable e) {
      if (transactionStatus != null) {
        transactionManager().rollback(transactionStatus);
      }
      throw new RuntimeException(e);
    }
  }
}

其中,@Pointcut注解表示切入点,即需要被拦截的方法,这里使用了@Transactional注解来表示切入点;@Around注解表示环绕通知,即在方法执行前后执行的逻辑,这里使用该注解来实现事务的开启、提交和回滚操作。

示例

为了更好地理解使用注解声明式事务的方式,这里我们用一个简单的示例来演示。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {

  private static final long serialVersionUID = 1L;

  private Integer id;

  private String name;

  private Integer age;
}
public interface UserService {

  void add(User user);

  User find(int id);
}
@Service
public class UserServiceImpl implements UserService {

  @Autowired
  private UserDao userDao;

  @Override
  @Transactional
  public void add(User user) {
    userDao.add(user);
  }

  @Override
  public User find(int id) {
    return userDao.find(id);
  }
}
@Repository
public class UserDao {

  @Autowired
  private JdbcTemplate jdbcTemplate;

  public User find(int id) {
    return jdbcTemplate.queryForObject("select * from user where id=?", new BeanPropertyRowMapper<>(User.class), id);
  }

  public void add(User user) {
    jdbcTemplate.update("insert into user(name, age) values(?, ?)", user.getName(), user.getAge());
  }
}

在UserService的实现类UserServiceImpl中,我们在add方法上添加了@Transactional注解,表示需要开启事务;在UserDao中直接使用了JdbcTemplate来执行SQL语句。

@SpringBootTest
class UserServiceTest {

  @Autowired
  private UserService userService;

  @Test
  public void test_add() {
    User user = new User(null, "test", 18);
    userService.add(user);
    User result = userService.find(user.getId());
    assertNotNull(result);
    assertEquals(user.getName(), result.getName());
  }

  @Test
  public void test_exception() {
    User user = new User(null, "test", 18);
    userService.add(user);
    assertThrows(DataIntegrityViolationException.class, () -> {
      userService.add(user);
    });
  }
}

在测试用例中,我们测试了正常插入数据和插入数据出现异常时事务回滚的情况。

总结

通过上述内容,我们可以总结出使用SpringBoot注解事务声明式事务的方式的步骤:

  1. 配置数据源。
  2. 添加依赖。
  3. 在需要使用事务的方法上添加@Transactional注解,或在切点方法上添加该注解。
  4. 测试所有情况以确定事务是否正确工作。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringBoot 注解事务声明式事务的方式 - Python技术站

(0)
上一篇 2023年5月15日
下一篇 2023年5月15日

相关文章

  • SpringBoot整合Mybatis-plus的具体使用

    我们来详细讲解一下 SpringBoot 整合 Mybatis-plus 的具体使用攻略。 1. 引入相关依赖 首先,我们需要在 pom.xml 文件中引入相关依赖: <!– Mybatis-plus 依赖 –> <dependency> <groupId>com.baomidou</groupId> &l…

    Java 2023年5月20日
    00
  • Spring请求参数校验功能实例演示

    我来为您讲解“Spring请求参数校验功能实例演示”的完整攻略,首先我们需要了解以下几点: Spring请求参数校验依赖于Hibernate Validator(JSR 380)。 在Controller层使用@Valid注解对参数进行校验。 在参数对象中使用Hibernate Validator的注解对属性进行校验。 接下来我们将透过两个示例来进行具体演示…

    Java 2023年5月20日
    00
  • JGroups实现聊天小程序

    以下是关于使用JGroups实现聊天小程序的完整攻略,希望能够帮助您: JGroups实现聊天小程序 介绍 JGroups是一个用于构建群组应用程序的工具包,该工具包允许应用程序中的各个节点之间相互通信和协作。在本教程中,我们将使用JGroups构建一个简单的聊天应用程序。 准备工作 在开始构建JGroups聊天应用程序之前,我们需要首先安装Java和Mav…

    Java 2023年5月23日
    00
  • ES6 Array常用扩展的应用实例分析

    下面就针对题目提供一份“ES6 Array常用扩展的应用实例分析”的攻略。 ES6 Array常用扩展 1. Array.from() Array.from() 方法可以将一个类似数组或可迭代对象转换为一个真正的数组。该方法需要一个目标对象作为参数,可以指定一个函数来对原数组的每个元素进行操作,并返回一个新的数组。 let arr = "12345…

    Java 2023年5月26日
    00
  • Java新API的时间格式化

    下面我将详细讲解Java新API的时间格式化的完整攻略。 什么是时间格式化? 时间格式化是将时间值转换为特定格式的过程,使其更易于理解和显示。Java提供了多种格式化时间的方法。 基本概念 Java的时间格式化主要是通过 java.time.format.DateTimeFormatter 类实现的。DateTimeFormatter 的常用方法如下: of…

    Java 2023年5月20日
    00
  • Java 数组详解及示例代码

    Java 数组详解及示例代码 什么是数组 数组(Array)是由相同类型的数据按照一定的顺序排列而成的集合,是Java程序设计中最基本的数据结构之一。 在Java中,数组可以看成是一种容器,可以存放多个同类型的数据。其中每个数据被称为元素(Element),而在数组中,每个元素可以通过一个编号(Index)进行唯一标识。 创建数组 在Java中,创建数组有两…

    Java 2023年5月23日
    00
  • java中你的项目应该如何正确分层

    在Java中,一个良好的项目设计需要正确的分层,这对于项目的稳定性,可扩展性以及可维护性都至关重要。下面将介绍几个分层和组织代码的最佳实践: 1. 分层架构 通常情况下,我们建议使用分层架构将应用程序划分为几个不同的部分,每个部分都有其独特的功能。这些层有不同的职责,且耦合度要尽量低。 分层结构通常包括以下几个部分: 表示层 (Presentation La…

    Java 2023年5月26日
    00
  • 简单总结SpringMVC拦截器的使用方法

    以下是关于“简单总结SpringMVC拦截器的使用方法”的完整攻略,其中包含两个示例。 1. 前言 SpringMVC是一种常用Java Web开发框架,其核心思想是基于MVC模式来实现Web应用程序开发。而拦截器是SpringMVC框架的一个重要组件,可以在请求到达Controller之前或之后进行一些处理。本攻略将简单总结SpringMVC拦截器的使用方…

    Java 2023年5月16日
    00
合作推广
合作推广
分享本页
返回顶部