Spring + Hibernate: No Hibernate Session bound to thread - java

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)

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().

Related

saveorupdate call in Junit test case throws no transaction in progress error

Premise
I have a Spring 5.1.5 project with Hibernate 5.4.1
The compilation goes through fine but while running test cases for a particular package I see multiple tests failing. All with the same error:
javax.persistence.TransactionRequiredException: no transaction is in progress at com.project.server.package.dao.impl.SomeDAOImplTest.someTest(SomeDAOImplTest.java:54)
The Problem
Now I know that Hibernate 5 enforces the check for a transaction and it doesn't find one here and throws an exception. My question is why does it do that given I have transactions initialized via spring context.
My test case:
#ContextConfiguration({ "classpath:/spring/applicationContext-package-dao--test.xml" })
public class SomeDAOImplTest extends AbstractDAOTest {
#Autowired
private SomeDAO someDAO;
private className obj;
#Before
public void setUp() {
obj = new ClassName();
obj.setId(3);
someDAO.saveOrUpdate(obj);
}
My applicationContext-package-dao--test.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="classpath:/spring/applicationContext-persistence-datasource-test.xml" />
<import resource="classpath:/spring/applicationContext-package-dao.xml" />
</beans>
The imported context applicationContext-persistence-datasource-test.xml has a bean txProxyTemplate as below:
<beans>
.
.//other beans
.
<bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager" />
</bean>
<bean id="transactionManager" class="com.desktone.transaction.DtResourcelessTransactionManager" />
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
.
.//other beans
.
</beans>
The other applicationContext-package-dao.xml has the bean definition for SomeDAO which has txProxyTemplate as it's parent.
<bean id="SomeDAO" parent="txProxyTemplate">
<property name="target">
<bean class="com.project.server.package.dao.impl.SomeDAOImpl">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</property>
<property name="transactionAttributes">
<props>
<prop key="saveOrUpdate">PROPAGATION_REQUIRED</prop>
<prop key="delete">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
</props>
</property>
</bean>
The saveorupdate call from SomeDAOImplTest calls SomeDAOImpl whose spring context config is applicationContext-package-dao.xml and has the Hibernate saveorupdate() call.
Things I have Tried:
Manually adding #Transactional tag to SomeDAOImplTest. (still throws no tx error)
Experimenting with PROPAGATION.REQUIRES_NEW (still throws no tx error) & PROPAGATION.MANDATORY(says marked mandatory but no tx).
Made sure the autowire is initialzing the bean.
Primary Suspicion
I suspect somehow the someDAO bean is initialized but txProxyTemplate bean isn't, so no transactionManager is in place. However, I have found no clues to coroborate this.
For me, this was happening because of a very fundamental issue. I'll explain the issue and the fix will be intuitive to everyone afterward.
When a Spring application runs all the beans are loaded in a single/global context. So even if some spring bean configuration depends on a transaction bean(for me it was txProxyTemplate) which isn't present in the same package at runtime it will be able to access it.
However, that's not true for a test case. My tests were reporting no transaction in progress since they couldn't load the txProxyTemplate and actually start a transaction. So my tests never ran in a transaction and I didn't know any better until I upgraded to Hibernate 5 and they put a hard constraint on this.
As you might have guessed defining the txProxyTemplate in the same spring config helped me work past this issue.
Good learning.

Intercepting query result using hibernate interceptor

I want to interceptor to the data fetch from database using hibernate that if in my data, particular field is present then get the value and check if that value is applicable to the user who queried it.
My application uses spring mvc with hibernate. I have configured an interceptor at session factory level.
class AuditInterceptor extends EmptyInterceptor {
#Override
public Object instantiate(String entityName, EntityMode entityMode, Serializable id) {
System.out.println("******************************* instantiated ****************************");
return null;
}
#Override
public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
System.out.println("******************************* on load ****************************");
return true;
}
}
In my spring-dao.xml
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="c3p0DataSource" />
<property name="packagesToScan">
...
</property>
<property name="hibernateProperties">
....
</property>
<property name="entityInterceptor">
<bean class="com.hibernate.AuditInterceptor" />
</property>
</bean>
I want whenever query.list() excutes it should be able to intercept data using above inteceptor.
Now, it is calling my interceptor when my application starts. I am not able to get data for validation.(I want to perform validation in interceptor)

Why is my initialisation of collection not working?

I have a service class annotated with #Transactional calling a DAO layer method to return an object with a collection on it lazily loaded. When I then try and initialize this collection in the service layer using Hibernate.inititialize(..), hibernate doesn't load the collection. The DAO is configured to use entity manager and the object class is annotated with JPA annotations. I have the following spring application context..
<beans xmlns="http://www.springframework.org/schema/beans"...">
<orcl:pooling-datasource id="dataSource" url="..." username="..." password="..."/>
<context:annotation-config/>
<!-- Hibernate entity manager -->
<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="org.gmp.webapp.model" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEmf" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean id="dao" class="org.gmp.webapp.dao.impl.HibDAOImpl" />
</beans>
My DAO interface and implementaionn...
package org.gmp.webapp.dao;
import java.util.List;
import org.gmp.webapp.model.Crime;
public interface DAO {
public Crime getCrime(String crimeNo);
}
import org.gmp.webapp.dao.DAO;
import org.gmp.webapp.model.Crime;
public class HibDAOImpl implements DAO {
#PersistenceContext
protected EntityManager em;
public Crime getCrime(String crimeNo) {
return this.em.find(Crime.class, crimeNo);
}
}
My object looks something like this..
#Entity
#Table(name="CRIME_TABLE")
public class Crime {
#Id
#Column(name = "CRIME_NO")
private String crimeNo;
#OneToMany
#JoinColumn(name="PER_CRIME_NO", referencedColumnName="CRIME_NO")
private List<PersonCrimeLink> personLinks;
....
public List<PersonCrimeLink> getPersonLinks() {
return personLinks;
}
}
The service class is annotated with transactional (spring) so I thought as the call to the DAO and the initialize were in the same transaction, this should work.
My service..
#Service
#Transactional(readOnly=true)
public class CrimeServiceImpl implements CrimeService {
#Autowired private CrimeDAO crimeDAO;
public Crime getCrime(String crimeNo) {
Crime crime = crimeDAO.getCrime(crimeNo);
Hibernate.initialize(crime.getPersonLinks());
return crime;
}
}
The collection is loaded when I run a test of the DAO method, when making a call to the getter for the collection. I have annotated the test method with #Transactional. The personLinks object is omitted but like I say it returns the records in the test. I think I am not understanding the transaction manager I am using as this process worked when I was using session factory and HibernateTransactionManager.
Many Thanks in advance for any guidance on this.
Just a quick tip on this, as you decided to use the JPA's EntityManagerFactory instead of the Hibernate's SessionFactory as your orm API, then i would stick to that API on other layers of the application.
That is, using the EntityManager to get the data and then switch to using the implementation API (Hibernate.initialize) is not a consistent / maintainable approach.
Like you said in the post, if you stick to the JPA specification, which is initializing collection once it is accessed for the first time then you do not get any errors and the list is loaded:
The LAZY strategy is a hint to the persistence provider runtime that
data should be fetched lazily when it is first accessed
So as of JPA specification, you only need to do this:
public Crime getCrime(String crimeNo) {
Crime crime = crimeDAO.getCrime(crimeNo);
crime.getPersonLinks().size(); // any access method
return crime;
}

Why does not "#Transactional(propagation = propagation.NEVER)" work?

In the Spring docs, for NEVER propagation:
Execute non-transactionally, throw an exception if a transaction
exists.
I wanted to try like following:
#Transactional(propagation = Propagation.NEVER)
public void getDeps(long ID) {
System.out.println(databaseImp.getDepartmentByID(ID));
}
#Transactional(propagation = Propagation.REQUIRED)
public void allProcessOnDB_second(long ID) {
getDeps(ID);
operation(ID);
}
#Transactional
public void operation(long id){
System.out.println(databaseImp.getDepartmentByID(id));
}
Well, it is not important what code wants to do.
I use the #Transactional(propagation = Propagation.NEVER) and I use this method in any transactional method but it doesn't work. I mean it must throw an exception, but it doesn't.
My Spring meta configuration file (XML) contains the following:
<context:annotation-config></context:annotation-config>
<context:component-scan base-package="database.transactionmanagement"/>
<tx:annotation-driven transaction-manager="transactionManager" mode="aspectj"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg name="dataSource" ref="datasource2"/>
</bean>
<bean id="datasource2" class="org.apache.tomcat.dbcp.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/hr"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</bean>
Thanks for your answers.
#Transactional annotations only apply to the Spring proxy objects. For example, if you call allProcessOnDB_second() from some spring bean which injects your service like this
#Autowired
private MyService myService;
...
myService.allProcessOnDB_second();
then myService is Spring proxy, and its #Transactional(propagation = Propagation.REQUIRED) is applied. If you were to call myService.getDeps(id) then #Transactional(propagation = Propagation.NEVER) would be applied.
But when you call the first method, and then second method from it, then second method isn't called through Spring proxy but rather directly, so its transactional configuration is ignored.
Spring transactions are proxy-based. That exception would be thrown if a bean A called another bean B, because the transactional aspect would intercept the call and throw the exception. But here, you're calling another method in the same object, and the transactional proxy is thus out of the picture.

Problem with spring aop. How to be sure that interceptor is invoked after commit?

I use spring 3.0.5 and with hibernate.
Interceptor is working.
Send domain id to jms queue.
Consumer recive it and search domain, but is faster than database commit and i get null.
How to be shure that interceptor will be called after db commit ?
appCtx.xml
<tx:annotation-driven order="10" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<aop:aspectj-autoproxy />
<bean id="domainProducerHandler" depends-on="domainEventService"
class="org.test.service.DomainProducerHandler" factory-method="aspectOf">
<property name="domainEventService" ref="domainEventService" />
<property name="order" value="1" />
</bean>
===================service class=====================
#SendDomainEvent
#Transactional
public ProtoMessage sendDonation(String aa) {
Domain domainObj = new Domain();
domainRepository.saveAndFlush(domainObj);
return domain;
}
==================interceptor class===================**
#AfterReturning(
pointcut="#annotation(org.test.service.SendDomainEvent)",
returning="retVal")
public void processDomainReturn(Object retVal) {
....
try {
domainEventService.publishToQueue(endDonationSuccessEvent);
} catch (Exception e) {
log.error("error during send endDonationSuccessEvent: " + e);
}
}
Interceptor class implements Ordered interface. I set order parameter to tx:annotation-driven order="10" but it doesn't work.
What do you mean by "order parameter"? The supported ways of ordering advice in Spring AOP are with the #Ordered annotation or the org.springframework.core.Ordered interface, which also defines constants for the highest and lowest priorities.

Categories

Resources