Java / Hibernate – 在只读模式下不允许写操作

最近我一直有一个恼人的例外,经过对Google和这个论坛的一些研究,我还没有find可以解决我的问题的答案。

这是事情 – 有时,当试图更新或创build一个新的对象与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);更新getHibernateTemplate().saveOrUpdate(object); 它会工作,但有时与相同的对象,通过调用相同的方法,它不起作用,但它似乎取决于我如何获得对象的第一位。

例如:假设我有一个包含3个字段的表:id,type,length。 可能发生的是,如果我通过id获得对象并更新长度,那么它将工作。 如果我通过types得到它并更新长度,那么它将不起作用。 所以,为了避免这个问题,我一直在做的事情是把这个方法拿回来,而这个方法以后不会引起问题,但是现在变得越来越讨厌,试图find一种可行的方法。

此外,现在我试图创build一个对象(但不是所有的,只是在一个特定的表),这个exception,并找不到解决方法。 我试图在事务中添加@Transactional(readOnly = false) ,但是没有任何改变,显示模式是说我不是只读的。

有什么build议么?

7月26日编辑:这里有一些与hibernate相关的configuration

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

我从查看filter更改单会话propery。 问题解决了:

  <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> 

当使用Spring OpenSessionInViewFilter并试图在Springpipe理的事务之外进行持久性操作时,通常会看到这个错误消息。 filter将会话设置为FlushMode.NEVER / MANUAL(取决于您使用的Spring和Hibernate的版本 – 它们大致相当)。 当Spring事务机制开始事务时,它将刷新模式更改为“COMMIT”。 交易完成后,根据情况将其设置为“无论如何/手动”。 如果你确定这种情况没有发生,那么下一个最可能的罪魁祸首就是非线程安全地使用会话。 Hibernate会话只能在一个线程中使用。 如果它跨越线程之间,可能会发生各种混乱。 请注意,从Hibernate加载的实体可以持有对其加载的Session的引用,并且跨线程处理实体因此也可以使Session从另一个线程访问。

我也偶然发现了这个。 我需要将Spring的OpenSessionInViewFilter中的刷新模式更改为手动,突然间我开始得到这个exception。 我发现这个问题是在没有注释为@Transactional的方法中发生的,所以我猜Spring会隐式地把所有的数据访问代码看作是只读的方法。 注解的方法解决了这个问题。

另一种方法是调用HibernateTemplate对象上的setCheckWriteOperations方法。

 @Transactional 

在你的function之上

尝试使用这个

 hibernateTemplate = new HibernateTemplate(sessionFactory); hibernateTemplate.setCheckWriteOperations(false); 

错误应该消失,因为模板不检查您是否正在使用事务。

应用程序上下文中,使用下面的Bean作为HibernateTemplate

 <bean id="template" class="org.springframework.orm.hibernate4.HibernateTemplate"> <property name="sessionFactory" ref="mysessionFactory"></property> <property name="checkWriteOperations" value="false"></property> </bean> 

下面的一段代码是为我工作的。

 hibernateTemplate = new HibernateTemplate(sessionFactory); hibernateTemplate.setCheckWriteOperations(false); 

您必须忘记将@Transactional注释添加到您的DAO服务类/方法,这将指定您的数据库操作将由springpipe理的事务处理。

我有同样的问题,经过一天的调查,我观察到下面的声明

 <tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/> 

我删除了

 mode="aspectj" 

问题就消失了