Дорогие все, что я пытался активировать автомат 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);
}