【发布时间】:2016-05-02 20:50:32
【问题描述】:
我计划从 Spring 4.2.1.RELEASE + Hibernate 4.2.19.Final 迁移到 4.2.1.RELEASE + Hibernate 5.0.7.Final。
我创建了一个简单的项目available on Github 来测试新的 Hibernate 版本,但遇到了一个问题:在我的集成测试中,我用 sql 文件中的两行初始化了一个 HSQLDB。关键是当我的 Hibernate 版本是 4.2.19.Final 时,来自ExampleIntegrationTRTest 的所有测试都通过了。但是对于 5.0.7.Final,第一个测试 (testExampleInsertWithRollback) 失败:
scripts/initData.sql
INSERT INTO TFOEMPLE(FOEMPLE_ID, FOEMPLE_NAME) values(1, 'Louis');
INSERT INTO TFOEMPLE(FOEMPLE_ID, FOEMPLE_NAME) values(2, 'Maria');
ExampleIntegrationTRTest.testExampleInsertWithRollback:此测试在 4.1 中通过,但由于 5.0.7.Final 中的 javax.persistence.EntityExistsException 而失败。显然,它尝试创建新的 FooEmployee,并为其分配一个 id 1,该 id 作为初始化的一部分已经存在于数据库中。
@ContextConfiguration({ "/spring/test/test-context.xml" })
@Test
public class ExampleIntegrationTRTest extends AbstractTransactionalTestNGSpringContextTests {
@Transactional
public void testExampleInsertWithRollback() {
FooEmployee response = null;
response = fooUserService.getEmployee(1);
//response is FooEmpleado ( BaseEntity ( FooEmployee@590013c7 id = 1 ) id = 1 nombre = Louis )
FooEmployee newFoo = new FooEmployee();
newFoo.setName("James");
createdFooWithRollback = fooUserService.createEmployee(newFoo).getId();
//The line above throws the exception
assertNotNull(createdFooWithRollback);
EntityManagerHolder holder = (EntityManagerHolder)TransactionSynchronizationManager.getResource(entityManagerFactory);
EntityManager em = holder.getEntityManager();
em.flush();
em.clear();
response = null;
response = fooUserService.getEmployee(createdFooWithRollback);
assertNotNull(response);
assertEquals(response.getId(), createdFooWithRollback);
assertEquals(response.getName(), "James");
}
堆栈跟踪
org.springframework.dao.DataIntegrityViolationException: A different object with the same identifier value was already associated with the session : [com.codependent.s4h5.entity.FooEmployeeEntity#1]; nested exception is javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [com.codependent.s4h5.entity.FooEmployeeEntity#1]
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:410)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:223)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:417)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:131)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy52.save(Unknown Source)
at com.codependent.s4h5.service.impl.FooUserServiceImpl.createEmployee(FooUserServiceImpl.java:36)
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.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy57.createEmployee(Unknown Source)
at com.codependent.s4h5.ExampleIntegrationTRTest.testExampleInsertWithRollback(ExampleIntegrationTRTest.java:47)
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.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:85)
at org.testng.internal.MethodInvocationHelper$1.runTestMethod(MethodInvocationHelper.java:200)
at org.springframework.test.context.testng.AbstractTestNGSpringContextTests.run(AbstractTestNGSpringContextTests.java:175)
at org.testng.internal.MethodInvocationHelper.invokeHookable(MethodInvocationHelper.java:212)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:689)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:882)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1189)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:124)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:108)
at org.testng.TestRunner.privateRun(TestRunner.java:767)
at org.testng.TestRunner.run(TestRunner.java:617)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:348)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:343)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:305)
at org.testng.SuiteRunner.run(SuiteRunner.java:254)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
at org.testng.TestNG.run(TestNG.java:1057)
at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)
Caused by: javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [com.codependent.s4h5.entity.FooEmployeeEntity#1]
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1664)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1602)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1608)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1152)
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:293)
at com.sun.proxy.$Proxy47.persist(Unknown Source)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:439)
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.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:483)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:468)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:440)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
... 49 more
Spring 的 test-context.xml
<tx:annotation-driven order="0" />
<!-- Drives transactions using datasource transaction manager -->
<bean name="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="mainEntityManagerFactory" />
</bean>
<bean id="mainEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="mainPersistenceUnit"/>
<property name="dataSource" ref="mainDataSource"/>
<property name="packagesToScan" value="com.codependent.s4h5.entity"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.hbm2ddl.auto">create-drop</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.import_files">scripts/initData.sql</prop>
</props>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
</property>
</bean>
<import resource="classpath:com/codependent/s4h5/spring/library.xml" />
<jdbc:embedded-database id="mainDataSource" type="HSQL"/>
<jpa:repositories base-package="com.codependent.s4h5.dao" entity-manager-factory-ref="mainEntityManagerFactory"/>
<context:component-scan base-package="com.codependent.s4h5.service.impl" />
<context:component-scan base-package="com.codependent.s4h5.mapper" />
<bean id="dozerMapper" class="org.dozer.spring.DozerBeanMapperFactoryBean"/>
项目 pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.codependent.s4h5</groupId>
<artifactId>spring4-hibernate5</artifactId>
<version>0.0.1-SNAPSHOT</version>
<description>Test</description>
<dependencyManagement>
<dependencies>
<!-- SPRING DATA -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-releasetrain</artifactId>
<version>${spring-data-releasetrain-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- SPRING -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring-version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<!-- HIBERNATE -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate-version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate-version}</version>
</dependency>
<!-- DOZER -->
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<version>5.5.1</version>
</dependency>
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer-spring</artifactId>
<version>5.5.1</version>
</dependency>
<!-- log system: slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j-version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${slf4j-version}</version>
<optional>true</optional>
<scope>runtime</scope>
</dependency>
<!-- TEST dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng-version}</version>
<type>jar</type>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>${powermock-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-testng</artifactId>
<version>${powermock-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb-j5</artifactId>
<version>2.2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>${log4j-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>${jboss-logging-version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.kubek2k</groupId>
<artifactId>springockito-annotations</artifactId>
<version>1.0.9</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<spring-version>4.2.1.RELEASE</spring-version>
<spring-data-releasetrain-version>Gosling-SR1</spring-data-releasetrain-version>
<hibernate-version>4.2.19.Final</hibernate-version>
<testng-version>6.8.17</testng-version>
<powermock-version>1.6.2</powermock-version>
<slf4j-version>1.7.7</slf4j-version>
<log4j-version>2.2</log4j-version>
<jboss-logging-version>3.2.1.Final</jboss-logging-version>
</properties>
</project>
BaseEntity.java
@SuppressWarnings("serial")
public abstract class BaseEntity<IdType extends Serializable> implements Serializable {
public abstract IdType getId();
public abstract void setId(IdType id);
}
FooEmployeeEntity.java
@Entity
@Table(name="TFOEMPLE")
public class FooEmployeeEntity extends BaseEntity<Integer> {
private static final long serialVersionUID = 2583160744316336577L;
@Id
@Column(name="FOEMPLE_ID")
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id ;
@Column(name="FOEMPLE_NAME")
private String name;
@ManyToOne
@JoinColumn(name="FOEMPLE_FODEPAR_ID")
private FooDepartmentEntity department;
//Getters-Setters
FooDepartmentEntity.java
@Entity
@Table(name="TFODEPAR")
public class FooDepartmentEntity extends BaseEntity<Integer> {
private static final long serialVersionUID = 2583160744316336577L;
@Id
@Column(name="FODEPAR_ID")
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id ;
@Column(name="FODEPAR_NAME")
private String name;
@OneToMany(mappedBy="department",cascade={CascadeType.MERGE,CascadeType.REFRESH, CascadeType.PERSIST, CascadeType.DETACH})
private List<FooEmployeeEntity> employees;
//Getters-Setters
【问题讨论】:
-
我测试了您的代码并将 Hibernate 版本修改为 5.0.7.Final。当我单独运行
testExampleScript时,它工作正常(与您所说的响应为空相反)。但是,当我运行所有测试用例时,就会出现问题。您确定您遇到的问题只是响应未通过空测试吗? -
@Bnrdo 感谢您试一试。你是绝对正确的,我被这么多的版本更改和东西搞混了。我用实际问题更新了问题:Hibernate 5 分配了一个不正确的 id,它与测试数据库中已经存在的另一个冲突。同样,在 Hibernate 4.2.19.Final 中测试通过,没有任何问题。