Spring`RestController`方法注释为@ Transactional`,但是“当前没有事务处于活动状态”?

时间:2019-08-14 14:01:34

标签: java spring transactions spring-data-jpa spring-transactions

假设我有一个简单的控制器

RequestMapping(value = "api/v1")
@RestController
public class FooController {

    private final FooService fooService;

    FooController(FooService fooService) {
        this.fooService = fooService;
    }

    @PostMapping("foos")
    @Transactional
    FooDTO createFoo( @RequestBody FooCreationDTO newFoo ) {
        Foo foo = fooService.createFoo( ... );

        return asDTO(foo);
    }

    @PostMapping("foos/op/delete-bulk")
    @Transactional
    void deleteBulk(@RequestBody List<String> codes) {
        fooService.deleteFoosByCodes(codes);
    }
}

我正在连接某些Retrofit2客户端,

public void FooService.deleteFoosByCodes(List<String> codes) {
  if (codes.isEmpty()) {
      return;
  }
  fooRepository.deleteMatching(codes);
}

@Repository
public interface FooRepository extends JpaRepository<Foo, Long> {

    @Modifying
    @Query("DELETE FROM Foo f WHERE f.code IN :fooCodes")
    void deleteMatching(@Param("fooCodes") List<String> fooCodes);
}

createFoo根据需要接收其交易,

deleteBulk引发异常:

Exception Description: No transaction is currently active; nested exception is javax.persistence.TransactionRequiredException: 
Exception Description: No transaction is currently active
    at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:402)
    at org.springframework.orm.jpa.DefaultJpaDialect.translateExceptionIfPossible(DefaultJpaDialect.java:127)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527)
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
    at com.sun.proxy.$Proxy201.deleteMatching(Unknown Source)
    at ch.cypherk.myapp.server.domain.FooService.deleteFoosByIDs(FooService.java:198)
    at ch.cypherk.myapp.server.api.v1.FooController.deleteBulk(FooController.java:63)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:752)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
  at ...
Caused by: javax.persistence.TransactionRequiredException: 
Exception Description: No transaction is currently active
    at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionWrapper.throwCheckTransactionFailedException(EntityTransactionWrapper.java:89)
    at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionWrapper.checkForTransaction(EntityTransactionWrapper.java:52)
    at org.eclipse.persistence.internal.jpa.EntityManagerImpl.checkForTransaction(EntityManagerImpl.java:2191)
    at org.eclipse.persistence.internal.jpa.QueryImpl.executeUpdate(QueryImpl.java:295)
    at org.springframework.data.jpa.repository.query.JpaQueryExecution$ModifyingExecution.doExecute(JpaQueryExecution.java:256)
    at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:91)
    at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:136)
    at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:125)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:605)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at ...

为什么?!

如果我也将@Transactional放在服务方法上,则调用也有效,但是那里没有事务。

在理解导致此错误的原因方面将提供帮助。

0 个答案:

没有答案