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

yizhihongxing

下面是详细讲解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日

相关文章

  • 一篇文章带你深入了解Java线程池

    一篇文章带你深入了解Java线程池 什么是线程池? 线程池是一个线程队列管理器,大大提高了多线程的处理效率。在开发中使用线程池可以避免多次创建和销毁线程带来的性能开销,提高程序的稳定性和性能表现。 Java中的线程池 Java中的线程池是由ThreadPoolExecutor和Executors来实现的,其中Executors是一个线程池的工厂类,提供了很多…

    Java 2023年5月18日
    00
  • 这一次搞懂SpringMVC原理说明

    一、 SpringMVC 原理 SpringMVC 是 Spring 框架中的一个模块,是用来实现基于 Java 技术的 Web 应用程序开发的。下面介绍 SpringMVC 的原理。 请求 dispatcherServlet 当用户请求一个页面时,dispatcherServlet 是 SpringMVC 的入口点。dispatcherServlet 是一…

    Java 2023年5月19日
    00
  • java对象类型转换和多态性(实例讲解)

    下面我将详细讲解Java对象类型转换和多态性的完整攻略。 对象类型转换 在Java中,对象类型转换分为向上转型和向下转型两种。 向上转型 向上转型指的是将一个子类对象转换为父类对象的过程。因为子类是继承自父类的,所以子类对象的类型也包含了父类对象的所有类型,所以可以将子类对象转换为父类对象。 向上转型的格式如下: 父类名 变量名 = 子类实例; 例如,有一个…

    Java 2023年5月26日
    00
  • 子线程任务发生异常时主线程事务回滚示例过程

    子线程任务发生异常时主线程事务回滚是一种常见的处理机制,下面我将为您提供一个完整的攻略来解释相关的过程。 首先,我们需要了解一些基本的知识点: 什么是子线程子线程就是在主线程之外启动的线程。子线程可以并行执行,无需等待主线程完成。 什么是主线程主线程是程序的入口,它负责启动并控制整个程序的执行流程。所有的子线程都是由主线程创建的。 什么是事务事务是一组相关的…

    Java 2023年5月26日
    00
  • Java File类常用方法与文件过滤器详解

    Java File类是对文件系统中的文件和文件夹进行操作的类。它提供了很多常用的方法,可以方便地对文件进行读取、写入和其他的一些操作。本文将详细讲解Java File类的常用方法及文件过滤器的使用。 文件对象创建 File类的构造方法很多,常见的有以下几种: File(File parent, String child):从父抽象路径名和子路径名字符串创建新…

    Java 2023年5月19日
    00
  • Java中的synchronized 优化方法之锁膨胀机制

    Java中的synchronized 优化方法之锁膨胀机制 Java中的synchronized是一种线程安全的同步机制,能够保证多个线程访问同一个对象的方法或段代码时,只有一个线程执行,其他线程等待,直到执行完毕后才能继续执行。然而,synchronized也可能带来一些性能问题。因此,Java提出了一些优化方法,其中之一就是锁膨胀机制。 什么是锁膨胀机制…

    Java 2023年5月26日
    00
  • 设计模式在Spring框架中的应用汇总

    设计模式在Spring框架中的应用汇总 概述 设计模式是一种解决特定场景下常见问题的经过验证的解决方案集合。它使用经过测试和验证的技术和方法,以提高代码的可读性,可维护性和可重用性,同时降低了代码的复杂性和重复性。 Spring框架是一个非常流行的开源框架,可以构建Java企业级应用程序。它提供了许多内置的模块以及许多可插拔的项目,以帮助开发人员创建高质量和…

    Java 2023年5月20日
    00
  • 解决java maven项目找不到jconsole-1.8.0.jar和tools-1.8.0.jar包问题

    解决java maven项目找不到jconsole-1.8.0.jar和tools-1.8.0.jar包问题的完整攻略如下: 问题说明 当使用Maven构建Java项目时,有时候会出现找不到jconsole-1.8.0.jar和tools-1.8.0.jar包的问题。这是因为Java从JDK 9开始,已经将jconsole.jar、tools.jar等jar…

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