【CSDN迁移】org.springframework.dao.InvalidDataAccessApiUsageException问题解决与分析

https://blog.csdn.net/jilijelon/article/details/71305636

今天在撸代码过程中遇到一个异常,解决之后记录一下,希望给同样遇到这个问题的人一个思路,也给自己的粗心大意提个醒:

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>