今天在撸代码过程中遇到一个异常,解决之后记录一下,希望给同样遇到这个问题的人一个思路,也给自己的粗心大意提个醒:
org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.通过报错信息理解,可以定位到错误原因 是和Spring事务有关,当前方法的权限是read-only。 我执行的方法是
excelExportDao.save(oobfs.get(1));所以需要找一下事务配置文件里面对save*的配置,事务的配置代码如下:
<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd"> <!-- 扫描cn.jkstudio.excelexport.service包下所有标注@Service的服务组件 --> <context:component-scan base-package="cn.jkstudio.excelexport.service"/> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <!-- 配置事务通知属性 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!-- 定义事务传播属性 --> <tx:attributes> <!-- 增 --> <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="new*" propagation="REQUIRED" /> <tx:method name="create*" propagation="REQUIRED" /> <!-- 删 --> <tx:method name="remove*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <!-- 改 --> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="edit*" propagation="REQUIRED" /> <tx:method name="set*" propagation="REQUIRED" /> <tx:method name="change*" propagation="REQUIRED" /> <!-- 查 --> <tx:method name="get*" propagation="REQUIRED" read-only="true" /> <tx:method name="find*" propagation="REQUIRED" read-only="true" /> <tx:method name="load*" propagation="REQUIRED" read-only="true" /> <tx:method name="*" propagation="REQUIRED" read-only="true" /> </tx:attributes> </tx:advice> <!-- 配置事务切面 --> <aop:config> <aop:pointcut id="serviceOperation" expression="execution(* cn.jkstudio.*.service.*.*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" /> </aop:config> </beans>可以看到的是,对save方法已经进行了事务配置,网上搜索了一下这个问题,大多数解决方法都是差不多的,大意就是
1、在执行操作之前 插入getHibernateTemplate().setFlushMode(2) 或者 在方法执行之后 getHibernateTemplate().flush(); 这也能够明白为什么会出现这个原因的。但是本人不推荐这种解决方式
2、使用 hibernateFilter 来解决:……
来自:http://blog.csdn.net/longxia1987/article/details/7819242
事实上,我的项目是从我之前的一个项目里面copy过来修改的,之前并没有遇到事务问题,按照该网上的方法修改之后并没有解决问题。
当我仔细检查后发现,我遇到这个报错的原因很简单,在配置事务切面的地方对包路径写的有问题:
<!-- 配置事务切面 --> <aop:config> <aop:pointcut id="serviceOperation" expression="execution(* cn.jkstudio.*.service.*.*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" /> </aop:config>检查expression="execution(* cn.jkstudio.*.service.*.*.*(..))"
第一个 * 表示方法返回值类型可以为任意类型
第二个 * 表示cn.jkstudio包下面的任意包
第三个 * 表示service包下面的任意包
第四个 * 表示service.任意包 下面的任意一个类
第五个 * 表示service.任意包.任意类下面的任意一个方法
后面小括号里面的两个 .. 表示该方法可以有0个或多个参数
因为我这个项目的包路径和之前的项目包路径有所区别,在service包下面直接是类代码,而没有继续分模块包。 这就导致在该项目中实际上并没有对service层的代码进行注入,所以,save方法才会报事务相关的错误。
问题找到了,也就好解决了,修改一下expression就好了。 希望给同样遇到这种错误的人提供解决问题的思路,有时候不一定是事务配置没写,而是粗心写错了切面注入的位置。:P
<!-- 配置事务切面 --> <aop:config> <aop:pointcut id="serviceOperation" expression="execution(* cn.jkstudio.*.service.*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" /> </aop:config>