Hello everyone, I'm using Spring's OpenSessionInViewFilter to allow lazy loading of Hibernate domain objects in my page class. Now the filter opens sessions are read only, and when I have to save something in my service bean, i get a "Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition." Exception, which makes sense. Now one solution for this is to open all sessions as read / write by extending this filter and overriding a couple of methods, which works, but seems like a bad idea considering the 90/10 Read/Write rule. So I decided to use @Transactional annotations on my service methods which need to save, and open a new Transaction. So I declared something like this. @Transactional(propagation=Propagation.REQUIRES_NEW, readOnly=false) above the method. Then in my context.xml i declared <tx:annotation-driven transaction-manager="transactionManger"/> and then declared a transaction manager for my session. I'm using eclipse with Spring project nature and it immediately picks this up, and adds a little orange double arrow symbol next to this, and the service method. But when I use it in the Page class, I still get the same exception, which leads me to believe that the proxy isn't being created. I looked at my logs and there is no indication of the TransactionManager being invoked. In my page class, instead of injecting the service directly, I also tried injecting ApplicationContext and then using its getBean method, but that did not work either. I tried the older approach, and declared transaction proxies for the beans like this. <bean id="transactionManger" parent="baseTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <!-- Proxied Services --> <bean id="proxyTemplate" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true"> <property name="transactionManager" ref="transactionManger" /> <property name="transactionAttributes"> <props> <prop key="save*">PROPAGATION_REQUIRES_NEW</prop> <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop> </props> </property> </bean> <bean id="enrollmentService" parent="proxyTemplate"> <property name="enrollmentServiceTarget"> <bean class="my.app.services.impl.EnrollmentServiceImpl"> <property name="enrollmentDao" ref="enrollmentDao" /> // Other injections for the service </bean> </property> <property name="proxyInterfaces" value="my.app.services.EnrollmentService" /> </bean>
And this does, work, and works very well at that. Looking at my logs I find [DEBUG] interceptor.TransactionInterceptor Completing transaction for [my.app.services.EnrollmentService.methodName] [DEBUG] hibernate3.HibernateTransactionManager Triggering beforeCommit synchronization [DEBUG] hibernate3.HibernateTransactionManager Triggering beforeCompletion synchronization [DEBUG] hibernate3.HibernateTransactionManager Triggering afterCommit synchronization [DEBUG] hibernate3.HibernateTransactionManager Triggering afterCompletion synchronization I haven't tried the spring / aop way of doing it, using <tx:advice> so I'm not sure if that would work. So my question is, why don't annotated transactions work? Is there something I can do differently to get them working? Would I have to make some contributions in app.module when the ApplicationContext is created? Or is there something that I'm just doing wrong? Declaring them in XML is fine, except that it gets cluttered quickly and is less readable. If anyone has any experience with this, or has any suggestions for me I would really appreciate it. Thanks,Jeshurun