Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HIbernate InvalidDataAccessApiUsageException - read-only mode

Summary: the Exception is telling me that the transaction is read-only; a debug println seems to indicate that I'm not in read-only mode.

Classes edited for internet publishing - sorry if I mistyped something but this is the jist of the code giving me problems. saveOrUpdate works when called on other object types but not on this one. I added the println to saveOrUpdate as I was debugging. I didn't write the abstract class, I'm just trying to use it (and now debug it).

Relevant output below code. Not sure where to go from here.

Update after investigation: I have also been in the middle of doing some updates to the spring config and a coworker pointed out that one method I called updateAParameter from was using spring in one way, and the broken method was using it in another way. Unfortunately the broken way is the way I was trying to get to.

So the problem as I now understand it is that if I instantiate the DataObjectDAOImpl "manually" in a method by getting a bean, then it allows me to write back to Hibernate correctly. If I use spring to set a class variable for that bean so I don't have to instantiate it in every method, then the InvalidDataAccessApiUsageException occurs when I access a method that tries to write to Hibernate, despite the fact that it reports not being in read-only mode. My coworker had a theory on this topic but I didn't understand what he was trying to say - something about extracting an interface from the SampleClass.

// Old way that works.
public class SampleClass {
public void someMethod {
ApplicationContext ac = ApplicationContextFactory.getApplicationContext();
DataObjectDAOImpl dodi = ((DataObjectDAOImpl) ac.getBean("dodi"));
//this works
dodi.updateAParameter("foo", exampleDataObject);
}
}

//New way that doesn't work but I would like it to.
public class SampleClass {
private DataObjectDAOImpl dodi = null;
//'dodi' has getter and setter methods that I am not pasting here for simplicity
public void someMethod {    
//causes Exception
dodi.updateAParameter("foo", exampleDataObject);
}
}

and here is relevant bean from the spring config

<bean id="sampleclass" class="com.service.SampleClass" scope="prototype">
    <property name="dodi" ref="doDAOimpl"/>
</bean>

here is the DAOImpl which is the same for the old and new way

public class DataObjectDAOImpl extends AbstractSpringDaoStuff {

 ...

 public void updateAParameter(String parameter, DataObject do) {
  do.setAParameter(parameter);
  super.saveOrUpdate(do);
 }

}


public abstract class AbstractSpringDaoStuff extends HibernateDaoSupport {

   ...

    @Transactional(readOnly=false)
     protected void saveOrUpdate(Object obj) {
     System.out.println ( "Read-only?: " + TransactionSynchronizationManager.isCurrentTransactionReadOnly () );

         getHibernateTemplate().saveOrUpdate(obj);
     }        
}

Output from the app server:

     [java] Read-only?: false
     [java] - Method execution failed:
     [java] org.springframework.dao.InvalidDataAccessApiUsageException: 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.
     [java]     at org.springframework.orm.hibernate3.HibernateTemplate.checkWriteOperationAllowed(HibernateTemplate.java:1186)
     [java]     at org.springframework.orm.hibernate3.HibernateTemplate$16.doInHibernate(HibernateTemplate.java:750)
     [java]     at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:419)
     [java]     at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
     [java]     at org.springframework.orm.hibernate3.HibernateTemplate.saveOrUpdate(HibernateTemplate.java:748)
     [java]     at com.est.dao.AbstractSpringDaoStuff.saveOrUpdate(AbstractSpringDaoMDA.java:24)
etc
like image 462
Nathan Spears Avatar asked Oct 06 '10 16:10

Nathan Spears


1 Answers

The one possible problem I can see here is that you are calling @Transactional method from the same bean. I'm not sure how it can be related to your exception, but since Spring's declarative transaction management is implemented via proxy-based AOP it means that this annotation doesn't take effect.

See also:

  • 7.6.1 Understanding AOP proxies
  • 10.5.1 Understanding the Spring Framework's declarative transaction implementation
like image 185
axtavt Avatar answered Oct 23 '22 01:10

axtavt