Announcement Announcement Module
Collapse
No announcement yet.
Transaction trouble Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Transaction trouble

    Hi,

    I am having trouble getting transactions to work. I am using Spring and Hibernate 3. I have searched the forums and found info that I thought would fix the problem but I have had no luck.

    Here is my applicationContext.xml

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans>
    
    	<!-- DataSource Definition -->
    	<bean id="dataSource"
          	class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    		<property name="driverClassName">
    			<value>org.postgresql.Driver</value>
    		</property>
    		<property name="url">
    			<value>jdbc:postgresql://localhost:5432/taskman</value>
    		</property>
    		<property name="username">
    			<value>user</value>
    		</property>
    		<property name="password">
    			<value>pass</value>
    		</property>
    	</bean>
    
    	<!-- Hibernate SessionFactory Definition -->
    	 <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    		<property name="mappingResources">
    			<list>
    				<value>edu/suu/taskman/model/bo/Person.hbm.xml</value>
    				<value>edu/suu/taskman/model/bo/Note.hbm.xml</value>
    				<value>edu/suu/taskman/model/bo/Task.hbm.xml</value>
    				<value>edu/suu/taskman/model/bo/Project.hbm.xml</value>
    				<value>edu/suu/taskman/model/bo/Status.hbm.xml</value>
    				<value>edu/suu/taskman/model/bo/Category.hbm.xml</value>
    				<value>edu/suu/taskman/model/bo/Request.hbm.xml</value>
    				<value>edu/suu/taskman/model/bo/Resolution.hbm.xml</value>
    				<value>edu/suu/taskman/model/bo/Department.hbm.xml</value>
    				<value>edu/suu/taskman/model/bo/LoginRole.hbm.xml</value>
    			</list>
    		</property>		
    		
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
    				<prop key="hibernate.show_sql">true</prop>
    				
    			</props>
    		</property>
    		
    		<property name="dataSource">
    			<ref bean="dataSource"/>
    		</property>
    	</bean>
    
    	<!-- Spring Data Access Exception Translator Defintion -->
    	<bean id="jdbcExceptionTranslator" class="org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator"> 
    		<property name="dataSource"><ref bean="dataSource"/></property> 
    	</bean>
    	
    	<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
           	<property name="sessionFactory" ref="sessionFactory"/>
        </bean>
    
    	<!-- =================================   START DAO Defenitions   ============================= -->
    
    	<!-- LoginUser DAO Definition: Hibernate implementation -->
    	<bean id="projectDao" class="edu.suu.taskman.model.dao.ProjectDaoImpl">
    		<property name="sessionFactory" ref="sessionFactory"/>
    	</bean>
    	<bean id="personDao" class="edu.suu.taskman.model.dao.PersonDaoImpl">
    		<property name="sessionFactory" ref="sessionFactory"/>
    	</bean>
    	<bean id="taskDao" class="edu.suu.taskman.model.dao.TaskDaoImpl">
    		<property name="sessionFactory" ref="sessionFactory"/>
    	</bean>
    	<bean id="statusDao" class="edu.suu.taskman.model.dao.StatusDaoImpl">
    		<property name="sessionFactory" ref="sessionFactory"/>
    	</bean>
    	<bean id="categoryDao" class="edu.suu.taskman.model.dao.CategoryDaoImpl">
    		<property name="sessionFactory" ref="sessionFactory"/>
    	</bean>
    	<bean id="requestDao" class="edu.suu.taskman.model.dao.RequestDaoImpl">
    		<property name="sessionFactory" ref="sessionFactory"/>
    	</bean>
    
    	<!-- =================================  END DAO Defenitions   ================================ -->
    	
    	<bean id="projectTrans" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    		<property name="transactionManager" ref="transactionManager"/>
    		<property name="target" ref="projectDao"/>
    		<property name="transactionAttributes">
    			<props>
    				<prop key="get*">PROPAGATION_REQUIRED</prop>
    				<prop key="save*">PROPAGATION_REQUIRED</prop>
    				<prop key="*">PROPAGATION_REQUIRED</prop>
    			</props>
    		</property>
    	</bean>
    	<bean id="personTrans" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" parent="projectTrans">
    		<property name="target" ref="personDao"/>
    	</bean>
    	<bean id="taskTrans" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" parent="projectTrans">
    		<property name="target" ref="taskDao"/>
    	</bean>
    	<bean id="statusTrans" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" parent="projectTrans">
    		<property name="target" ref="statusDao"/>
    	</bean>
    	<bean id="categoryTrans" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" parent="projectTrans">
    		<property name="target" ref="categoryDao"/>
    	</bean>
    	<bean id="requestTrans" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" parent="projectTrans">
    		<property name="target" ref="requestDao"/>
    	</bean>
    	
    </beans>
    Any time I try to save I get the following stack trace:
    Code:
    Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into FlushMode.AUTO or remove 'readOnly' marker from transaction definition
            at org.springframework.orm.hibernate3.HibernateTemplate.checkWriteOperationAllowed(HibernateTemplate.java:1071)
            at org.springframework.orm.hibernate3.HibernateTemplate$18.doInHibernate(HibernateTemplate.java:689)
            at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:365)
            at org.springframework.orm.hibernate3.HibernateTemplate.saveOrUpdate(HibernateTemplate.java:687)
            at edu.suu.taskman.model.dao.TaskDaoImpl.save(Unknown Source)
            at edu.suu.taskman.view.backing.TaskController.save(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:585)
            at org.apache.myfaces.el.MethodBindingImpl.invoke(MethodBindingImpl.java:138)
            ... 34 more
    Here is what my save method looks like:
    Code:
        public void save(Task task) {       
            getHibernateTemplate().saveOrUpdate(task);
        }
    I have ready Karl Baum's article which has helped me immensely. It seems that my transaction manager doesn't recognize the methods I told it to put in a transaction. Any help would be greatly appreciated.

  • #2
    As the exception's error message suggests, somewhere you're setting the FlushMode to NEVER. (You could instead be setting the transaction to readonly, but I don't see that in your config file.)

    If you were motivated to read Karl Baum's article I gather you're having problems with lazy initialization, and somehow set the flush mode in an attempt to fix that. It's probably not the right approach.

    Comment


    • #3
      I thought I was removing the readOnly marker by wrapping my methods in a transaction with:

      Code:
      <bean id="projectTrans" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
      		<property name="transactionManager" ref="transactionManager"/>
      		<property name="target" ref="projectDao"/>
      		<property name="transactionAttributes">
      			<props>
      				<prop key="get*">PROPAGATION_REQUIRED</prop>
      				<prop key="save*">PROPAGATION_REQUIRED</prop>				
      			</props>
      		</property>
      	</bean>
      You are right in that I was having lazy initialization problems. To fix this I added the OpenSessionInViewFilter to my web.xml. I don't know how that sets FlushMode.NEVER.

      I have recently updated this application from using Hibernate 2 to Hibernate 3. The application worked fine with Hibernate 2. I am still combing through documentation to try and figure this out, but I thought maybe there would be something obvious that I was doing wrong that someone could point out.

      Comment


      • #4
        One thing to note is that Hibernate 3 uses lazy loading by default (lazy="true") - whereas Hibernate 2 was not lazy by default. If you have any properties that you specifically don't want to be lazy-loaded, then you should add lazy="false" within the mapping files.

        Comment


        • #5
          Yes, I did go through my app to make sure of that.

          Comment


          • #6
            The read-only mode is never the default, so something somewhere ought to be explicitly setting it. I assume you've done searches (via grep or whatever) for "FlushMode", for "NEVER", etc.

            You could try explicitly setting the flush mode, either in the transactionAttributes or via Session.setFlushMode().

            If you're facile with a debugger you could download the hibernate code and set a breakpoint in setFlushMode().

            Comment


            • #7
              That is good to know that the read-only mode is not default. I have no references to "FlushMode" or "NEVER", etc. anywhere in my code. I have read the documentation on declarative transactions several times. After reading the documentation I modified my declarative transaction defenition. This is my declarative transaction defenition from applicationContext.xml:

              Code:
              <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
              		<property name="sessionFactory" ref="sessionFactory"/>
              	</bean>
              
              <bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
              		<property name="transactionManager" ref="txManager"/>
              		<property name="transactionAttributes">
              			<props>
              				<prop key="*">PROPAGATION_REQUIRED</prop>
              			</props>
              		</property>
              	</bean>
              	<bean id="projectTrans" parent="txProxyTemplate">
              		<property name="target">
              			<bean class="edu.suu.taskman.model.service.ProjectServiceImpl"/>
              		</property>
              	</bean>
              	<bean id="personTrans" parent="txProxyTemplate">
              		<property name="target">
              			<bean class="edu.suu.taskman.model.service.PersonServiceImpl"/>
              		</property>
              	</bean>
              	<bean id="taskTrans" parent="txProxyTemplate">
              		<property name="target">
              			<bean class="edu.suu.taskman.model.service.TaskServiceImpl"/>
              		</property>
              	</bean>
              	<bean id="statusTrans" parent="txProxyTemplate">
              		<property name="target">
              			<bean class="edu.suu.taskman.model.service.StatusServiceImpl"/>
              		</property>
              	</bean>
              	<bean id="categoryTrans" parent="txProxyTemplate">
              		<property name="target">
              			<bean class="edu.suu.taskman.model.service.CategoryServiceImpl"/>
              		</property>
              	</bean>
              	<bean id="requestTrans" parent="txProxyTemplate">
              		<property name="target">
              			<bean class="edu.suu.taskman.model.service.RequestServiceImpl"/>
              		</property>
              	</bean>
              I followed the documentation for "Concise proxy definitions" and the target beans are my ServiceImpl classes. I still get "Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into FlushMode.AUTO or remove 'readOnly' marker from transaction definition."

              If read-only mode is not the default how else could it be set?
              Last edited by grimesp; Dec 16th, 2005, 12:46 PM.

              Comment


              • #8
                You would normally set readonly in Spring by something like this in your transactionAttributes
                <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>

                At the Hibernate level you can call Session.setFlushMode(FlushMode.NEVER).

                You might be able to just ignore the question of how things got the way they are and simply force the session to not be readonly but calling Session.setFlushMode with one of the other flush modes, e.g. FlushMode.AUTO.

                Comment


                • #9
                  What dbms are you using ? Have you updated your jdbc driver when moving to hibernate3 ? I've had a similar problem with postgresql , and i needed the newest driver

                  Comment


                  • #10
                    I am using PostgreSQL 8.1 with postgresql-8.1-404.jdbc3.jar

                    What version/driver worked for you?

                    Comment


                    • #11
                      FlushMode.AUTO

                      Somehow my FlushMode is being set to NEVER in my application. I have no idea where, I have greped, searched in my IDE, etc. I took Loren's advice and explicitly set the FlushMode to AUTO in all of my save methods. This fixed one of my 5 save methods, that one now persists to the database. The other save methods no longer throw the "Write operations are not allowed in read-only mode (FlushMode.NEVER)...", they appear to do the same thing as the save method that actually works but nothing is persisted to the database.

                      Any ideas?

                      Comment


                      • #12
                        I had problems with 7.3 . Don't remember the driver version , as i simply took the latest for my DB . You seem up to date so I guess no luck with findinig the problem there

                        Comment


                        • #13
                          This may help

                          I was having the same problem with an Oracle db.

                          InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session ...
                          I believe the problem was caused by upgrading to the latest 3.1 Hibernate jar, but that's just a guess.

                          I added flushMode property to openSessionInViewInterceptor everything seems to work.

                          <bean name="openSessionInViewInterceptor"
                          class="org.springframework.orm.hibernate3.support. OpenSessionInViewInterceptor">
                          <property name="sessionFactory"><ref bean="sessionFactory"/></property>
                          <property name="flushMode">
                          <bean id="org.springframework.orm.hibernate3.HibernateAc cessor.FLUSH_AUTO" class="org.springframework.beans.factory.config.Fi eldRetrievingFactoryBean"/>
                          </property>
                          </bean>
                          I hope this helps.

                          Comment


                          • #14
                            The same occurred when upgrading to 2.0 M1, Hibernate 3.1, using tx:advice

                            I am also using OpenSessionInViewFilter. When I using the old transaction config
                            method, every thing is OK. But when I converted the config to use the new tx:advice style, the same problem accurred.

                            I have solved the problem with a customized OpenSessionInViewFilter implementation as the following code shows:

                            public class OpenSessionInViewFilter extends org.springframework.orm.hibernate3.support.OpenSes sionInViewFilter {
                            protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
                            Session session = SessionFactoryUtils.getSession(sessionFactory, true);
                            session.setFlushMode(FlushMode.AUTO);
                            return session;
                            }

                            protected void closeSession(Session session, SessionFactory sessionFactory) {
                            session.flush();
                            SessionFactoryUtils.releaseSession(session, sessionFactory);
                            }
                            }

                            Comment


                            • #15
                              Can you please raise an issue on JIRA? Thanks.

                              Comment

                              Working...
                              X