Reputation: 6660
Hibernate is throwing a javax.persistence.TransactionRequiredException
inside one of my test methods. But, according to the logs, there is a transaction in progress (created by Spring). Has anyone any idea of what I could be missing?
See the logs:
INFO org.springframework.test.context.transaction.TransactionalTestExecutionListener - Began transaction (1) for test context [DefaultTestContext@506dd108 testClass = FooTest, testInstance = com.example.FooTest@59b68d78, testMethod = test@FooTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@6001ef4b testClass = FooTest, locations = '{classpath:/appContext.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]; transaction manager [org.springframework.jdbc.datasource.DataSourceTransactionManager@1f05562b]; rollback [true]
INFO com.example.FooTest - Test started.
INFO org.springframework.test.context.transaction.TransactionalTestExecutionListener - Rolled back transaction after test execution for test context [DefaultTestContext@506dd108 testClass = FooTest, testInstance = com.example.FooTest@59b68d78, testMethod = test@FooTest, testException = javax.persistence.TransactionRequiredException: Executing an update/delete query, mergedContextConfiguration = [MergedContextConfiguration@6001ef4b testClass = FooTest, locations = '{classpath:/appContext.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]
My test class is:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/appContext.xml")
@Transactional
public class FooTest {
private static final Logger logger = LoggerFactory.getLogger(FooTest.class);
@PersistenceContext
private EntityManager em;
@Test
public void test() {
logger.info("Test started.");
em.createQuery("delete from Foo").executeUpdate();
logger.info("Test finished.");
}
}
My appContext.xml is:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">
<bean id="embeddedEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="embeddedDataSource"/>
<property name="persistenceUnitName" value="Foo" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="embeddedDataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<jdbc:embedded-database id="embeddedDataSource">
<jdbc:script location="classpath:schema.sql" encoding="UTF-8"/>
<jdbc:script location="classpath:test-data.sql" encoding="UTF-8"/>
</jdbc:embedded-database>
</beans>
My META-INF/persistence.xml is rather straightforward:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="Foo">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>com.example.Foo</class>
</persistence-unit>
</persistence>
And, finally, the stacktrace (filtered):
javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.jpa.spi.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:71)
at com.example.FooTest.test(FooTest.java:27)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:232)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:175)
Upvotes: 1
Views: 2336
Reputation: 6660
I was using the wrong transaction manager. The solution was to replace:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="embeddedDataSource"/>
</bean>
by
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="dataSource" ref="embeddedDataSource"/>
</bean>
Many thanks to M. Deinum for his comment. Had he posted it as an answer, I would have accepted it.
Upvotes: 1
Reputation: 556
I agree that you should be using a JpaTransactionManager. I also believe you need to mark the method transactional:
@Transactional
public void test() {
You can debug it by hard coding the transaction begin and commit in your test. It looks like the exception in pointing to em.createQuery.... (thus hard code the transaction there, if you want to diagnose further).
Hope that helps a little:)
Upvotes: 1