Announcement Announcement Module
Collapse
No announcement yet.
EnableTransactionManagement / Transactional: No Session found for current thread Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • EnableTransactionManagement / Transactional: No Session found for current thread

    I know, that this question had been asked numerous times, but anyway the given answers didn't help me.

    I get the symptomatic error "No Session found for current thread" when calling a service method which is annotated with @Transactional although @EnableTransactionManagement is set.

    I had the same problem a year before and ended up with a xml-Configuration. Maybe you can help me.
    My setting is as followed:

    Code:
    public class LifepulseWebAppinitializer extends	AbstractAnnotationConfigDispatcherServletInitializer {
    
    	@Override
    	protected Class<?>[] getRootConfigClasses() {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	protected Class<?>[] getServletConfigClasses() {
    		return new Class[] { LifepulseWebConfig.class };
    	}
    
    	@Override
    	protected String[] getServletMappings() {
    		return new String[] { "/" };
    	}
    }
    As you can see LifepulseWebConfig is given as configuration and it looks like this:
    Code:
    package com.lifepulse.config;
    
    @Configuration
    @EnableWebMvc
    @ComponentScan(value= {"com.lifepulse.controllers"})
    @EnableTransactionManagement(proxyTargetClass=true, mode=AdviceMode.PROXY)
    public class LifepulseWebConfig extends WebMvcConfigurerAdapter implements TransactionManagementConfigurer {
    	@Autowired
    	ApplicationContext context;	
    	
    	
    	@Bean
    	ViewResolver viewResolver(){
    		InternalResourceViewResolver resolver = new InternalResourceViewResolver();
    		resolver.setSuffix(".jsp");
    		return resolver;
    	}
    	
    	@Bean
    	MainService mainService(){
    		return new MainServiceImpl();
    	}
    	
    	@Bean(name="databaseUrl")
    	public String getDatabaseUrl(){
    		return "jdbc:mysql://localhost/db_name";
    	}
    	
    	@Bean(name="sessionFactoryProperties")
    	public Properties getSessionFactoryProperties(){
    		Properties props = new Properties();
    		props.put("hibernate.dialect", MySQL5InnoDBDialect.class.getName());
    		props.put("hibernate.hbm2ddl.auto", "create-drop");
    		props.put("hibernate.show_sql", "true");
    		props.put("hibernate.format_sql", "true");
    			
    		return props;
    	}
    	
    
    	@SuppressWarnings("unchecked")
    	private static final Class<? extends Serializable>[] ANNOTATED_CLASSES=new Class[]{
    		Melder.class
    	};
    	
    	
    
    	private static Class<? extends Serializable>[] getAnnotatedClasses(){
    		return ANNOTATED_CLASSES;
    	}
    	
    
    	@Bean
    	public DataSource dataSource() {
    		DriverManagerDataSource dataSource = new DriverManagerDataSource();
    		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    		dataSource.setUrl(getDatabaseUrl());
    		dataSource.setUsername("bla");
    		dataSource.setPassword("foo");
    		return dataSource;
    	}
    
    	@Bean
    	public LocalSessionFactoryBean sessionFactory() {
    		
    		LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
    		factory.setAnnotatedClasses(getAnnotatedClasses());		
    		factory.setHibernateProperties(getSessionFactoryProperties());
    		factory.setDataSource(dataSource());
    		return factory;
    	}
    
    	@Bean()
    	public GenericDao genericDao() {
    		return new HibernateDaoImpl();
    	}
    	
    
    	@Override
    	public PlatformTransactionManager annotationDrivenTransactionManager() {
    		System.out.println("1: "+txManager());
    		return txManager();
    	}
    
    	@Bean
    	PlatformTransactionManager txManager(){
    		HibernateTransactionManager htm = new HibernateTransactionManager(sessionFactory().getObject());
    		System.out.println("2: "+htm);
    		return htm;
    	}
    	
    	@Bean(name="transactionInterceptor")
    	TransactionInterceptor transactionInterceptor(){
    		Properties prop = new Properties();
    		prop.put("save", "PROPAGATION_REQUIRED");
    		TransactionInterceptor ti = new TransactionInterceptor(txManager(), prop);
    		return ti;
    	}
    	
    }

    The @Bean MainService is annotated with @Transactional as can be seen here:

    Code:
    package com.lifepulse.services.impl;
    
    @Transactional(readOnly=false, rollbackFor={ServiceException.class})
    public class MainServiceImpl implements MainService {
    
    	@Autowired private GenericDao dao;
    	
    	@Override
    	public void createMelder(Melder melder) throws ServiceException {
    		dao.create(melder);	
    	}
    
    }
    And this is the controller where the service-Method is called:
    Code:
    @Controller()
    @RequestMapping(value="/")
    public class MainController {
    
    	@Autowired private MainService mainService;
    	
    	private static int counter = 0;
    
    	@RequestMapping(value="")
    	public String index(){
    		Melder m = new Melder();
    		m.setAppName("testName"+(counter++));
    		m.setValue("A Value");
    		try {
    			mainService.createMelder(m);
    		} catch (ServiceException e) {
    			e.printStackTrace();
    		}
    		
    		
    		return "index";
    	}
    	
    }

    And here the StackTrace:

    Code:
    HTTP ERROR 500
    
    Problem accessing /lifepulse/. Reason:
    
        No Session found for current thread
    
    Caused by:
    org.hibernate.HibernateException: No Session found for current thread
    	at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
    	at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:978)
    	at com.ansiworks.persistence.HibernateDaoImpl.create(HibernateDaoImpl.java:57)
    	at com.ansiworks.lifepulse.services.impl.MainServiceImpl.createMelder(MainServiceImpl.java:18)
    	at com.ansiworks.lifepulse.controllers.MainController.index(MainController.java:28)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:601)
    	at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219)
    	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
    	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:746)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:687)
    	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
    	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:915)
    	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:811)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:735)
    	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:796)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
    	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:669)
    	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:445)
    	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:138)
    	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:564)
    	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:213)
    	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1054)
    	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:372)
    	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:175)
    	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:988)
    	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:136)
    	at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:258)
    	at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:109)
    	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
    	at org.eclipse.jetty.server.Server.handle(Server.java:410)
    	at org.eclipse.jetty.server.HttpChannel.run(HttpChannel.java:245)
    	at org.eclipse.jetty.server.HttpConnection$1.run(HttpConnection.java:75)
    	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:597)
    	at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:528)
    	at java.lang.Thread.run(Thread.java:722)

    The application works fine except the transaction-manager stuff.
    CGLIB is loaded.

    Can anybody help me out?

    Greetings tarator

  • #2
    Now I tried it again and I found out what was wrong: The beans regarding the transactionmanager must be loaded in a seperate WebApplicationContext (can somebody confirm this!?)

    My configuration now looks like this:

    I seperated my Web App Config into a "PersistenceConfig" and a "LifepulseWebCnfig":

    Code:
    package com.lifepulse.config;
    
    @Configuration
    public class PersistenceConfig{ 
    	
    	/** The Application Context. */
    	@Autowired
    	ApplicationContext context;
    	
    	@Bean(name="databaseUrl")
    	public String getDatabaseUrl(){
    		return "jdbc:mysql://localhost/lifepulse";
    	}
    
    	@Bean(name="sessionFactoryProperties")
    	public Properties getSessionFactoryProperties(){
    		Properties props = new Properties();
    		props.put("hibernate.dialect", MySQL5InnoDBDialect.class.getName());
    		props.put("hibernate.hbm2ddl.auto", "create-drop");
    		props.put("hibernate.show_sql", "true");		
    		props.put("hibernate.format_sql", "true");	
    		return props;
    	}
    	
    	
    	/** The Constant ANNOTATED_CLASSES. */
    	@SuppressWarnings("unchecked")
    	private static final Class<? extends Serializable>[] ANNOTATED_CLASSES=new Class[]{
    		Melder.class
    	};
    	
    	private static Class<? extends Serializable>[] getAnnotatedClasses(){
    		return ANNOTATED_CLASSES;
    	}
    	
    	
    	@Bean
    	public DataSource dataSource() {
    		DriverManagerDataSource dataSource = new DriverManagerDataSource();
    		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    		dataSource.setUrl(getDatabaseUrl());
    		dataSource.setUsername("tarator");
    		dataSource.setPassword("tarator");
    		return dataSource;
    	}
    
    	@Bean
    	public LocalSessionFactoryBean sessionFactory() {
    		LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
    		factory.setAnnotatedClasses(getAnnotatedClasses());		
    		factory.setHibernateProperties(getSessionFactoryProperties());
    		factory.setDataSource(dataSource());
    		return factory;
    	}
    
    	@Bean()
    	public GenericDao genericDao() {
    		return new HibernateDaoImpl();
    	}
    
    	@Bean
    	PlatformTransactionManager txManager(){
    		HibernateTransactionManager htm = new HibernateTransactionManager(sessionFactory().getObject());
    		return htm;
    	}
    	
    	@Bean(name="transactionInterceptor")
    	TransactionInterceptor transactionInterceptor(){
    		Properties prop = new Properties();
    		prop.put("save", "PROPAGATION_REQUIRED");
    		TransactionInterceptor ti = new TransactionInterceptor(txManager(), prop);
    		return ti;
    	}
    }
    Code:
    package com.lifepulse.config;
    
    @Configuration
    @EnableWebMvc
    @ComponentScan(value= {"com.lifepulse.controllers", "com.lifepulse.services"})
    @EnableTransactionManagement(proxyTargetClass=true, mode=AdviceMode.PROXY)
    public class LifepulseWebConfig extends WebMvcConfigurerAdapter{
    
    	@Autowired
    	ApplicationContext context;
    
    	@Bean
    	ViewResolver viewResolver(){
    		InternalResourceViewResolver resolver = new InternalResourceViewResolver();
    		resolver.setSuffix(".jsp");
    		return resolver;
    	}
    	
    	@Bean
    	MainService mainService(){
    		return new MainServiceImpl();
    	}
    
    }
    First I tried to import my PersistenceConfig into my LifepulseWebConfig with the @Import annotation, but this doesn't work:
    Code:
    @Configuration
    @EnableWebMvc
    @ComponentScan(value= {"com.lifepulse.controllers", "com.lifepulse.services"})
    @EnableTransactionManagement(proxyTargetClass=true, mode=AdviceMode.PROXY)
    
    // This imports the beans of PersitstenceConfig, but the transactionManager doesn't work anyway...
    @Import(PersistenceConfig.class)
    public class LifepulseWebConfig extends WebMvcConfigurerAdapter{
    ....
    }
    The trick was to add the PersistenceConfig seperately into the ServletConfigClasses THIS WORKS
    Code:
    package com.lifepulse;
    
    public class LifepulseServletinitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    
    	@Override
    	protected Class<?>[] getRootConfigClasses() {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	protected Class<?>[] getServletConfigClasses() {
                    //Important: The PersistenceConfig with the transactionmanager must be given as a seperate class here!
    		return new Class[] { PersistenceConfig.class, LifepulseWebConfig.class };
    	}
    
    	@Override
    	protected String[] getServletMappings() {
    		return new String[] { "/" };
    	}
    }
    No my - with @Transactional annotated - classes really work with the transactionmanager.

    My questions:

    * Did I create two different Spring IoC container's with my configuration?
    * Is it mandatory for the transaction-manager to be created in a different Container than the with @Transactional Annotated classes?

    Comment


    • #3
      * Did I create two different Spring IoC container's with my configuration?
      No... A single one with multiple sources for the bean definitions.

      * Is it mandatory for the transaction-manager to be created in a different Container than the with @Transactional Annotated classes?
      No you still have a single container in your configuration...

      Also your configuration is flawed as you are both scanning your classes and constructing a bean which basically leads to 2 bean instances (at least for your MainServiceImpl).

      I'm also wondering why are you configuring a TransactionInterceptor this basically overrides the one which is registered by @EnableTransactionManager next to that you are using @Transactional so your current one is basically interrupting proper tx management.

      Comment


      • #4
        First: thanks for your quick answer!

        Originally posted by Marten Deinum View Post
        No... A single one with multiple sources for the bean definitions.


        No you still have a single container in your configuration...
        But why then it doesn't work, when I simpy import my PersistenceConfig into the LifepulseWebConfig with @Import ?


        Originally posted by Marten Deinum View Post
        Also your configuration is flawed as you are both scanning your classes and constructing a bean which basically leads to 2 bean instances (at least for your MainServiceImpl).
        I removed the service package from @ComponentScan. I haven't annotated my service classes/interfaces with @Service, so I just had one instance of my service. The scan was unnecessary anyway....

        Originally posted by Marten Deinum View Post
        I'm also wondering why are you configuring a TransactionInterceptor this basically overrides the one which is registered by @EnableTransactionManager next to that you are using @Transactional so your current one is basically interrupting proper tx management.
        True. I removed it...

        Like mentioned I still doesn't know why it didn't work with @Import...

        Greetings George.

        Comment

        Working...
        X