关于springMvc+mybatis+hibernateJPA混用导致的JPA事物问题

    项目中同时使用到了mybatis和JPA,使用spring 声明式事物来管理各自的事物,但是JPA老报错

javax.persistence.TransactionRequiredException: no transaction is in progress
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.checkTransactionNeeded(AbstractEntityManagerImpl.java:1171)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1332)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:347)
    at com.sun.proxy.$Proxy162.flush(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298)
    at com.sun.proxy.$Proxy53.flush(Unknown Source)

文件配置如下spring-context配置如下:

<?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:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:task="http://www.springframework.org/schema/task"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.3.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
    http://www.springframework.org/schema/task
    http://www.springframework.org/schema/task/spring-task-4.3.xsd">


    <!-- 自动加载属性配置文件 -->
    <context:property-placeholder
        ignore-resource-not-found="true" ignore-unresolvable="true"
        file-encoding="UTF-8"
        location="classpath:properties/dbjdbc.properties,classpath:properties/config.properties"
        system-properties-mode="ENVIRONMENT" />
        
    <!-- 使用Annotation自动注册Bean,解决事物失效问题:在主容器中不扫描@Controller注解,在SpringMvc中只扫描@Controller注解。  -->
    <context:component-scan base-package="net.lantrack"><!-- base-package 如果多个,用“,”分隔 -->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!-- task executor and scheduler -->
    <task:annotation-driven />
    
    <!-- datasource start -->
    <!-- hrms datasource -->
    <bean id="dataSource" name="dataSource"
        class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
        destroy-method="close">
        <property name="driverClassName"
            value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.hrmsurl}" />
        <property name="username" value="${jdbc.hrmsusername}" />
        <property name="password" value="${jdbc.hrmspassword}" />
        <!-- 初始化连接大小 -->
        <property name="initialSize" value="0" />
        <!-- 连接池最大使用连接数量 -->
        <property name="maxActive" value="20" />
        <!-- 连接池最大空闲 <property name="maxIdle" value="20" /> -->
        <!-- 连接池最小空闲 -->
        <property name="minIdle" value="5" />
        <!-- 获取连接最大等待时间 -->
        <property name="maxWait" value="60000" />
        <!-- <property name="validationQuery" value="${validationQuery.sqlserver}"
            /> -->
        <property name="testOnBorrow" value="false" />
        <property name="testOnReturn" value="false" />
        <property name="testWhileIdle" value="true" />

        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="300000" />

        <!-- 打开removeAbandoned功能 -->
        <property name="removeAbandoned" value="true" />
        <!-- 1800秒,也就是30分钟 -->
        <property name="removeAbandonedTimeout" value="3600" />
        <!-- 关闭abanded连接时输出错误日志 -->
        <property name="logAbandoned" value="true" />

        <!-- 开启Druid的监控统计功能 -->
        <property name="filters" value="stat" />
        <!--<property name="filters" value="mergeStat" /> -->
        <!-- Oracle连接是获取字段注释 -->
        <property name="connectProperties">
            <props>
                <prop key="remarksReporting">true</prop>
            </props>
        </property>
    </bean>

    <!-- hjws datasource -->
    <bean id="dataSourceHw" name="dataSourceHw"
        class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
        destroy-method="close">
        <property name="driverClassName"
            value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.hjwsurl}" />
        <property name="username" value="${jdbc.hjwsusername}" />
        <property name="password" value="${jdbc.hjwspassword}" />
        <!-- 初始化连接大小 -->
        <property name="initialSize" value="0" />
        <!-- 连接池最大使用连接数量 -->
        <property name="maxActive" value="20" />
        <!-- 连接池最大空闲 <property name="maxIdle" value="20" /> -->
        <!-- 连接池最小空闲 -->
        <property name="minIdle" value="5" />
        <!-- 获取连接最大等待时间 -->
        <property name="maxWait" value="60000" />
        <!-- <property name="validationQuery" value="${validationQuery.sqlserver}"
            /> -->
        <property name="testOnBorrow" value="false" />
        <property name="testOnReturn" value="false" />
        <property name="testWhileIdle" value="true" />

        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="300000" />

        <!-- 打开removeAbandoned功能 -->
        <property name="removeAbandoned" value="true" />
        <!-- 1800秒,也就是30分钟 -->
        <property name="removeAbandonedTimeout" value="3600" />
        <!-- 关闭abanded连接时输出错误日志 -->
        <property name="logAbandoned" value="true" />

        <!-- 开启Druid的监控统计功能 -->
        <property name="filters" value="stat" />
        <!--<property name="filters" value="mergeStat" /> -->
        <!-- Oracle连接是获取字段注释 -->
        <property name="connectProperties">
            <props>
                <prop key="remarksReporting">true</prop>
            </props>
        </property>
    </bean>
    <!-- datasource end -->


    <!-- mybatis factory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:other/mybatis.xml" />
        <property name="mapperLocations" value="classpath*:mapper/**/*Mapper.xml" />
    </bean>
    <!-- mybatis scan mappers under the dao dir -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
        <property name="basePackage" value="net.lantrack.**.dao" />
    </bean>
    <!-- mybatis transaction manager -->

   

<bean id="transactionManagerMybatis" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        <property name="dataSource" ref="dataSource" />
    </bean>
    

    <!-- hibernateJPA持久层配置 -->
    <!-- 注解自动映射 -->
    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"></bean>
    <!-- 配置JPA工厂 -->

   

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">

        <property name="dataSource" ref="dataSourceHw" />
        <property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />
        <property name="loadTimeWeaver">
            <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
        </property>
    </bean>
    <!-- 使用JPA的的事务 -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    
    
    <!-- 配置声明式事务:方法一,在Service实现类或者public实现方法上使用注解@Transactional,则此类或方法就会启用事务机制 -->
    <!-- mybatis事物 -->
    <tx:annotation-driven transaction-manager="transactionManagerMybatis" proxy-target-class="true" />
    <!-- JPA事物 -->
    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
    
    

    <!-- 配置多数据源 -->
<!--     <bean id="dynamicDataSource" -->
<!--         class="net.lantrack.framework.core.datasource.DynamicDataSource"> -->
<!--         <property name="targetDataSources"> -->
<!--             <map key-type="java.lang.String"> -->
<!--                 指定lookupKey和与之对应的数据源 -->
<!--                 <entry key="ds_hrms" value-ref="dataSource"></entry> -->
<!--                 <entry key="local" value-ref="dataSource1"></entry> -->
<!--             </map> -->
<!--         </property> -->
        <!-- 指定默认的数据源 -->
<!--         <property name="defaultTargetDataSource" ref="dataSource" /> -->
<!--     </bean> -->
    
    <!-- 配置使Spring采用CGLIB代理 -->
    <aop:aspectj-autoproxy proxy-target-class="true" />

    <!-- 需要注册的bean -->
    <bean class="net.lantrack.framework.core.util.SpringContextHolder"></bean>
    <!-- <import resource="spring-activiti.xml"></import> -->

</beans>


由于mybatis事物没有问题,JPA事物未注册,于是给俩个持久层配置事物时换了个位置,如下:

<!-- 配置声明式事务:方法一,在Service实现类或者public实现方法上使用注解@Transactional,则此类或方法就会启用事务机制 -->
    <!-- JPA事物 --><!-- 双持久层时,先注册JPA事物,在加载mybatis事物 -->
    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
    <!-- mybatis事物 -->

    <tx:annotation-driven transaction-manager="transactionManagerMybatis" proxy-target-class="true" />

最终问题解决,经过测试mybatis和JPA事物都可以正常运行!具体原因还待逐步分析,可能是spring代理的问题,待后续再研究

猜你喜欢

转载自blog.csdn.net/little_pig_lxl/article/details/80437488