Spring 5 - нет EntityManager с фактической транзакцией, доступной для текущего потока - PullRequest
0 голосов
/ 18 марта 2020

Дорогие все, что я пытался активировать автомат c Управление транзакциями с помощью @EnableTransactionManagement для моих классов конфигурации и @Transactional для моих классов обслуживания. Я также проверил критерии того, что классы должны иметь методы publi c и вызываться извне компонента. К сожалению, я пока не смог найти причину, по которой транзакции не запускаются автоматически.

Сообщение об ошибке: Нет EntityManager с фактической транзакцией, доступной для текущего потока - не может надежно обработать вызов 'merge';

Есть идеи, что я могу попробовать? Заранее спасибо.

Я использую

  • spring.version 5.1.4.RELEASE
  • spring.data.version 2.1.3.RELEASE
  • hibernate.version> 5.4.1.Final
  • java .version 1.8

StackTrace:

[2020-03-18 20:40:28] [http-nio-8080-exec-7] ERROR c.o.c.w.r.c.e.RestResponseEntityExceptionHandler - 500 Status Code
org.springframework.dao.InvalidDataAccessApiUsageException: No EntityManager with actual transaction available for current thread - cannot reliably process 'merge' call; nested exception is javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'merge' call
    at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:402)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:255)
    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:135)
    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.$Proxy136.merge(Unknown Source)
    at com.myapp.persistence.service.question.answer.AnswerServiceImpl.createEntity(AnswerServiceImpl.java:70)
    at com.myapp.persistence.service.question.answer.AnswerServiceImpl.createEntity(AnswerServiceImpl.java:30)
    at com.ontius.core.persistence.service.AbstractService.create(AbstractService.java:294)
    at com.ontius.core.persistence.service.AbstractService.createOrUpdate(AbstractService.java:344)
    at com.myapp.persistence.service.question.answer.AnswerServiceImpl.createOrUpdateAnswer(AnswerServiceImpl.java:130)
    at com.myapp.persistence.service.question.answer.AnswerServiceImpl.createOrUpdateAnswer(AnswerServiceImpl.java:143)
    at com.myapp.rest.controller.rest.UserController.saveAnswers(UserController.java:157)
    at com.myapp.rest.controller.rest.UserController$$FastClassBySpringCGLIB$$7dc31be3.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:69)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
    at com.myapp.rest.controller.rest.UserController$$EnhancerBySpringCGLIB$$bfb4084.saveAnswers(<generated>)
    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.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:215)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:142)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:998)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:901)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:875)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at com.ontius.core.web.security.jwt.filter.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:92)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:96)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:74)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:678)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1598)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)
Caused by: javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'merge' call
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:292)
    at com.sun.proxy.$Proxy116.merge(Unknown Source)
    at com.ontius.core.persistence.repository.AbstractJpaRepository.merge(AbstractJpaRepository.java:34)
    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.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359)
    at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608)
    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 org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
    ... 99 common frames omitted

Классы конфигурации

public class ApplicationInitializer extends AbstractMetricsApplicationInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { ApplicationConfiguration.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return null;
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

}
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {
        "com.myapp.rest.controller",
        "com.myapp.rest.mapper"
})
@Import({
        PersistenceJpaConfiguration.class,
        WebSecurityJwtConfiguration.class,
})
public class ApplicationConfiguration {

}

@Configuration
@EnableJpaRepositories(basePackages = "com.myapp.persistence.repository")
@ComponentScan(basePackages = "com.myapp.persistence")
@EnableTransactionManagement
public class PersistenceJpaConfiguration {

    ...

    @Bean
    public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter) throws Exception {
        LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactory.setDataSource(dataSource);
        entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter);
       entityManagerFactory.setPackagesToScan(this.persistencePropertyContainer.getPackagesToScan());
       entityManagerFactory.setJpaProperties(this.persistencePropertyContainer.getJpaProperties());
        return entityManagerFactory;
    }

    @Bean
    public DataSource dataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(this.persistencePropertyContainer.getDriverClassName());
        dataSource.setUrl(this.persistencePropertyContainer.getDataSourceUrl());
        dataSource.setUsername(this.persistencePropertyContainer.getDatabaseUsername());
        dataSource.setPassword(this.persistencePropertyContainer.getDatabasePassword());
        dataSource.setInitialSize(this.persistencePropertyContainer.getInitialSize());
        dataSource.setMaxTotal(this.persistencePropertyContainer.getMaxTotal());
        dataSource.setMaxIdle(this.persistencePropertyContainer.getMaxIdle());
        return dataSource;
    }

    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {
        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
        jpaVendorAdapter.setDatabase(this.persistencePropertyContainer.getDatabase());
        jpaVendorAdapter.setGenerateDdl(this.persistencePropertyContainer.getGenerateDdl());
        return jpaVendorAdapter;
    }
}
@Configuration
@EnableWebSecurity(debug = true)
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, jsr250Enabled = true)
@EnableTransactionManagement
@ComponentScan(basePackages = {
        "com.myapp.web.security.service",
        "com.myapp.web.security.setup"
})

public class WebSecurityJwtConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    protected void configure(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(this.authenticationProvider());
    }

    protected void configure(HttpSecurity http) throws Exception {
        ((HttpSecurity)((HttpSecurity)((HttpSecurity)http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()).cors().and()).httpBasic().realmName(this.securityPropertyContainer.getRealmName()).and()).csrf().disable();
    }

    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(this.userDetailsService);
        authenticationProvider.setPasswordEncoder(this.passwordEncoder());
        return authenticationProvider;
    }

    @Bean
    public GrantedAuthorityDefaults grantedAuthorityDefaults() {
        return new GrantedAuthorityDefaults(this.getRolePrefix());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderUtility.createPasswordEncoder();
    }

    protected String getRolePrefix() {
        return "";
    }

}

Контроллер

@RestController
@RequestMapping("/api/users")
@CrossOrigin
@Slf4j
public class UserController extends AbstractController<User, Long> {
    ...
    @Autowired
    private AnswerService answerService;
    ...

    @RequestMapping(value = "/data", method = RequestMethod.POST)
    @PreAuthorize("hasRole('ADMIN') or hasRole('USER')")
    @ResponseStatus(HttpStatus.OK)
    public AuthUserData saveAnswers(...) {
        Answer answer = answerService.createOrUpdateAnswer(...);
        ...
    }

}

Сервис

@Service
@Transactional
@Slf4j
public class AnswerServiceImpl extends AbstractService<Answer, Long> implements AnswerService {

  ...

  @Override
    @Transactional
    public Answer createOrUpdateAnswer(Object answerValue, Long userId, Long answerSetId, Long questionGroupId, Long questionId) {
        AnswerSet answerSet = (answerSetId != null) ? answerSetService.findById(answerSetId) : null;
        QuestionGroup questionGroup = (questionGroupId != null) ? questionGroupService.findById(questionGroupId) : null;
        Question question = (questionId != null) ? questionService.findById(questionId) : null;
        return createOrUpdateAnswer(answerValue, userId, answerSet, questionGroup, question);
    }


    @Override
    @Transactional
    public Answer createOrUpdateAnswer(Object answerValue, long userId, AnswerSet answerSet, QuestionGroup questionGroup, Question question) {
        User user = userService.findById(userId);

        verifyObjectNotNull(user, User.class);
        verifyObjectNotNull(question, Question.class);
        verifyObjectNotNull(questionGroup, QuestionGroup.class);

        if(answerSet == null) {
            answerSet = new AnswerSet();
            answerSet.setName(String.format("answer-set-%s-%s-%s", user.getId(), questionGroup.getName(), UUID.randomUUID().toString()));
            answerSet.setQuestionGroup(getPersistedEntity(questionGroup, questionGroupService, QuestionGroup.class));
            answerSet.setUser(user);
        }

        Answer answer = new Answer();
        answer.setUser(user);
        answer.setQuestion(getPersistedEntity(question, questionService, Question.class));
        answer.setAnswerSet(getPersistedEntity(answerSet, answerSetService, AnswerSet.class));

        Answer answerEntity = find(answer);

        if(answerEntity != null) {
            setAnswerValue(answerEntity, question, answerValue);
            return createOrUpdate(answerEntity);
        } else {
            setAnswerValue(answer, question, answerValue);
            return createOrUpdate(answer);
        }
    }


    @Override
    @Transactional
    public Answer createEntity(Answer entity) {
        if(isAnswerExisting(entity, false)) {
            String message = "An answer with the given constraint already exists." + entity.getQuestion().getName();

            log.error(message);
            throw new EntityExistsException(message);
        }

        setAssociations(entity);

        return getRepository().merge(entity);  // <--- Here The Exception get thrown
    }

}

EDIT1: Я попытался с помощью обходного пути избежать самовывоза, но все же это не работает, когда я вызываю внутри класса экземпляр компонента через контекст компонента. Тем не менее транзакция не началась

    @Override
    public Answer createEntity(Answer entity) {
       AnswerService service = context.getBean(AnswerService.class);
       return service.createEntityTransactional(entity);
    }


    @Override
    @Transactional
    public Answer createEntityTransactional(Answer entity) {
        if(isAnswerExisting(entity, false)) {
            String message = "An answer with the given constraint already exists." + entity.getQuestion().getName();

            log.error(message);
            throw new EntityExistsException(message);
        }
        setAssociations(entity);
        return getRepository().merge(entity);
    }

...