Spring + Hibernate: No Hibernate Session bound to

2019-07-26 22:51发布

问题:

I am trying to implement the following: clear some details from DB on SpringSecurity logout handler. The main problem that after trying to get user details from DB I get this error. The rest of code and even the same method work fine in other cases.

public class CurrentUserLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {

    /**
     * 
     */
    @Autowired
    private RequestsService requestsService;

    /**
     * 
     */
    @Autowired
    private OffersService offersService;

    /**
     * 
     */
    @Autowired
    private UsersService usersService;

    /**
     * 
     */
    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
            throws IOException, ServletException {
        if (authentication != null) {
            UserDetailsExtended details = (UserDetailsExtended) authentication.getPrincipal();
            User user = usersService.get(details.getId()); // fails here

            requestsService.unlockAllByBackoffice(user);
            offersService.unlockAllByBackoffice(user);
        }

        setDefaultTargetUrl("/");
        super.onLogoutSuccess(request, response, authentication);
    }
}

Config:

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="packagesToScan" value="com.ejl.butler.object.data" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
                <prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>
                <prop key="hibernate.cache.region.factory_class">${hibernate.cache.region.factory_class}</prop>
           </props>
        </property>
    </bean>
    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

DAO:

public User get(final Long id) {
        Session session = SessionFactoryUtils.getSession(sessionFactory, false);

        return (User) session.get(User.class, id);
    }

Spring security config:

<logout invalidate-session="true" logout-url="/logout" success-handler-ref="logoutSuccessHandler"/>

Exception:

No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
    at org.springframework.orm.hibernate3.SessionFactoryUtils.doGetSession(SessionFactoryUtils.java:356)
    at org.springframework.orm.hibernate3.SessionFactoryUtils.getSession(SessionFactoryUtils.java:202)

@Transactional resolves the problem but I can't understand why? I mean it fails only in this handler in all other calls this method works fine without this annotation!

Thank you in advance!

UPD: My temporary solution is to add @Transactional to whole onLogoutSuccess method.. It works)

回答1:

If you have defined a TransactionManager in your spring context you have to specify @Transactional somewhere in the stack. Otherwise you will get the exception you encountered because you are trying to run a query outside of a transaction.

There are workarounds to this such specifying current_session_context_class in your hibernate configuration to thread or

<property name="current_session_context_class">org.hibernate.context.ThreadLocalSessionContext</property>

but it's not production safe..

The possible values for current_session_context_class are jta, thread and managed. Further to that, jta and thread are supported by hibernate out of box. thread context is used in most stand alone hibernate apps or those based on light weight frameworks like Spring and jta is used in Java EE environments.

Also try sessionFactory.getCurrentSession() instead of SessionFactoryUtils.getSession().