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使用Jsp的示例代码

    下面是 Spring Boot 使用 JSP 的详细攻略,内容包括: 添加 Maven 依赖 配置 Spring Boot 创建 JSP 页面 创建 Controller 类 运行并访问页面 1. 添加 Maven 依赖 首先在 pom.xml 文件中添加以下依赖: <dependencies> <dependency> <gr…

    Java 2023年6月15日
    00
  • Java中Lambda表达式的使用详解

    Java中Lambda表达式的使用详解 Lambda表达式是JDK8引入的一个新特性,它可以让Java程序员写出更简洁、更易读、更灵活的代码。本文将详细讲解Java中Lambda表达式的用法。 什么是Lambda表达式 Lambda表达式是一种匿名函数,它可以作为方法参数传递给其他方法,也可以作为返回值返回给调用方。Lambda表达式的语法如下: (参数列表…

    Java 2023年5月26日
    00
  • Java 二叉树遍历特别篇之Morris遍历

    Java 二叉树遍历特别篇之 Morris 遍历 简介 Morris 遍历是一种基于线索二叉树的遍历方式,它利用了二叉树中大量的空指针,将遍历的信息存储在空指针中,从而省去了递归和栈的空间消耗。这种遍历方式的时间复杂度为 $O(n)$,空间复杂度为 $O(1)$,因此比递归和栈的遍历方式更加高效。 本文将对 Morris 遍历进行详细的讲解,并提供两条示例说…

    Java 2023年5月26日
    00
  • 解决springboot 获取form-data里的file文件的问题

    关于“解决springboot 获取form-data里的file文件的问题”的攻略,我们可以分为以下几个步骤来讲解: 添加相关依赖 在使用Spring Boot的过程中需要引入一些相关依赖,我在这里推荐使用spring-boot-starter-web模块,并且添加spring-boot-starter-tomcat或者spring-boot-starte…

    Java 2023年5月20日
    00
  • JSONObject按put顺序排放与输出方式

    下面是有关”JSONObject按put顺序排放与输出方式”的攻略。 什么是JSONObject JSONObject是Java中的一个类,可以用于存储和操作JSON格式的数据。它能够将Java对象转换成JSON格式的字符串,也可以将JSON格式的字符串转换成Java对象。 JSONObject按put顺序排放 JSONObject是一种无序的数据结构,它并…

    Java 2023年5月26日
    00
  • IntelliJ中高效重构的10个快捷方式详解

    当谈到Java编程的时候,IntelliJ IDEA是程序员们的首选。IntelliJ IDEA是一款IDE,它是由JetBrains公司开发的一种Java集成开发环境。本文将介绍IntelliJ IDEA中的10个高效重构快捷方式,它们将帮助您在重构代码时更快、更高效地完成工作。 1. Rename(重命名) “Rename”(重命名)是一种在Intell…

    Java 2023年5月26日
    00
  • 苹果Mac中如何安装java应用?java mac版安装教程

    苹果Mac系统中安装Java应用需要经过以下几步: 1. 下载Java 首先需要下载Java,可以在Oracle官网下载最新版本的JDK(Java Development Kit)安装包,或者根据自己需要选择较旧的版本。下载完成后,双击安装包运行即可。 2. 设置环境变量 安装完JDK后,需要在系统环境变量中设置Java的HOME路径和可执行路径。打开终端(…

    Java 2023年5月26日
    00
  • Java 装箱与拆箱详解及实例代码

    Java 装箱与拆箱详解及实例代码 什么是装箱与拆箱 在Java中,基本的数据类型包括byte, short, int, long, float, double, char, boolean等。而Java中还有一种引用类型,例如String、Scanner等。在此基础上,Java还增加了一种特殊的包装类型,它们分别是Byte, Short, Integer,…

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