我最近经常遇到一个烦人的异常,经过谷歌和这个论坛的一些研究,我仍然没有找到可以解决我问题的答案。
事情是这样的 - 有时,我在尝试使用 hibernate 更新或创建新对象时收到以下错误:
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.
at org.springframework.orm.hibernate3.HibernateTemplate.checkWriteOperationAllowed(HibernateTemplate.java:1186)
at org.springframework.orm.hibernate3.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:696)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:419)
at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
at org.springframework.orm.hibernate3.HibernateTemplate.save(HibernateTemplate.java:694)
真正奇怪的是,有时当使用 getHibernateTemplate().saveOrUpdate(object);
方法更新对象时,它会起作用,但有时使用相同的对象并调用相同的方法它不起作用,但这似乎取决于我首先如何获取对象。
示例:假设我有一个包含 3 个字段的表:id、type、length。可能发生的情况是,如果我通过 id 获取对象并更新长度,那么它将起作用。如果我通过类型获取它并更新长度,那么它将不起作用。所以到目前为止我一直在做的避免这个问题的方法是获取对象以后不会导致问题的方法,但是尝试找到一种可行的方法变得越来越烦人。
另外,现在我在尝试创建一个对象时遇到了这个异常(但不是全部,只是在一个特定的表上),并且找不到解决方法。我试图在事务中添加 @Transactional(readOnly = false)
但它没有改变任何东西,并且显示模式表示我无论如何都不是只读的。
有什么建议吗?
7 月 26 日编辑: 这里是一些与hibernate相关的配置
<property name="hibernateProperties">
<props>
<prop key="jdbc.fetch_size">20</prop>
<prop key="jdbc.batch_size">25</prop>
<prop key="cglib.use_reflection_optimizer">true</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="connection.autoReconnect">true</prop>
<prop key="connection.autoReconnectForPools">true</prop>
<prop key="connection.is-connection-validation-required">true</prop>
</props>
</property>
如果有帮助的话
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="execute*">PROPAGATION_REQUIRED</prop>
<prop key="add*">PROPAGATION_REQUIRED</prop>
<prop key="create*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
</props>
</property>
8 月 31 日编辑:
我的类中扩展 HibernateDaoSupport
以保存对象的相关代码是:
public void createObject(Object persisObj) {
getHibernateTemplate().save(persisObj);
}
最佳答案
使用 Spring 时通常会看到该错误消息 OpenSessionInViewFilter并尝试在 Spring 管理的事务之外进行持久性操作。过滤器将 session 设置为 FlushMode.NEVER/MANUAL(取决于您使用的 Spring 和 Hibernate 的版本——它们大致相同)。当 Spring 事务机制开始一个事务时,它会将刷新模式更改为“COMMIT”。事务完成后,它会根据需要将其设置回 NEVER/MANUAL。如果您绝对确定这不会发生,那么下一个最有可能的罪魁祸首是 session 的非线程安全使用。 Hibernate Session 只能在一个线程中使用。如果它在线程之间交叉,就会发生各种困惑。请注意,从 Hibernate 加载的实体可以持有对加载它的 Session 的引用,因此跨线程处理实体可能会导致 Session 也可以从另一个线程访问。
https://stackoverflow.com/questions/6810158/