First of all, I dare to ask a simple question: did you hit the reload/refresh button of your database tool?
Otherwise, please post your code (JUNIT-Test and application).
First of all, I dare to ask a simple question: did you hit the reload/refresh button of your database tool?
Otherwise, please post your code (JUNIT-Test and application).
Hi, First of all, apologies for a late response. I was out sick.
Here is the scenario I was testing. I have two tables. User and Roles. Whenver a new user is created, one new record is inserted into the User table and one into the role table. (A user has a role (1:1)).
Both the insert operations are called one afrer the another in the same method.
JUnit Test Case:
I throw an exception on the insert role method in my Junit test case. It works fine. When I refresh the database tool, I dont a user object inserted into the database.
Application Environment:
I use the same code, same application context xml file and same hibernate properties. But when I refresh, I see no records are inserted to role table, which is as expected, but a new record is inserted into user table. This means, the rolback is not happening.
The insertUser and insertRole methods have the transactional annotation as well as defined below:Code:@Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class) public boolean createUser(Object userObject) { try{ insertUser(userObject); insertRole(userObject); catch(Exception e) { throw e; } }
The logs are:Code:@Transactional(propagation=Propagation.REQUIRED) public void insertRole(Object object) throws Exception{ ..... }
Code:2009-04-03 13:11:42,656 ERROR [org.hibernate.event.def.AbstractFlushingEventListener] - <Could not synchronize database state with session> org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:94) at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275) at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:114) at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:109) at org.hibernate.jdbc.AbstractBatcher.prepareBatchStatement(AbstractBatcher.java:244) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2252) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2688) at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79) at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279) at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263) at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167) at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321) at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50) at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027) at org.springframework.orm.hibernate3.SpringSessionSynchronization.beforeCommit(SpringSessionSynchronization.java:135) at org.springframework.transaction.support.TransactionSynchronizationUtils.triggerBeforeCommit(TransactionSynchronizationUtils.java:72) at org.springframework.transaction.support.AbstractPlatformTransactionManager.triggerBeforeCommit(AbstractPlatformTransactionManager.java:905) at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:715) at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:701) at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:321) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:116) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) at $Proxy6.createUser(Unknown Source) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:307) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:198)
Any ideas any body. I really need some help here. I have been struggling for past couple of days to solve this issue. I have tried several variations of different configurations and nothing seems to work.
Any help would be really appreciated.
Thanks..
Maybe the corresponding class XY of the method createUser was not instantiated via an Interface, i.e.
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext .xml");
IXYService s = (IXYService)ctx.getBean("nameOfClassXY");
Well, the class is being instantiated via an interface.
Here is the complete application code.
ApplicationContext.xml file. For the sake of brevity and testing, I had included all beans in one xml file.
DAO CodeCode:<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <!-- Transaction Management --> <tx:annotation-driven transaction-manager="txManager"/> <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <bean id="smartDaoTarget" class="com.package.dao.impl.SmartWorkDaoImpl"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <bean id="smartBaseBO" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces" value="com.package.core.dao.SmartBaseBO" /> <property name="target" ref="smartDaoTarget"/> </bean> <bean id="userManager" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces" value="com.package.core.users.UserManager"/> <property name="target" ref="userManagerTarget"/> </bean> <bean id="userManagerTarget" class="com.package.core.users.impl.UserManagerImpl"> <property name="smartBaseBO" ref="smartBaseBO"/> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mappingLocations"> <list> <value>/WEB-INF/hbm/security/Authorities.hbm.xml</value> <value>/WEB-INF/hbm/security/Users.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">${hibernate.dialect}</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.max_fetch_depth">3</prop> <prop key="hibernate.connection.release_mode">auto</prop> </props> </property> </bean> <bean id="dataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy" destroy-method="close"> <property name="targetDataSource" ref="dataSourceTarget"/> <property name="defaultAutoCommit" value="false"/> </bean> <bean id="dataSourceTarget" class="oracle.jdbc.pool.OracleConnectionPoolDataSource" destroy-method="close"> <property name="URL" value="jdbc:oracle:thin:@192.168.1.100:1521:test"/> <property name="user" value="testuser" /> <property name="password" value="testpwd" /> </bean> </beans>
========
The Unit test case works fine. It doesn't create a user, if the role creation for the user fails. It rolls back properly. The database doesn't contain the record as expected. (the tool was refreshed).Code://SmartBaseBO.java interface definition file. public interface SmartBaseBO { public boolean add(Object aObject); } public class SmartWorkDaoImpl implements SmartBaseBO { private SessionFactory sessionFactory; public boolean add(Object aObject) { boolean bRetVal = false; Session session = getSession(); try { session.save(aObject); bRetVal = !bRetVal; } catch (HibernateException e) { throw SessionFactoryUtils.convertHibernateAccessException(e); } finally { session.flush(); } return bRetVal; } private Session getSession() { return SessionFactoryUtils.getSession(getSessionFactory(), true); } public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } public SessionFactory getSessionFactory() { return this.sessionFactory; } } //UserManager Interface package com.package.core.users; public interface UserManager { void createUser(Users user, String role) throws Exception; } //UserManager Implementation package com.package.core.users.impl; public class UserManagerImpl implements UserManager { private final static Log LOG = LogFactory.getLog(UserManagerImpl.class); private SmartBaseBO smartBaseBO; @Transactional(propagation=Propagation.REQUIRES_NEW,rollbackFor = Exception.class) public void createUser(Users user, String role) throws Exception { try { smartBaseBO.add(user); Authorities auth = new Authorities(); auth.setAuthority(role); auth.setUsername(user.getUsername()); auth.setUsers(user); smartBaseBO.add(auth); } catch (Exception e) { LOG.error("------------------------------ EXCEPTION ----------"); throw e; } } public void setSmartBaseBO(SmartBaseBO smartBaseBO) { this.smartBaseBO = smartBaseBO; } } //JUnit Test Case public class UserManagerTest { @Test public void testAdd() { try { ApplicationContext appCtx = new ClassPathXmlApplicationContext("applicationContext.xml"); UserManager userManager = (UserManager) appCtx.getBean("userManager"); Users user = new Users(); user.setUsername("junittest3"); user.setFirstName("junittest1"); user.setLastName("junittest1"); user.setPassword("test"); user.setUpdated(new Date()); user.setPrimaryEMail("test@email.com"); userManager.createUser(user, "DEFAULT_ROLE"); } catch (Exception e) { System.out.println(e); } } }
But, same code doesnt work when used in the application. The logs show that the rollback was done, but the database has the new record, whereas the new record should not have been inserted. (again, the tool was refreshed).
My guess, is it has something to do with Spring Transaction Synchronization and Spring Session management.
Database: Oracle 10g
AppServer: Tomcat 6.0.18
Spring 2.5.6
Hibernate 3.3.1 GA
Thanks for the help.
Last edited by ritesh; Apr 9th, 2009 at 12:35 PM.
Well.. my problem is not resolved. It's a strange problem, and I am not able to figure out the cause of the problem.
In my log4j.properties file, when I set
lo4j.logger.org.hibernate=INFO
the rollback doesnt work. But when I set
log4j.logger.org.hibernate-DEBUG
then the rollback works fine. I know it sounds crazy, but this is what I am seeing on my setup.
The application works fine and rollback and transactions happen as expected when the log level is set to DEBUG, but when the log level is set to INFO, it doesn't work.
This leads me to think that there is some kind of bug in hibernate code and setting of rolback flag is somehow made dependent on the log level. I am not sure, but I am still digging into this. If someone has seen this behavior before, I would be thankful, if they can provide some insight into this.
Thanks.