gpt4 book ai didi

java - 无法使用 JpaTransactionManager 在 Spring 测试中保留实体

转载 作者:行者123 更新时间:2023-11-30 09:31:07 33 4
gpt4 key购买 nike

我正在尝试坚持使用一个实体。当我自己处理交易时,我的测试用例有效(数据保存在数据库中)。

public User saveUser(User user) {
getEm().getTransaction().begin();
getEm().persist(user);
getEm().getTransaction().commit();
return user;
}

(实体管理器来 self 的 DAO 类扩展的模板类)

当我配置 spring 来处理事务时,它停止持久化数据。

测试上下文.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">

<tx:annotation-driven transaction-manager="transactionManager"/>

<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="domainPU" />
<property name="loadTimeWeaver">
<bean
class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
</bean>

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://192.168.5.111/testdb" />
<property name="username" value="sdgdsgs" />
<property name="password" value="sdfgdsg" />
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory">
<ref local="entityManagerFactory" />
</property>
</bean>

</beans>

用户库测试:

@ContextConfiguration(locations = { "classpath:test-context.xml", "classpath:module-context.xml" })
@TransactionConfiguration(defaultRollback=false)
public class UsersRepositoryTest extends AbstractTransactionalTestNGSpringContextTests {

@Autowired
private UsersRepository usersRepository;

@Test(dependsOnMethods = {"findUserByLogin"})
public void registerUser() throws DataAccessException {
User myUser = getUserHomer();
usersRepository.saveUser(myUser);

User returnedUser = usersRepository.getUserByLogin(myUser.getLogin());

assertNotNull(returnedUser);
...
}
}

堆栈跟踪:

2012-10-22 08:26:26 org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean createNativeEntityManagerFactory
INFO: Building JPA container EntityManagerFactory for persistence unit 'domainPU'
2012-10-22 08:26:26 org.hibernate.annotations.common.Version <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {4.0.1.Final}
2012-10-22 08:26:26 org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {4.1.6.Final}
2012-10-22 08:26:26 org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
2012-10-22 08:26:26 org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
2012-10-22 08:26:26 org.hibernate.ejb.Ejb3Configuration configure
INFO: HHH000204: Processing PersistenceUnitInfo [
name: domainPU
...]
2012-10-22 08:26:26 org.hibernate.service.jdbc.connections.internal.ConnectionProviderInitiator instantiateExplicitConnectionProvider
INFO: HHH000130: Instantiating explicit connection provider: org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider
2012-10-22 08:26:27 org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect
2012-10-22 08:26:27 org.hibernate.engine.jdbc.internal.LobCreatorBuilder useContextualLobCreation
INFO: HHH000424: Disabling contextual LOB creation as createClob() method threw error : java.lang.reflect.InvocationTargetException
2012-10-22 08:26:27 org.hibernate.engine.transaction.internal.TransactionFactoryInitiator initiateService
INFO: HHH000268: Transaction strategy: org.hibernate.engine.transaction.internal.jdbc.JdbcTransactionFactory
2012-10-22 08:26:27 org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory <init>
INFO: HHH000397: Using ASTQueryTranslatorFactory
2012-10-22 08:26:27 org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization
INFO: Bean 'entityManagerFactory' of type [class org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2012-10-22 08:26:27 org.springframework.context.support.AbstractApplicationContext$BeanPostProcessorChecker postProcessAfterInitialization
INFO: Bean 'hibernateTranslator' of type [class org.springframework.orm.hibernate4.HibernateExceptionTranslator] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2012-10-22 08:26:27 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@5c28305d: defining beans [org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,entityManagerFactory,dataSource,transactionManager,org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor#0,hibernateTranslator,usersDao,zoneDao,usersRepository,zoneRepository,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0]; root of factory hierarchy
2012-10-22 08:26:27 org.springframework.test.context.transaction.TransactionalTestExecutionListener startNewTransaction
INFO: Began transaction (1): transaction manager [org.springframework.orm.jpa.JpaTransactionManager@3341b736]; rollback [false]
Hibernate: select user0_.id as id0_, user0_.active as active0_, user0_.creation_date as creation3_0_, user0_.email as email0_, user0_.last_login_date as last5_0_, user0_.login as login0_, user0_.password as password0_, user0_1_.AVATAR as AVATAR1_, user0_1_.FIRST_NAME as FIRST2_1_, user0_1_.ID as ID1_, user0_1_.LAST_NAME as LAST4_1_, case when user0_1_.id is not null then 1 when user0_.id is not null then 0 end as clazz_ from user user0_ left outer join client user0_1_ on user0_.id=user0_1_.id where user0_.login=?
Hibernate: select phone0_.id as id2_0_, phone0_.phone_number as phone2_2_0_, phone0_.user_id as user3_2_0_ from phone phone0_ where phone0_.id=?
Hibernate: select address0_.ID as ID6_0_, address0_.apartment_number as apartment2_6_0_, address0_.city as city6_0_, address0_.country as country6_0_, address0_.house_number as house5_6_0_, address0_.post_code as post6_6_0_, address0_.street as street6_0_ from address address0_ where address0_.ID=?
Hibernate: select user0_.id as id0_, user0_.active as active0_, user0_.creation_date as creation3_0_, user0_.email as email0_, user0_.last_login_date as last5_0_, user0_.login as login0_, user0_.password as password0_, user0_1_.AVATAR as AVATAR1_, user0_1_.FIRST_NAME as FIRST2_1_, user0_1_.ID as ID1_, user0_1_.LAST_NAME as LAST4_1_, case when user0_1_.id is not null then 1 when user0_.id is not null then 0 end as clazz_ from user user0_ left outer join client user0_1_ on user0_.id=user0_1_.id where user0_.login=?
2012-10-22 08:26:27 org.springframework.test.context.transaction.TransactionalTestExecutionListener endTransaction
INFO: Committed transaction after test execution for test context [[TestContext@63edf84f testClass = UsersRepositoryTest, testInstance = pl.eports.zonen.user.repository.UsersRepositoryTest@7e3bc473, testMethod = findUserByLogin@UsersRepositoryTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@1c493dca testClass = UsersRepositoryTest, locations = '{classpath:test-context.xml, classpath:module-context.xml}', classes = '{}', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader']]]
2012-10-22 08:26:27 org.springframework.test.context.transaction.TransactionalTestExecutionListener startNewTransaction
INFO: Began transaction (2): transaction manager [org.springframework.orm.jpa.JpaTransactionManager@3341b736]; rollback [false]
Hibernate: select user0_.id as id0_, user0_.active as active0_, user0_.creation_date as creation3_0_, user0_.email as email0_, user0_.last_login_date as last5_0_, user0_.login as login0_, user0_.password as password0_, user0_1_.AVATAR as AVATAR1_, user0_1_.FIRST_NAME as FIRST2_1_, user0_1_.ID as ID1_, user0_1_.LAST_NAME as LAST4_1_, case when user0_1_.id is not null then 1 when user0_.id is not null then 0 end as clazz_ from user user0_ left outer join client user0_1_ on user0_.id=user0_1_.id where user0_.login=?
2012-10-22 08:26:27 org.springframework.test.context.transaction.TransactionalTestExecutionListener endTransaction
INFO: Committed transaction after test execution for test context [[TestContext@63edf84f testClass = UsersRepositoryTest, testInstance = pl.eports.zonen.user.repository.UsersRepositoryTest@7e3bc473, testMethod = registerUser@UsersRepositoryTest, testException = java.lang.AssertionError: expected object to not be null, mergedContextConfiguration = [MergedContextConfiguration@1c493dca testClass = UsersRepositoryTest, locations = '{classpath:test-context.xml, classpath:module-context.xml}', classes = '{}', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader']]]
PASSED: findUserByLogin
FAILED: registerUser
java.lang.AssertionError: expected object to not be null
at org.testng.Assert.fail(Assert.java:94)
...

从stacktrace可以看出,事务似乎开始和结束了,但是没有产生sql插入,也没有数据插入db(数据回滚设置为false)

我已经尝试在 persist() 之后强制刷新数据,但 spring 管理的事务似乎到那时已经完成。

我在论坛上寻找过类似的问题,但无济于事。如有必要,我可以提供更多代码。

我正在使用 Spring 3.1.2 和 Hibernate 4.1.6.Final

更新:

DAO: (@Transactional 注解暂时放在服务层)

@Repository
public class JpaUsersDAO extends JpaDAOTemplate<User> implements UsersDAO {

public JpaUsersDAO(EntityManagerFactory factory) {
super(factory.createEntityManager(), User.class);
}

@Transactional
public User saveUser(User user) {
getEm().persist(user);
return user;
}
}

DAOT 模板:

public abstract class JpaDAOTemplate<T extends Serializable> {

private EntityManager em;

private Class<T> clazz;

public JpaDAOTemplate(EntityManager em, final Class<T> clazz) {
this.em = em;
this.clazz = clazz;
}

public EntityManager getEm() {
return em;
}

public T getById(Integer id) {...}
...
}

bean 定义:

<bean id="usersDao"
class="pl.package.user.dao.impl.JpaUsersDAO">
<constructor-arg ref="entityManagerFactory" />
</bean>

似乎事务在选择之后和调用 getEm().persist() 之前的某处丢失了 - org.hibernate.ejb.TransactionImpl#tx is null 在调用 persist() 时,但它是org.hibernate.engine.transaction.internal.jdbc.JDBCTransaction 在调用之前(当调用 sql select 语句时)

更新 2调试级堆栈跟踪:

[2012-10-23 11:15:14,546]DEBUG 38629[main] - org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:365) - Creating new transaction with name [registerUser]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
[2012-10-23 11:15:33,252]DEBUG 57335[main] - org.hibernate.internal.SessionImpl.<init>(SessionImpl.java:316) - Opened session at timestamp: 13509837332
[2012-10-23 11:15:33,252]DEBUG 57335[main] - org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:368) - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl@18025c5c] for JPA transaction
[2012-10-23 11:15:40,085]DEBUG 64168[main] - org.hibernate.engine.transaction.spi.AbstractTransactionImpl.begin(AbstractTransactionImpl.java:158) - begin
[2012-10-23 11:15:40,101]DEBUG 64184[main] - org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:295) - Obtaining JDBC connection
[2012-10-23 11:15:40,101]DEBUG 64184[main] - org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:301) - Obtained JDBC connection
[2012-10-23 11:15:40,101]DEBUG 64184[main] - org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.java:69) - initial autocommit status: true
[2012-10-23 11:15:40,101]DEBUG 64184[main] - org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.java:71) - disabling autocommit
[2012-10-23 11:16:06,934]DEBUG 91017[main] - org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:407) - Not exposing JPA transaction [org.hibernate.ejb.EntityManagerImpl@18025c5c] as JDBC transaction because JpaDialect [org.springframework.orm.jpa.DefaultJpaDialect@5f343722] does not support JDBC Connection retrieval
[2012-10-23 11:16:06,934]DEBUG 91017[main] - org.springframework.test.context.transaction.TransactionalTestExecutionListener.isRollback(TransactionalTestExecutionListener.java:357) - No method-level @Rollback override: using default rollback [false] for test context [[TestContext@5809fdee testClass = UsersRepositoryTest, testInstance = pl.eports.zonen.user.repository.UsersRepositoryTest@3fde891b, testMethod = registerUser@UsersRepositoryTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@77fe4169 testClass = UsersRepositoryTest, locations = '{classpath:test-context.xml, classpath:module-context.xml}', classes = '{}', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader']]]
[2012-10-23 11:16:06,934] INFO 91017[main] - org.springframework.test.context.transaction.TransactionalTestExecutionListener.startNewTransaction(TransactionalTestExecutionListener.java:275) - Began transaction (1): transaction manager [org.springframework.orm.jpa.JpaTransactionManager@37977909]; rollback [false]
[2012-10-23 11:17:08,103]DEBUG152186[main] - org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:245) - Returning cached instance of singleton bean 'org.springframework.transaction.interceptor.TransactionInterceptor#0'
[2012-10-23 11:17:08,118]DEBUG152201[main] - org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource.getTransactionAttribute(AbstractFallbackTransactionAttributeSource.java:106) - Adding transactional method 'saveUser' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
[2012-10-23 11:17:08,118]DEBUG152201[main] - org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:245) - Returning cached instance of singleton bean 'txManager'
[2012-10-23 11:17:27,073]DEBUG171156[main] - org.springframework.orm.jpa.JpaTransactionManager.doGetTransaction(JpaTransactionManager.java:331) - Found thread-bound EntityManager [org.hibernate.ejb.EntityManagerImpl@18025c5c] for JPA transaction
[2012-10-23 11:18:04,031]DEBUG208114[main] - org.springframework.transaction.support.AbstractPlatformTransactionManager.handleExistingTransaction(AbstractPlatformTransactionManager.java:470) - Participating in existing transaction

最后更新:

问题出在我将 EntityManagerFactory 注入(inject)到我的 DAO 中的方式。我使用 applicationContext.xml 配置文件来注入(inject)它(这样 EMF 不参与事务)。为了让它工作,我将我的 DAO 类更改为:

@Repository
public class JpaUsersDAO extends JpaDAOTemplate<User> implements UsersDAO {

@PersistenceContext
private EntityManager em;
...
}

最佳答案

您正在使用 Spring 3.0。我不清楚你的编码 public User saveUser(User user) 方法。即使您使用 Spring 3.0,您也可以自己处理事务(Bean Management Transaction)。它只需要使用 @Transactional(propagation = Propagation.REQUIRED) 注解。根据您的流程更改传播类型。

DAO 示例:

GroupDAO.java

@Repository("GroupDAO")
public class GroupDAO {
@PersistenceContext
protected EntityManager em;

@Transactional(propagation = Propagation.REQUIRED)
public void insert(Group group) {
try {
em.persist(group);
em.flush();
} catch (PersistenceException pe) {
}
}
}

带有 EclipseLink JPA 的 spring-bean.xml <-- 仅供引用。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:faces="http://www.springframework.org/schema/faces"
xmlns:int-security="http://www.springframework.org/schema/integration/security"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:sec="http://www.springframework.org/schema/security"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/integration/security http://www.springframework.org/schema/integration/security/spring-integration-security-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/faces http://www.springframework.org/schema/faces/spring-faces-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">

<context:annotation-config/>
<context:component-scan base-package="your-package"/>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.5.111/testdb"/>
<property name="username" value="your-username"/>
<property name="password" value="your-password"/>
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<!-- <property name="dataSource" ref="dataSource"/>-->
<property name="persistenceUnitName" value="domainPU"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect"/>
</property>
<property name="jpaPropertyMap">
<props>
<prop key="eclipselink.weaving">false</prop>
</props>
</property>

<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver">
</bean>
</property>
</bean>

<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="databasePlatform" value="org.eclipse.persistence.platform.database.MySQLPlatform"/>
<!-- <property name="databasePlatform" value="org.eclipse.persistence.platform.database.OraclePlatform" />-->
<property name="generateDdl" value="false"/>
<property name="showSql" value="true"/>
</bean>
</beans>

关于java - 无法使用 JpaTransactionManager 在 Spring 测试中保留实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13006398/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com