Java HibernateException:无法为当前线程获取事务同步会话

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26562787/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 02:48:35  来源:igfitidea点击:

HibernateException: Couldn't obtain transaction-synchronized Session for current thread

javaspringhibernateormtransactions

提问by dtrunk

I'm getting the following exception when trying to use my @Serviceannotated classes:

尝试使用带@Service注释的类时出现以下异常:

org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
    at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134) ~[spring-orm-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014) ~[hibernate-core-4.3.6.Final.jar:4.3.6.Final]
    at webapp.base.repository.GenericDaoImpl.saveOrUpdate(GenericDaoImpl.java:59) ~[base-0.0.1-SNAPSHOT-classes.jar:na]
    at com.example.repository.PageViewDaoImpl.saveOrUpdate(PageViewDaoImpl.java:19) ~[site-0.0.1-SNAPSHOT.jar:na]
    at com.example.repository.PageViewDaoImpl.saveOrUpdate(PageViewDaoImpl.java:14) ~[site-0.0.1-SNAPSHOT.jar:na]
    at com.example.service.PageViewServiceImpl.savePageView(PageViewServiceImpl.java:26) ~[site-0.0.1-SNAPSHOT.jar:na]
    at com.example.interceptor.PageViewInterceptor.preHandle(PageViewInterceptor.java:29) ~[site-0.0.1-SNAPSHOT.jar:na]
    at org.springframework.web.servlet.HandlerExecutionChain.applyPreHandle(HandlerExecutionChain.java:130) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:620) [servlet-api-3.0.jar:na]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) [servlet-api-3.0.jar:na]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303) [tomcat-catalina-7.0.52.jar:7.0.52]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [tomcat-catalina-7.0.52.jar:7.0.52]
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748) [tomcat-catalina-7.0.52.jar:7.0.52]
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:488) [tomcat-catalina-7.0.52.jar:7.0.52]
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:411) [tomcat-catalina-7.0.52.jar:7.0.52]
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:338) [tomcat-catalina-7.0.52.jar:7.0.52]
    at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:466) [tomcat-catalina-7.0.52.jar:7.0.52]
    at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:337) [tomcat-catalina-7.0.52.jar:7.0.52]
    at org.apache.catalina.core.StandardHostValve.throwable(StandardHostValve.java:427) [tomcat-catalina-7.0.52.jar:7.0.52]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:200) [tomcat-catalina-7.0.52.jar:7.0.52]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) [tomcat-catalina-7.0.52.jar:7.0.52]
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950) [tomcat-catalina-7.0.52.jar:7.0.52]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) [tomcat-catalina-7.0.52.jar:7.0.52]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) [tomcat-catalina-7.0.52.jar:7.0.52]
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040) [tomcat-coyote-7.0.52.jar:7.0.52]
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607) [tomcat-coyote-7.0.52.jar:7.0.52]
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:313) [tomcat-coyote-7.0.52.jar:7.0.52]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_65]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_65]
    at java.lang.Thread.run(Thread.java:745) [na:1.7.0_65]

The way I initialize my application is complicated so I need to provide a link to the full base code to get additional information: https://github.com/dtrunk90/webapp-base. I'm using this as a maven overlay.

我初始化应用程序的方式很复杂,因此我需要提供指向完整基本代码的链接以获取更多信息:https: //github.com/dtrunk90/webapp-base。我将它用作 Maven 覆盖。

And here is the necessary code:

这是必要的代码:

Initializer (from webapp-base):

初始化程序(来自 webapp-base):

public abstract class AbstractWebApplicationInitializer extends AbstractDispatcherServletInitializer {
    @Override
    protected String[] getServletMappings() {
        return new String[] {"/*"};
    }

    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
        encodingFilter.setEncoding("UTF-8");
        encodingFilter.setForceEncoding(true);
        return new Filter[] {encodingFilter};
    }

    @Override
    protected WebApplicationContext createRootApplicationContext() {
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();

        ConfigurableEnvironment environment = rootContext.getEnvironment();
        environment.setDefaultProfiles("production");

        PropertyUtil propertyUtil = PropertyUtil.getInstance(environment.getActiveProfiles());
        String[] basePackages = propertyUtil.getPropertySplitTrimmed("webapp", "basePackages");
        rootContext.scan(basePackages);

        return rootContext;
    }

    @Override
    protected WebApplicationContext createServletApplicationContext() {
        return new AnnotationConfigWebApplicationContext();
    }
}

Initializer (from my webapp):

初始化程序(来自我的 webapp):

public class WebApplicationInitializer extends AbstractWebApplicationInitializer {
}

@Configuration(from webapp-base):

@Configuration(来自 webapp-base):

@Configuration
@EnableTransactionManagement
public class TransactionConfiguration {
    @Bean
    public DataSource dataSource() throws IOException {
        Properties conProps = PropertyUtil.getInstance().getProperties("jdbc");
        if (conProps.containsKey("url")) {
            DriverManagerDataSource dataSource = new DriverManagerDataSource(conProps.getProperty("url"), conProps);
            dataSource.setDriverClassName(conProps.getProperty("driverClassName"));
            return dataSource;
        }

        return null;
    }

    @Bean
    public SessionFactory sessionFactory() throws IOException {
        DataSource dataSource = dataSource();
        if (dataSource != null) {
            LocalSessionFactoryBuilder sessionBuilder = new LocalSessionFactoryBuilder(dataSource);
            sessionBuilder.scanPackages(PropertyUtil.getInstance().getPropertySplitTrimmed("hibernate", "packagesToScan"));
            sessionBuilder.addProperties(PropertyUtil.getInstance().getProperties("hibernate"));
            return sessionBuilder.buildSessionFactory();
        }

        return null;
    }

    @Bean
    public HibernateTransactionManager transactionManager() throws IOException {
        SessionFactory sessionFactory = sessionFactory();
        if (sessionFactory == null) {
            return null;
        }

        return new HibernateTransactionManager(sessionFactory);
    }
}

@Configuration(from my webapp):

@Configuration(来自我的网络应用程序):

@Configuration
public class MainConfiguration extends WebMvcConfigurerAdapter {
    @Autowired
    private PageViewInterceptor pageViewInterceptor; // Is annotated with @Component

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(pageViewInterceptor);
    }
}

@Service:

@Service

@Service
public class PageViewServiceImpl implements PageViewService {
    @Autowired
    private PageViewDao pageViewDao;

    @Override
    public void savePageView(long ip, String visitPage, String userAgent) {
        PageView obj = new PageView();
        obj.setVisitDate(new Date());
        obj.setUserAgent(userAgent);
        obj.setPage(visitPage);
        obj.setIp(ip);

        pageViewDao.saveOrUpdate(obj);
    }
}

@Repository:

@Repository

@Repository
public class PageViewDaoImpl extends GenericDaoImpl<PageView, Long> implements PageViewDao {
    @Override
    public void saveOrUpdate(PageView obj) {
        if (!obj.isBot()) {
            super.saveOrUpdate(obj);
        }
    }
}

public abstract class GenericDaoImpl<T extends Identifier<I>, I extends Serializable> implements GenericDao<T, I> {
    @Autowired
    private SessionFactory sessionFactory;

    public SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            throw new IllegalStateException("SessionFactory has not been set on DAO before usage");
        }

        return sessionFactory;
    }

    @Transactional
    public void saveOrUpdate(T obj) {
        getSessionFactory().getCurrentSession().saveOrUpdate(obj);
    }
}

Then I'm autowiring PageViewServiceand use its methods.

然后我自动装配PageViewService并使用它的方法。

I know there are several questions with the same problem here but I already checked anything:

我知道这里有几个问题有同样的问题,但我已经检查过任何东西:

Could not obtain transaction-synchronized Session for current thread

无法获取当前线程的事务同步会话

  • @EnableTransactionManagementis provided
  • Services wil be autowired as interfaces
  • @EnableTransactionManagement提供
  • 服务将自动装配为接口

HibernateException: Could not obtain transaction-synchronized Session for current thread

HibernateException:无法获取当前线程的事务同步会话

  • Checked for @Transactionaleverywhere I use getSessionFactory().getCurrentSession()
  • 检查@Transactional我使用的所有地方getSessionFactory().getCurrentSession()

Spring Hibernate - Could not obtain transaction-synchronized Session for current thread

Spring Hibernate - 无法为当前线程获取事务同步会话

  • @EnableTransactionManagementis provided
  • Checked for @Transactionaleverywhere I use getSessionFactory().getCurrentSession()
  • @EnableTransactionManagement提供
  • 检查@Transactional我使用的所有地方getSessionFactory().getCurrentSession()

org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread

org.hibernate.HibernateException: 无法获取当前线程的事务同步会话

  • There's no helpful answer. I want component scanning for all my components, not only controller
  • 没有有用的答案。我想要对所有组件进行组件扫描,而不仅仅是控制器

采纳答案by Vlad Mihalcea

Looking at your log I can instantly tell that your transaction settings are wrongly set. That's because there's no TransactionInterceptorcall in your stack trace.

查看您的日志,我可以立即看出您的交易设置设置错误。那是因为TransactionInterceptor您的堆栈跟踪中没有调用。

The TransactionInterceptoris called by your Spring Service proxies when your web controllers call the actual Service methods.

TransactionInterceptor当你的web控制器调用实际的服务方法是通过你的Spring服务代理调用。

  1. Make sure you use the Spring hibernate4 classes:

    org.springframework.orm.hibernate4.HibernateTransactionManager
    
  2. Don't override @Transactionalmethods, but use a template patterns instead.

  3. Try using JPATransactionManagerinstead so you can inject the current EntityManagerwith the @PersistenceContextannotation instead. This is much more elegant than calling sessionFactory.getCurrentSession()in every DAO method.

  1. 确保使用 Spring hibernate4 类:

    org.springframework.orm.hibernate4.HibernateTransactionManager
    
  2. 不要覆盖@Transactional方法,而是使用模板模式。

  3. 尝试使用,JPATransactionManager以便您可以EntityManager使用@PersistenceContext注释注入电流。这比调用sessionFactory.getCurrentSession()每个 DAO 方法要优雅得多。

回答by Manuel Jordan

One

You must use @Transactionalfor @Serviceand @Repository. It lets Spring apply and create proxies with Transaction support.

您必须使用@Transactionalfor@Service@Repository。它让 Spring 应用和创建具有事务支持的代理。

In your code your @Serviceclass has no the @Transacionaleither in class level or method level

在您的代码中,您的@Service类没有@Transacional类级别或方法级别

Second

第二

Where is the class that implements WebApplicationInitializer? I see you are extending a class.. Anyway My Point is, where is something like the following:

实现的类在哪里WebApplicationInitializer?我看到你正在扩展一个类。无论如何,我的观点是,如下所示:

@Override
public void onStartup(ServletContext container) {
    // Create the 'root' Spring application context
    AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
    rootContext.register(CentralServerConfigurationEntryPoint.class);

    // Manage the lifecycle of the root application context
    container.addListener(new ContextLoaderListener(rootContext));

    // Create the dispatcher servlet's Spring application context
    AnnotationConfigWebApplicationContext dispatcherServlet = new AnnotationConfigWebApplicationContext();
    dispatcherServlet.register(CentralWebConfigurationEntryPoint.class);

    // Register and map the dispatcher servlet
    ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherServlet));
    dispatcher.setLoadOnStartup(1);
    dispatcher.addMapping("/");

}

Where CentralServerConfigurationEntryPoint.classmust only scan components that must work in the server side (@Service, @Repository, @Configurationfor Transaction, Hibernate, DataSource etc)

Where CentralServerConfigurationEntryPoint.classmust only scan components that must work in server side ( @Service, @Repository, @Configurationfor Transaction, Hibernate, DataSource etc)

Where CentralWebConfigurationEntryPointmust only scan components that must work in the client/web side (@Controller, @Configurationfor Formatters, Tiles, Converters etc)

CentralWebConfigurationEntryPoint只能扫描组件,在客户端/网络端必须工作(@Controller@Configuration用于格式化程序,瓷砖,转换器等)

I dont understand your code about

我不明白你的代码

@Override
protected WebApplicationContext createRootApplicationContext() {
    AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();

    ConfigurableEnvironment environment = rootContext.getEnvironment();
    environment.setDefaultProfiles("production");

    PropertyUtil propertyUtil = PropertyUtil.getInstance(environment.getActiveProfiles());
    String[] basePackages = propertyUtil.getPropertySplitTrimmed("webapp", "basePackages");
    rootContext.scan(basePackages);

    return rootContext;
}

@Override
protected WebApplicationContext createServletApplicationContext() {
    return new AnnotationConfigWebApplicationContext();
}

My point is: you musthave two AnnotationConfigWebApplicationContextone for the server and web side.

我的观点是:服务器端和 Web 端必须有两个AnnotationConfigWebApplicationContext

回答by Kuldeep Singh

Very short answer for this questions id, you just need to use @Transactional with your dao class, mark your configuration class as @EnableTransactionManagement and create a bean

这个问题的答案非常简短,你只需要在你的 dao 类中使用 @Transactional,将你的配置类标记为 @EnableTransactionManagement 并创建一个 bean

**@Bean
public PlatformTransactionManager transactionManager() {
    DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource());
    return transactionManager;
}**

Here, if you see the code example available in EnableTransactionManagement annotation, it suggest to use DataSourceTransactionManager instead of HibernateTransactionManager.

在这里,如果您在 EnableTransactionManagement 注释中看到可用的代码示例,则建议使用 DataSourceTransactionManager 而不是 HibernateTransactionManager。