2 friday571 Friday571 于 2014.07.24 23:37 提问

spring+jpa开发,事务管理遇到奇葩问题,求码友共同探讨
最近用到spring +jpa eclipselink+ struts做开发,遇到一个无解的问题,业务层中一个用事务管理的方法中,一个受管的对象(fh)更新其一个复杂型属性(country)时居然会将country重新插入到数据库。!!!

public String updateSsss(){
Farmhouse fh = farmDao.findById(xxx);//前提1
// Farmhouse fh = new Farmhouse();//前提2
Country country = countryDao.findById(yyy);//行3
fh.setCountry(country);//关键行4
farmDao.update(fh);//行5
}

这个方法用事务管理了的,首先行5注释与否不影响结果,然后如果选择前提2的话,正常执行;如果选择前提1的话,它会将country的内容重新insert一次,导致问题的是关键行4(如果注释则不会有问题),当然,最终主键重复了插不进去,事务也回滚了。
简单说就是如果对象已存在, 更改它的关联对象就会引发插入。
小生封装了一个基本的DAO方法,其中update内部执行persist();  farmDao,countryDao都是继承基本DAO。

我附上spring事务配置代码:

<bean
    class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="jpaDialect" 
    class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect " /> 

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
    <property name="username" value="root"/>
    <property name="password" value="111111"/>
    <property name="url" value="jdbc:mysql://111.16.253.66:3306/XXX"/>
</bean>

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="dataSource" ref="dataSource" />
    <property name="jpaDialect" ref="jpaDialect" /> 
    <property name="jpaVendorAdapter">
        <bean
            class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
            <property name="database" value="MYSQL" />
            <property name="showSql" value="true" />
            <property name="databasePlatform" value="org.eclipse.persistence.platform.database.MySQLPlatform" /> 
        </bean>
    </property>
</bean>

<bean id="transactionManager"
    class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
    <property name="nestedTransactionAllowed" value="true"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
   <tx:attributes>
        <tx:method name="submit*" />
        <tx:method name="add*" />
        <tx:method name="delete*" />
        <tx:method name="update*" />
   </tx:attributes>
</tx:advice>

<aop:config>
  <aop:pointcut id="pointcut"  
    expression="execution(* service.impl.*.*(..))" />
  <aop:advisor advice-ref="txAdvice"
    pointcut-ref="pointcut" />
</aop:config>  

1个回答

Friday571
Friday571   2014.07.25 16:07

找到答案了,那是因为findById( id )这个函数里面,忘了将用完的EntityManager clear一下

Csdn user default icon
上传中...
上传图片
插入图片