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

后端 未结 4 1190
无人共我
无人共我 2020-12-01 16:40

I\'m getting the following exception when trying to use my @Service annotated classes:

org.hibernate.HibernateException: Could not obtain transa         


        
相关标签:
4条回答
  • 2020-12-01 17:00

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

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

    1. Make sure you use the Spring hibernate4 classes:

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

    3. Try using JPATransactionManager instead so you can inject the current EntityManager with the @PersistenceContext annotation instead. This is much more elegant than calling sessionFactory.getCurrentSession() in every DAO method.

    0 讨论(0)
  • 2020-12-01 17:03
    @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(SessionFactory sessionFactory)
    { 
        HibernateTransactionManager htm = new HibernateTransactionManager();
        htm.setTransactionSynchronization(HibernateTransactionManager.SYNCHRONIZATION_ALWAYS);
        htm.setDataSource(dataSource());
        htm.setSessionFactory(sessionFactory);
        return htm;
    }
    
        You just need to add
        -------------------------------
        htm.setTransactionSynchronization(HibernateTransactionManager.SYNCHRONIZATION_ALWAYS);
        -------------------------------
        I used dependencies 
        -----------------------------------
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.2.2.Final</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>5.0.1.RELEASE</version>
    </dependency>
    
    0 讨论(0)
  • 2020-12-01 17:23

    One

    You must use @Transactional for @Service and @Repository. It lets Spring apply and create proxies with Transaction support.

    In your code your @Service class has no the @Transacional either in class level or method level

    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:

    @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.class must only scan components that must work in the server side (@Service, @Repository, @Configuration for Transaction, Hibernate, DataSource etc)

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

    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 must have two AnnotationConfigWebApplicationContext one for the server and web side.

    0 讨论(0)
  • 2020-12-01 17:27

    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

    **@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.

    0 讨论(0)
提交回复
热议问题