无法在spring中打开JPA EntityManager进行事务处理

时间:2012-11-11 02:11:28

标签: spring hibernate java-ee jpa jta

我正在使用JPA Hibernate 4.1.7和Spring 3.1.3构建测试应用程序。

我在jta上获得一个NPE导致JPA EntityManager失败,这里是堆栈跟踪

    DEBUG TestContext - Retrieved ApplicationContext for test class [class cvut.dp.foodtables.service.FoodServiceImplTest] from cache with key [[MergedContextConfiguration@61cc1457 testClass = FoodServiceImplTest, locations = '{classpath:/WEB-INF/context/applicationContext.xml}', classes = '{}', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader']].
DEBUG DefaultListableBeanFactory - Returning cached instance of singleton bean 'txManager'
DEBUG JpaTransactionManager - Creating new transaction with name [testSome]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
DEBUG SessionImpl - Opened session at timestamp: 13525989368
DEBUG TransactionCoordinatorImpl - Skipping JTA sync registration due to auto join checking
DEBUG AbstractEntityManagerImpl - Looking for a JTA transaction to join
WARN  TestContextManager - Caught exception while allowing TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener@16f88474] to process 'before' execution of test method [public void cvut.dp.foodtables.service.FoodServiceImplTest.testSome()] for test instance [cvut.dp.foodtables.service.FoodServiceImplTest@3210a146]
org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is java.lang.NullPointerException
    at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:427)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371)
    at org.springframework.test.context.transaction.TransactionalTestExecutionListener$TransactionContext.startTransaction(TransactionalTestExecutionListener.java:514)
    at org.springframework.test.context.transaction.TransactionalTestExecutionListener.startNewTransaction(TransactionalTestExecutionListener.java:272)
    at org.springframework.test.context.transaction.TransactionalTestExecutionListener.beforeTestMethod(TransactionalTestExecutionListener.java:165)
    at org.springframework.test.context.TestContextManager.beforeTestMethod(TestContextManager.java:358)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:73)
    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:231)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    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:300)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:53)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:123)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:104)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:164)
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:110)
    at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:175)
    at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcessWhenForked(SurefireStarter.java:107)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:68)
Caused by: java.lang.NullPointerException
    at org.hibernate.engine.transaction.internal.jta.JtaStatusHelper.getStatus(JtaStatusHelper.java:73)
    at org.hibernate.engine.transaction.internal.jta.JtaStatusHelper.isActive(JtaStatusHelper.java:115)
    at org.hibernate.engine.transaction.internal.jta.CMTTransaction.join(CMTTransaction.java:149)
    at org.hibernate.ejb.AbstractEntityManagerImpl.joinTransaction(AbstractEntityManagerImpl.java:1220)
    at org.hibernate.ejb.AbstractEntityManagerImpl.postInit(AbstractEntityManagerImpl.java:178)
    at org.hibernate.ejb.EntityManagerImpl.<init>(EntityManagerImpl.java:89)
    at org.hibernate.ejb.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:179)
    at org.springframework.orm.jpa.JpaTransactionManager.createEntityManagerForTransaction(JpaTransactionManager.java:445)
    at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:366)
    ... 31 more
DEBUG DirtiesContextTestExecutionListener - After test method: context [[TestContext@5579d6f9 testClass = FoodServiceImplTest, testInstance = cvut.dp.foodtables.service.FoodServiceImplTest@3210a146, testMethod = testSome@FoodServiceImplTest, testException = org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is java.lang.NullPointerException, mergedContextConfiguration = [MergedContextConfiguration@61cc1457 testClass = FoodServiceImplTest, locations = '{classpath:/WEB-INF/context/applicationContext.xml}', classes = '{}', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader']]], class dirties context [false], class mode [null], method dirties context [false].
DEBUG DirtiesContextTestExecutionListener - After test class: context [[TestContext@5579d6f9 testClass = FoodServiceImplTest, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [MergedContextConfiguration@61cc1457 testClass = FoodServiceImplTest, locations = '{classpath:/WEB-INF/context/applicationContext.xml}', classes = '{}', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader']]], dirtiesContext [false].
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 11.134 sec <<< FAILURE!

我已经将该错误用Google搜索过,但仍无法找到任何解决方案。

以下是测试:

package cvut.dp.foodtables.service;

import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

public class FoodServiceImplTest extends BaseServiceTest
{
    @Autowired
    private FoodService foodService;

    public FoodServiceImplTest()
    {
        super();
    }

    @Test
    public void testSome()
    {        
        Long id = foodService.addFood("test", 15, "test");
        assertEquals(1, foodService.getAllFood().size());
    }
}

扩展

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
    "classpath:/WEB-INF/context/applicationContext.xml"})
@TransactionConfiguration(defaultRollback=true, transactionManager="txManager")
@Transactional //extend the transactions to whole tests in order to rollback the tests
public class BaseServiceTest
{
    public BaseServiceTest()
    {
    }
}

我认为错误是在我的配置中的某处,所以我不会在这里发布所有的来源......

这是我的applicationContext.xml(编辑:更改为3.1.xds文件,没有更改)

<!--<?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:webflow="http://www.springframework.org/schema/webflow-config" 
       xmlns:faces="http://www.springframework.org/schema/faces" 
       xmlns:p="http://www.springframework.org/schema/p" 
       xmlns:context="http://www.springframework.org/schema/context" 
       xmlns:tx="http://www.springframework.org/schema/tx" 
       xmlns:aop="http://www.springframework.org/schema/aop" 

       xsi:schemaLocation=" http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
            http://www.springframework.org/schema/webflow-config 
            http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd 
            http://www.springframework.org/schema/faces 
            http://www.springframework.org/schema/faces/spring-faces-2.0.xsd 
            http://www.springframework.org/schema/context 
            http://www.springframework.org/schema/context/spring-context-2.5.xsd 
            http://www.springframework.org/schema/tx 
            http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" 
       default-autowire="byType"
>

<!-- Enable annotions -->
    <context:annotation-config />
    <context:component-scan base-package="cvut.dp.foodtables"/>
<!-- @Configurable -->
    <context:spring-configured/> 

<!-- Property files -->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>/WEB-INF/properties/jdbc.properties</value>
                <value>/WEB-INF/properties/jpa.properties</value>
            </list>
        </property>
    </bean>        
<!-- JDBC data source -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="initialSize" value="2" />
        <property name="minIdle" value="2" />
    </bean>
<!-- JPA settings --> 
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="databasePlatform" value="${jpa.platform}"/>
                <property name="generateDdl" value="true"/>
                <property name="showSql" value="true"/>

            </bean>
        </property>
        <property name="packagesToScan" value="cvut.dp.foodtables" />
    </bean> 

<!-- Define transaction manager -->
    <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

<!-- @Transactional support-->
    <tx:annotation-driven transaction-manager="txManager" /> 

</beans>

我没有persistence.xml

jdbc.properties:

jdbc.driverClassName=org.hibernate.dialect.MySQLDialect
jdbc.url=jdbc:mysql://localhost:3306/FoodTables
jdbc.username=root

jpa.properties:

jpa.platform=org.hibernate.dialect.MySQLDialect

这是web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
     version="3.0">


<!-- SPRING -->
    <context-param>
        <description>Spring config files</description>
        <param-name>contextConfigLocation</param-name>
        <param-value>
                /WEB-INF/context/*.xml
        </param-value>
    </context-param>

    <listener>
        <description>Loads Spring on server start</description>
        <listener-class>
               org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

    <listener>
        <description>Request -> thread association</description>
        <listener-class>
               org.springframework.web.context.request.RequestContextListener
        </listener-class>
    </listener>  
<!-- SPRING END --> 
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
</web-app>

我的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>cvut.dp</groupId>
    <artifactId>FoodTables</artifactId>
    <version>1.0</version>
    <packaging>war</packaging>

    <name>FoodTables</name>

    <properties>
        <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>4.1.7.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-documentation</artifactId>
            <version>3.6.0.Beta2</version>
            <type>pom</type>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>3.1.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>3.1.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>3.1.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>3.1.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>3.1.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>3.1.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.16</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.7.1</version>
        </dependency>
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>4.1.8.Final</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <artifactId>hibernate-jpa-2.0-api</artifactId>
            <groupId>org.hibernate.javax.persistence</groupId>
            <type>jar</type>
            <version>1.0.1.Final</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.21</version>
        </dependency>
    </dependencies>

    <build>
        <testResources>
            <testResource>
                <directory>src/test/resources</directory>
                <filtering>true</filtering>
            </testResource>

            <testResource>
                <directory>src/main/webapp</directory>

                <filtering>true</filtering>

                <includes>
                    <include>**/context/applicationContext*.xml</include>
                    <include>**/properties/*.properties</include>
                </includes>
            </testResource>
        </testResources>  
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                    <compilerArguments>
                        <endorseddirs>${endorsed.dir}</endorseddirs>
                    </compilerArguments>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.1.1</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.1</version>
                <executions>
                    <execution>
                        <phase>validate</phase>
                        <goals>
                            <goal>copy</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${endorsed.dir}</outputDirectory>
                            <silent>true</silent>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>javax</groupId>
                                    <artifactId>javaee-endorsed-api</artifactId>
                                    <version>6.0</version>
                                    <type>jar</type>
                                </artifactItem>
                            </artifactItems>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

最常见的答案是我应该在persistance.xml中设置hibernate.transaction.jta.platform属性,这是我没有的。这是我的第一个Java EE应用程序,我真的不知道我在做什么。但是这个错误令人沮丧。

4 个答案:

答案 0 :(得分:5)

我遇到了同样的问题。解决方案是在xml配置中使用default-autowire =“byName”而不是“byType”。如果你有“byType”,那么Spring会自动将LocalContainerEntityManagerFactoryBean中的属性“jtaDataSource”与你定义的数据源bean一起自动装配。

答案 1 :(得分:1)

虽然jens的回答是正确的并且解决了您的问题,但我只是想补充一点,您不必为此更改默认自动装配。你也可以在每个bean上设置它。

- (void)viewDidLoad {
    [super viewDidLoad];
    UINib *nib = [UINib nibWithNibName:@"my_TableViewCell" bundle:nil];
    [[self tableView] registerNib:nib forCellReuseIdentifier:@"tableViewCell"];

    NSLog(@"%@", self.oManagedObjectContext);
}

现在除了“entityManagerFactory”

之外,你还在所有bean上都有byType-autowiring

答案 2 :(得分:0)

这不是jdbc.projects中定义的密码条目。

  

&lt; property name =“password”value =“$ {jdbc.password}”/&gt;

最好为项目创建一个独立的用户/密码,不要在生产中使用root。

答案 3 :(得分:0)

尝试添加“META-INF / persistence.xml”:

    <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
    <persistence-unit name="myUnit" transaction-type="RESOURCE_LOCAL">
    </persistence-unit>
    </persistence>

在org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo第91行(PersistenceUnitTransactionType getTransactionType())中设置断点也可以帮助您确定spring认为您拥有jta-datasource或事务类型的原因。