Spring中非事务方法调用事务方法仍启事务?IntelliJ警告存疑
事务自调用的疑惑:IntelliJ警告与实际事务行为不符?
在Spring Boot 3.2.2环境下,我遇到一个事务相关的疑问:PersonService类的非事务方法createPerson调用了标注@Transactional的createPersonTransactional方法。IntelliJ IDEA高亮该调用,提示这是事务自调用,运行时不会触发事务,但控制器调用createPerson方法后,日志却显示事务已创建。我原本认为这类内部方法调用会直接执行原方法而非Spring生成的事务代理方法,因此疑惑IntelliJ的警告是否错误?
代码示例
@Service class PersonService(val personRepository: PersonRepository) { fun createPerson(personRequest: PersonRequest): Person { return createPersonTransactional(personRequest) } @Transactional fun createPersonTransactional(personRequest: PersonRequest): Person { val person = Person(name = personRequest.name) personRepository.save(person) return person } } interface PersonRepository : JpaRepository<Person, String> @RestController class PersonController( private val personService: PersonService ) { @PostMapping("/person", produces = [MediaType.APPLICATION_XML_VALUE]) fun createPerson(@RequestBody personRequest: PersonRequest): Person { return personService.createPerson(personRequest) } }
运行日志
2024-02-09T09:38:32.084Z DEBUG 5102 --- [nio-8081-exec-3] o.s.web.servlet.DispatcherServlet : POST "/person", parameters={} 2024-02-09T09:38:32.084Z DEBUG 5102 --- [nio-8081-exec-3] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.example.rosbug.PersonController#createPerson(PersonRequest) 2024-02-09T09:38:32.084Z DEBUG 5102 --- [nio-8081-exec-3] o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor 2024-02-09T09:38:32.152Z DEBUG 5102 --- [nio-8081-exec-3] m.m.a.RequestResponseBodyMethodProcessor : Read "application/json;charset=UTF-8" to [PersonRequest(name=bert)] 2024-02-09T09:38:32.178Z DEBUG 5102 --- [nio-8081-exec-3] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(1455667122<open>)] for JPA transaction 2024-02-09T09:38:32.178Z DEBUG 5102 --- [nio-8081-exec-3] o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT 2024-02-09T09:38:32.182Z DEBUG 5102 --- [nio-8081-exec-3] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@65c57510] 2024-02-09T09:38:32.283Z DEBUG 5102 --- [nio-8081-exec-3] o.s.orm.jpa.JpaTransactionManager : Initiating transaction commit 2024-02-09T09:38:32.283Z DEBUG 5102 --- [nio-8081-exec-3] o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(1455667122<open>)] 2024-02-09T09:38:32.305Z DEBUG 5102 --- [nio-8081-exec-3] o.s.orm.jpa.JpaTransactionManager : Not closing pre-bound JPA EntityManager after transaction 2024-02-09T09:38:32.308Z DEBUG 5102 --- [nio-8081-exec-3] m.m.a.RequestResponseBodyMethodProcessor : Using 'application/xml', given [*/*] and supported [application/xml] 2024-02-09T09:38:32.320Z DEBUG 5102 --- [nio-8081-exec-3] m.m.a.RequestResponseBodyMethodProcessor : Writing [com.example.rosbug.Person@3b4eb178] 2024-02-09T09:38:32.340Z DEBUG 5102 --- [nio-8081-exec-3] o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptor 2024-02-09T09:38:32.341Z DEBUG 5102 --- [nio-8081-exec-3] o.s.web.servlet.DispatcherServlet : Completed 200 OK
解答
IntelliJ的警告没有错误,你看到的事务并非来自createPersonTransactional方法上的@Transactional注解,而是来自Spring Data JPA的save方法本身。
关键分析点:
- Spring事务代理机制:内部方法调用(同一个类中方法互相调用)确实不会触发Spring的事务代理增强,所以你自己标注在
createPersonTransactional上的@Transactional并未生效。 - 日志中的事务来源:日志里明确显示事务名称是
org.springframework.data.jpa.repository.support.SimpleJpaRepository.save,说明这个事务是由JpaRepository的默认实现类SimpleJpaRepository的save方法触发的——Spring Data JPA的save方法自带@Transactional注解,默认会开启事务。 - 验证方式:可以在
createPersonTransactional的personRepository.save(person)之后手动抛出一个异常,观察数据是否回滚。如果是createPersonTransactional的事务生效,数据会被回滚;但实际情况是数据不会回滚,因为事务是save方法的,save执行完成后事务已经提交,后续异常无法触发回滚。
简单来说:IntelliJ警告的是你自己写的@Transactional不会生效,而日志里的事务是Spring Data JPA自带的,两者并不冲突。
内容的提问来源于stack exchange,提问作者PaulNUK
相关产品推荐
相关产品推荐

