Java / 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 日编辑:这里有一些与休眠相关的配置

<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);
}

原文由 Guillaume 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 710
2 个回答

我从视图过滤器更改了单个会话属性。问题解决了:

   <filter>
    <filter-name>hibernateFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
    <init-param>
      <param-name>singleSession</param-name>
      <param-value>false</param-value>
    </init-param>
  </filter>

原文由 Fırat Küçük 发布,翻译遵循 CC BY-SA 3.0 许可协议

当使用 Spring OpenSessionInViewFilter 并尝试在 Spring 管理的事务之外执行持久性操作时,通常会看到该错误消息。过滤器将会话设置为 FlushMode.NEVER/MANUAL(取决于您使用的 Spring 和 Hibernate 的版本——它们大致相同)。当 Spring 事务机制开始一个事务时,它将刷新模式更改为“COMMIT”。事务完成后,它会根据需要将其设置回 NEVER/MANUAL。如果您 绝对确定 这不会发生,那么下一个最有可能的罪魁祸首就是对 Session 的非线程安全使用。 Hibernate Session 只能在一个线程中使用。如果它在线程之间交叉,就会发生各种混乱。请注意,从 Hibernate 加载的实体可以保存对加载它的 Session 的引用,因此跨线程处理实体也可能导致从另一个线程访问 Session。

原文由 Ryan Stewart 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题