什么时候应该使用@Transactional注解?

问题描述 投票:0回答:3

我想知道我们什么时候应该在 Spring Boot 服务中使用

@Transactional

既然 JpaRepository 的

save()
方法带有
@Tranasactional
注释,我是否需要在我的服务方法中添加该注释?

我看过几篇文章说,如果您的服务方法内仅使用存储库(如下面的场景),则不需要将

@Transactional
放在服务方法上,因为
save()
已经注释了与
@Transactional
。是真的吗?

class EmployeeService {
    @Autowired
    EmployeeRepository repo;
        
    @Transactional //(Is it required here?)
    public void saveEmployee(Employee employee) {
        repo.save(employee)
    }
}

既然我们使用了多个存储库,那么在下面的情况下是否应该使用方法

getStudentsWithNameStartsWithAndGradeLessThan()

@Getter 
@Setter 
@Entity 
@Table(name = "student") 
public class Student { 
      @Id 
      @GeneratedValue(strategy = GenerationType.IDENTITY) 
      @Column(name = "id", nullable = false) 
      private Long id; 
     
      @Column(name = "name") 
      private String name; 
     
      @Column(name = "average_grade") 
      private Short averageGrade; 
}
public interface StudentRepository extends JpaRepository<Student, Long> { 
      Set<Student> findByAverageGradeLessThan(Short averageGrade); 
      Set<Student> findByNameStartsWithIgnoreCase(String name); 
}
@Service 
public class StudentService { 
     
      private final StudentRepository studentRepository; 
     
      public StudentService(StudentRepository studentRepository) { 
        this.studentRepository = studentRepository; 
      } 
     
       @Transactional //(Is it required here?)
      public Set<Student> getStudentsWithNameStartsWithAndGradeLessThan(String prefix, Short averageGrade) {
     
       Set<Student> students = studentRepository.findByNameStartsWithIgnoreCase(prefix); 
       students.retainAll(studentRepository.findByAverageGradeLessThan(averageGrade)); 
        return students; 
    
    } 
}
java spring spring-boot spring-data-jpa
3个回答
1
投票

如果您希望 Spring 事务管理为您打开事务、提交并处理您的行为回滚。特别是如果您正在使用多个表,您应该使用它,它充当 AOP 并确保事务已提交或回滚。

这个注解对你来说不是强制性的,而是让 spring 管理完整的跨表事务以保持一致性的一个好习惯。

如果您不使用此注释,Spring Data JPA 通常会将事务管理委托给底层持久化提供程序(例如 Hibernate、Eclipse 等),或者依赖于 Spring 应用程序上下文的默认事务配置。

考虑下面的示例示例,如果我在保存到第二个表时遇到异常,我的事务也应该回滚到第一个表。这可以通过 @Transactional 来完成,它将处理样板代码。

@Transactional
public void processOrder(Order order) {
    // Save order details
    orderRepository.save(order);

    // Update product quantity
    Product product = productRepository.findById(order.getProductId()).orElse(null);
    if (product != null) {
        int newQuantity = product.getQuantity() - order.getQuantity();
        if (newQuantity >= 0) {
            product.setQuantity(newQuantity);
            productRepository.save(product);
        } else {
            throw new IllegalArgumentException("Insufficient quantity in stock");
        }
    } else {
        throw new IllegalArgumentException("Product not found");
    }
}

更多信息在这里


0
投票

为了完成您对该问题的评论,我会说:

是的,

save()
方法确实已经有
@Transactional
注释,如果你打开它的实现,你可以自己看到它。

@Transactional
public <S extends T> S save(S entity) {
    Assert.notNull(entity, "Entity must not be null");
    if (this.entityInformation.isNew(entity)) {
        this.em.persist(entity);
        return entity;
    } else {
        return this.em.merge(entity);
    }
}

如果您的方法仅调用此方法而没有其他方法,则添加它是没有意义的。

假设你的方法有下一个主体:

    @Transactional
    public void saveEmployee(Employee employee) {
    
    repo.save(employee)
    userTrackerRepo.update() // or any other repo invocation or validation that if fails then save method should do rollback.
   }

那么有

@Transactional
注释就有意义了


0
投票

我认为,如果一个接口涉及到修改多个数据库表,应该使用事务来避免数据不一致。在你的第一段代码中,看起来是一个保存操作,但是如果涉及到多个表,你可以添加@Transactional注解。在你的第二段代码中,这似乎是一个数据库查询操作,如果涉及多个数据库表,你还应该添加事务。一般来说,是否需要追加交易是根据具体的业务情况来决定的..

© www.soinside.com 2019 - 2024. All rights reserved.