Guanxing工程在后来为了避免写DAO,引入了JPA。为了避免影响老的工程,JPA使用了自己的事务管理器。
spring-service.xml
<!-- 事务配置 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" propagation="SUPPORTS" read-only="true" />
<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
<tx:method name="is*" propagation="SUPPORTS" read-only="true" />
<tx:method name="list*" propagation="SUPPORTS" read-only="true" />
<tx:method name="query*" propagation="SUPPORTS" read-only="true" />
<tx:method name="*" />
</tx:attributes>
</tx:advice>
<aop:config proxy-target-class="true">
<aop:pointcut id="serviceOperation"
expression="execution(* com.baidu.global.mobile.server.guanxing.service..*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" />
</aop:config>
<!-- PlatformTransactionManager,为了让Spring @SpringJUnit4ClassRunner @Transactional生效,id必须是transactionManager -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
spring-jpa.xml
<?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:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<!-- Configures Spring Data JPA and sets the base package of my DAOs. -->
<jpa:repositories
base-package="com.baidu.global.mobile.server.guanxing.monitor.repository" />
<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan"
value="com.baidu.global.mobile.server.guanxing.monitor.model" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
<!-- <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
/> <property name="generateDdl" value="${jpa.generateDdl}" /> <property name="databasePlatform"
value="${persistence.dialect}" /> </bean> -->
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
<tx:annotation-driven />
<!-- <bean id="persistenceExceptionTranslationPostProcessor" class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"
/> -->
</beans>
然后发现线上经常报JPA事务配置转换错误(具体报错信息但是没有记录下来,忘记了。。)。定位了一下,发现是因为id冲突了,
<!-- PlatformTransactionManager,为了让Spring @SpringJUnit4ClassRunner @Transactional生效,id必须是transactionManager -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
DataSourceTransactionManager和JpaTransactionManager的id都是系统默认的transactionManager。这样的结果就会导致一个被无视了。于是将JPA的改了一个id,变成:
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
但是发现JPA的所有更新操作都失效了,只有查询是可以的。该回去就可以了,所以可以确定是JPA的事务配置问题。Google了一下,发现Springside提供了Spring多事务管理器配置的模板工程:spring对多个transactionManager的支持已成熟,取消原来的显式定义。照着配置一下就可以了:
<!-- Configures Spring Data JPA and sets the base package of my DAOs. -->
<jpa:repositories
base-package="com.baidu.global.mobile.server.guanxing.monitor.repository"
transaction-manager-ref="txManager" />
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
<tx:annotation-driven transaction-manager="txManager"
proxy-target-class="true" />
注意 一定要同时配置<tx:annotation-driven transaction-manager="txManager">
,否则会报如下错误:
ErrorMessage: Could not open JPA EntityManager for transaction; nested exception is java.lang.IllegalStateException: Already value [org.springframework.jdbc.datasource.ConnectionHolder@11623292] for key [{ CreateTime:"2014-11-17 11:48:08", ActiveCount:2, PoolingCount:0, CreateCount:1, DestroyCount:0, CloseCount:4, ConnectCount:6, Connections:[ ] }] bound to thread [http-bio-80-exec-1]