我最近经常遇到一个烦人的例外,经过对谷歌和这个论坛的一些研究后,我仍然没有找到可以解决我问题的答案。
这就是事情 - 有时,我在尝试用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);
}
答案 0 :(得分:11)
当使用Spring OpenSessionInViewFilter并尝试在Spring管理的事务之外执行持久性操作时,通常会看到该错误消息。过滤器将会话设置为FlushMode.NEVER / MANUAL(取决于您使用的Spring和Hibernate的版本 - 它们大致相当)。当Spring事务机制开始一个事务时,它将刷新模式更改为“COMMIT”。事务完成后,它会根据需要将其设置为NEVER / MANUAL。如果你绝对确定没有发生这种情况,那么下一个最可能的罪魁祸首就是非线程安全地使用Session。 Hibernate Session必须只在一个线程中使用。如果它穿过线程之间,就会发生各种混乱。请注意,从Hibernate加载的实体可以保存对加载它的Session的引用,因此跨线程处理实体也可以导致从另一个线程访问Session。
答案 1 :(得分:7)
添加
@Transactional
在你的功能之上
答案 2 :(得分:6)
我也偶然发现了这一点。我需要将Spring的OpenSessionInViewFilter中的刷新模式更改为手动,突然我开始得到这个异常。我发现问题是在没有注释为@Transactional的方法中出现问题,所以我猜Spring会隐式地将所有数据访问代码视为只读方法。注释该方法解决了这个问题。
另一种方法是在HibernateTemplate对象上调用setCheckWriteOperations方法。
答案 3 :(得分:6)
我从视图过滤器更改了单个会话属性。问题解决:
<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>
答案 4 :(得分:3)
尝试使用此
hibernateTemplate = new HibernateTemplate(sessionFactory);
hibernateTemplate.setCheckWriteOperations(false);
错误应该消失,因为模板没有检查您是否正在使用交易。
答案 5 :(得分:2)
您必须忘记将@Transactional注释添加到您的DAO服务类/方法,这将指定您的数据库操作将由Spring托管事务处理。
答案 6 :(得分:1)
下面的代码对我有用。
hibernateTemplate = new HibernateTemplate(sessionFactory);
hibernateTemplate.setCheckWriteOperations(false);
答案 7 :(得分:1)
1)在数据库操作方法和上面添加@Transactional 2)确保你有注释驱动的转换管理器
添加
在applicationContext.xml文件中的HibernateTransactionManager配置上面
答案 8 :(得分:0)
我遇到了同样的问题,经过一天的调查后,我发现了以下声明
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
我删除了
mode="aspectj"
并且问题消失了
答案 9 :(得分:0)
尝试使用此
this.getHibernateTemplate().setCheckWriteOperations(false);
如果您使用的是hibernate4并且无法更新实体/表,那么您需要创建会话并刷新会话,即
this.getHibernateTemplate().setCheckWriteOperations(false);
Session session = this.getHibernateTemplate().getSessionFactory().openSession();
session.saveOrUpdate(entityName,app);
session.flush();
session.close();