Announcement Announcement Module
Collapse
No announcement yet.
TransactionManager / Caching problem Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • TransactionManager / Caching problem

    Hi,

    I am using Hibernate 2.1.6 and Spring 1.1. with Spring Transaction Demarcation.
    Following are my configurations

    Application context configuration
    Code:
     <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
            <property name="resourceRef"><value>true</value></property>
            <property name="jndiName"><value>jdbc/mScapeEventStore</value></property>
     </bean>
        
      <bean id="mScape&#58;HibernateSessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
            <property name="schemaUpdate">
                <value>true</value>
            </property>
            <property name="mappingResources">
                <list>
                    <value>com/westglobal/mscape/modules/minimax/hibernate/minimax.hbm.xml</value>
                    <value>com/westglobal/mscape/modules/threshold/dao/hibernate/threshold.hbm.xml</value>
                    <value>com/westglobal/mscape/modules/action/javamail/dao/hibernate/mailAddress.hbm.xml</value>
                    <value>com/westglobal/mscape/modules/action/persistence/action.hbm.xml</value>
                    <value>com/westglobal/mscape/modules/decisiontree/persistence/hibernate/decisiontree.hbm.xml</value>
    		<value>com/westglobal/mscape/modules/mapping/lookup/hibernate/mapping.hbm.xml</value>
                    <value>com/westglobal/mscape/persistence/hibernate/event.hbm.xml</value>
                    <value>com/westglobal/mscape/persistence/hibernate/pipeline.hbm.xml</value>	
                    <value>com/westglobal/mscape/persistence/hibernate/module.hbm.xml</value>	                
                    <value>com/westglobal/mscape/reporting/dao/hibernate/timeframe.hbm.xml</value>
                </list>
            </property>
            <property name="hibernateProperties">
                <props>
                    <prop key="hibernate.dialect">$&#123;hibernate.dialect&#125;</prop> 
                    <prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.Provider</prop>
                    <prop key="hibernate.cache.use_query_cache">true</prop>
                </props>
            </property>
            <property name="dataSource"><ref bean="dataSource"/></property>
        </bean>
    
        <bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
           <property name="sessionFactory"><ref local="mScape&#58;HibernateSessionFactory"/></property>
        </bean>
    
        <bean id="mScape&#58;thresholdPropertyValueDao" class="com.westglobal.mscape.modules.threshold.dao.hibernate.HibernateThresholdPropertyValueDao">
            <property name="sessionFactory"><ref bean="mScape&#58;HibernateSessionFactory"/></property>
        </bean>
    
        <bean id="mScape&#58;RuntimeFrameworkTarget" class="com.westglobal.mscape.runtime.RuntimeFrameworkImpl">
            <property name="pipelineStore"><ref bean="mScape&#58;PipelineStore"/></property>
        </bean>
    
        <bean id="mScape&#58;RuntimeFramework" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
            <property name="transactionManager"><ref bean="transactionManager"/></property>
            <property name="target"><ref bean="mScape&#58;RuntimeFrameworkTarget"/></property>
            <property name="transactionAttributes">
                <props>
                    <prop key="processEvent">PROPAGATION_REQUIRED</prop>
                </props>
            </property>
        </bean>
    Hibernate mapping config for the Domain Object where the problem arises
    Code:
    <...>
    <class name="HibernateThresholdPropertyValue">
    	<cache usage="read-write"/>
    	<id type="int" name="id">
    		<generator class="native"/>
    	</id>
    	<property name="value" not-null="true" unique="true"/>
    	<set name="thresholds" inverse="true" lazy="true">
    		<key column="threshold_pv_id"/>
    		<one-to-many class="HibernateThreshold"/>
    	</set>
    </class>
    <...>
    DAO Code
    Code:
    public class HibernateThresholdPropertyValueDao extends HibernateDaoSupport implements ThresholdPropertyValueDao &#123;
       private static class GetThresholdPropertyValueCallback implements HibernateCallback &#123;
            private String value;
            
            public GetThresholdPropertyValueCallback&#40;String value&#41; &#123;
                this.value = value;
            &#125;
            
            public Object doInHibernate&#40;Session session&#41; throws HibernateException, SQLException &#123;
                Query q = session.getNamedQuery&#40;FIND_THRESHOLD_PROPERTY_VALUE_QUERY&#41;;
                q.setCacheable&#40;true&#41;;
                q.setText&#40;"value", value&#41;;  
                return q.uniqueResult&#40;&#41;;
            &#125;
        &#125;
        
        private static class GetOrCreatePropertyValueDaoCallback implements HibernateCallback &#123;
            private String value;
            
            public GetOrCreatePropertyValueDaoCallback&#40;String value&#41; &#123;
                this.value = value;
            &#125;
            
            public Object doInHibernate&#40;Session session&#41; throws HibernateException, SQLException &#123;
                HibernateCallback callback = new GetThresholdPropertyValueCallback&#40;value&#41;;
                ThresholdPropertyValue thresholdPropertyValue = &#40;ThresholdPropertyValue&#41;callback.doInHibernate&#40;session&#41;;
                if &#40;thresholdPropertyValue == null&#41; &#123;
                    thresholdPropertyValue = new HibernateThresholdPropertyValue&#40;value&#41;;
                    session.save&#40;thresholdPropertyValue&#41;;
                &#125;
                return thresholdPropertyValue;
            &#125;
        &#125;
    
        public ThresholdPropertyValue getOrCreateThresholdPropertyValue&#40;String value&#41; &#123;
    	return &#40;ThresholdPropertyValue&#41;getHibernateTemplate&#40;&#41;.execute&#40;new GetOrCreatePropertyValueDaoCallback&#40;value&#41;&#41;;
        &#125;
    &#125;
    The TransactionProxyFactoryBean target calls processEvent which eventually calls the HibernateThresholdPropertyValueDao method getOrCreateThresholdPropertyValue(...).
    The HibernateThresholdPropertyValueDao method getOrCreateThresholdPropertyValue(...) is called a few times from the processEvent
    The second time the method getOrCreateThresholdPropertyValue(...) is called I get the following error.

    java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC][SQLServer]Violation of UNIQUE KEY constraint 'UQ__HibernateThresho__2F10007B'. Cannot insert duplicate key in object 'HibernateThresholdPropertyValue'.
    2004-10-27 13:29:10,712 DEBUG [Thread-15 net.sf.hibernate.util.JDBCExceptionReporter] - <SQL Exception>
    java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC][SQLServer]Violation of UNIQUE KEY constraint 'UQ__HibernateThresho__2F10007B'. Cannot insert duplicate key in object 'HibernateThresholdPropertyValue'.
    at com.microsoft.jdbc.base.BaseExceptions.createExcep tion(Unknown Source)
    at com.microsoft.jdbc.base.BaseExceptions.getExceptio n(Unknown Source)
    at com.microsoft.jdbc.sqlserver.tds.TDSRequest.proces sErrorToken(Unknown Source)
    at com.microsoft.jdbc.sqlserver.tds.TDSRequest.proces sReplyToken(Unknown Source)
    at com.microsoft.jdbc.sqlserver.tds.TDSRPCRequest.pro cessReplyToken(Unknown Source)
    at com.microsoft.jdbc.sqlserver.tds.TDSRequest.proces sReply(Unknown Source)
    at com.microsoft.jdbc.sqlserver.SQLServerImplStatemen t.getNextResultType(Unknown Source)
    at com.microsoft.jdbc.base.BaseStatement.commonTransi tionToState(Unknown Source)
    at com.microsoft.jdbc.base.BaseStatement.postImplExec ute(Unknown Source)
    at com.microsoft.jdbc.base.BasePreparedStatement.post ImplExecute(Unknown Source)
    at com.microsoft.jdbc.base.BaseStatement.commonExecut e(Unknown Source)
    at com.microsoft.jdbc.base.BaseStatement.executeInter nal(Unknown Source)
    at com.microsoft.jdbc.base.BasePreparedStatement.exec ute(Unknown Source)
    at org.apache.commons.dbcp.DelegatingPreparedStatemen t.execute(DelegatingPreparedStatement.java:256)
    at net.sf.hibernate.persister.EntityPersister.insert( EntityPersister.java:508)
    at net.sf.hibernate.persister.EntityPersister.insert( EntityPersister.java:432)
    at net.sf.hibernate.impl.ScheduledIdentityInsertion.e xecute(ScheduledIdentityInsertion.java:29)
    at net.sf.hibernate.impl.SessionImpl.doSave(SessionIm pl.java:932)
    at net.sf.hibernate.impl.SessionImpl.doSave(SessionIm pl.java:857)
    at net.sf.hibernate.impl.SessionImpl.saveWithGenerate dIdentifier(SessionImpl.java:775)

    I am using the ehcache plugin with default configurations.
    It seems that the query cache is unaware that it needs to be updated on the second hit during the transaction. The first call to
    getOrCreateThresholdPropertyValue makes a call to session.save(thresholdPropertyValue).

    This problem only manifested when the transaction manager was introduced. If the transaction manager is removed the
    query cache is aware that it needs to be updated (on the second call to getOrCreateThresholdPropertyValue(...)).
    It works of course if I set the queries forceCacheToRefresh to true.
    Is this what I have to do to synchronise the queryCache during a transaction?
    Any help would be greatly appreciated.

    Sinead
Working...
X