我想知道我们什么时候应该在 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;
}
}
如果您希望 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");
}
}
为了完成您对该问题的评论,我会说:
是的,
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
注释就有意义了
我认为,如果一个接口涉及到修改多个数据库表,应该使用事务来避免数据不一致。在你的第一段代码中,看起来是一个保存操作,但是如果涉及到多个表,你可以添加@Transactional注解。在你的第二段代码中,这似乎是一个数据库查询操作,如果涉及多个数据库表,你还应该添加事务。一般来说,是否需要追加交易是根据具体的业务情况来决定的..