HIbernate InvalidDataAccessApiUsageException - 只读模式
摘要:异常告诉我该事务是只读的;调试 println 似乎表明我不处于只读模式。
为互联网发布而编辑的类 - 抱歉,如果我输错了一些内容,但这是给我带来问题的代码的要点。 saveOrUpdate 在其他对象类型上调用时有效,但在这一对象类型上调用时无效。我在调试时将 println 添加到 saveOrUpdate 中。我没有编写抽象类,我只是尝试使用它(现在调试它)。
相关输出如下代码。不知道从这里去哪里。
调查后更新: 我也一直在对 spring 配置进行一些更新,一位同事指出,我调用 updateAParameter 的一个方法是以一种方式使用 spring,而损坏的方法是以另一种方式使用它。不幸的是,这条破碎的路正是我试图到达的路。
所以我现在理解的问题是,如果我通过获取 bean 在方法中“手动”实例化 DataObjectDAOImpl,那么它允许我正确写回 Hibernate。如果我使用 spring 为该 bean 设置类变量,这样我就不必在每个方法中实例化它,那么当我访问尝试写入 Hibernate 的方法时,就会发生 InvalidDataAccessApiUsageException,尽管事实上它报告不在其中只读模式。我的同事对这个主题有一个理论,但我不明白他想说什么——关于从 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);
}
}
这里是来自 spring 配置的相关 bean,
<bean id="sampleclass" class="com.service.SampleClass" scope="prototype">
<property name="dodi" ref="doDAOimpl"/>
</bean>
新旧方式输出是相同的:
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);
}
}
这里是 DAOImpl,它对于应用程序服务器的
[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
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我在这里看到的一个可能的问题是您正在从同一个 bean 调用
@Transactional
方法。我不确定它如何与您的异常相关,但由于 Spring 的声明式事务管理是通过基于代理的 AOP 实现的,这意味着此注释不会生效。另请参阅:
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: