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"
问题就消失了