项目中同时使用到了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代理的问题,待后续再研究