Spring Entity bean未知。使用新的Spring 3.1 packagesToScan属性而没有persistence.xml

时间:2012-04-26 10:19:20

标签: java spring jpa spring-data-jpa

我的EclipseLink和Spring(MVC和spring-data)版本3.1.1设置的另一个问题:

我试图让JPA在没有使用this article的persistence.xml文件的情况下工作。在文章中它说:

  

通常,JPA定义了一个持久性单元   META-INF / persistence.xml文件。从Spring 3.1开始,这个XML文件   不再需要 - LocalContainerEntityManagerFactoryBean   现在支持要扫描的包的'packagesToScan'属性   可以指定@Entity类。

     

persistence.xml文件是要删除的最后一段XML -   现在,JPA可以完全设置,没有XML。

我知道如果有人使用persistence.xml文件,那么这里的所有Entity类都应该在这里声明。但是,我正在尝试使用packagesToScan属性。下面是完整的启动日志和向servlet发出一个请求后产生的错误,该请求最终尝试在数据库中创建新用户。它似乎没有认识到User对象是一个实体。由于我对Spring没有什么经验,我想知道是否有人,首先可以发现我正在制造的错误,但除此之外,知道调试这个的最佳方法。我想知道EntityManagerFactory已经识别出哪些Entity对象。

我的备份选项是切换到使用persistence.xml(实际上还没有尝试过)但是如果可能的话我想摆脱它(少担心一个XML文件)。

更新:我根据Sean Patrick Floyd的回答,在推荐配置更改为entityManagerFactory之后更新了错误日志,但这并没有解决主要问题。我还尝试了另一种方法,通过创建一个persistence.xml文件(旧的和更常见的方式)来实现这一点,并在我访问的servlet中添加了一小段测试代码来启动它功能。 所以现在我的servlet中有一些代码:

User user = new User();
user.setFirstName("John");
user.setLastName("Doe");
// user = userService.addUser(user);

EntityManagerFactory emf = Persistence.createEntityManagerFactory("proxiPU");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(user); 
em.getTransaction().commit();
em.close();
emf.close();

这个persistence.xml文件:

<?xml version="1.0" encoding="UTF-8" ?>
<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" xmlns="http://java.sun.com/xml/ns/persistence">

    <persistence-unit name="proxiPU" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <class>com.proxi.user.User</class>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
            <property name="eclipselink.jdbc.driver" value="org.hsqldb.jdbcDriver"/>
            <property name="eclipselink.jdbc.url" value="jdbc:hsqldb:file:\Users\nly31175\hsqldb;shutdown=true"/>
            <property name="eclipselink.jdbc.user" value="proxi"/>
            <property name="eclipselink.jdbc.password" value=""/>
            <property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.HSQLPlatform"/>
            <property name="eclipselink.logging.level" value="FINEST"/>
            <property name="eclipselink.orm.throw.exceptions" value="true"/>
            <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
            <property name="eclipselink.ddl-generation.output-mode" value="database"/>
        </properties>
    </persistence-unit>
</persistence>

这实际上有效,所以我现在想知道EntityManagerFactory初始化的方式是否存在问题。我已经包含了应该执行数据库相关内容的UserService类的代码。

这是完整的启动日志(包括错误):

INFO: Reloading Context with name [/proxi] is completed
INFO : com.proxi.controller.HomeController - Welcome home! The client locale is en_GB
[EL Info]: 2012-04-26 15:17:35.066--ServerSession(313687096)--Thread(Thread[http-bio-8980-exec-3,5,main])--EclipseLink, version: Eclipse Persistence Services - 2.2.0.v20110202-r8913
[EL Config]: 2012-04-26 15:17:35.079--ServerSession(313687096)--Connection(1182807222)--Thread(Thread[http-bio-8980-exec-3,5,main])--connecting(DatabaseLogin(
    platform=>HSQLPlatform
    user name=> ""
    connector=>JNDIConnector datasource name=>null
))
INFO : hsqldb.db.HSQLDB36EB6EA7CB.ENGINE - checkpointClose start
INFO : hsqldb.db.HSQLDB36EB6EA7CB.ENGINE - checkpointClose end
[EL Config]: 2012-04-26 15:17:36.016--ServerSession(313687096)--Connection(1257700692)--Thread(Thread[http-bio-8980-exec-3,5,main])--Connected: jdbc:hsqldb:file:\Users\nly31175\hsqldb;shutdown=true
    User: proxi
    Database: HSQL Database Engine  Version: 2.2.6
    Driver: HSQL Database Engine Driver  Version: 2.2.6
INFO : hsqldb.db.HSQLDB36EB6EA7CB.ENGINE - Database closed
[EL Config]: 2012-04-26 15:17:36.365--ServerSession(313687096)--Connection(385835848)--Thread(Thread[http-bio-8980-exec-3,5,main])--connecting(DatabaseLogin(
    platform=>HSQLPlatform
    user name=> ""
    connector=>JNDIConnector datasource name=>null
))
INFO : hsqldb.db.HSQLDB36EB6EA7CB.ENGINE - checkpointClose start
INFO : hsqldb.db.HSQLDB36EB6EA7CB.ENGINE - checkpointClose end
[EL Config]: 2012-04-26 15:17:36.877--ServerSession(313687096)--Connection(603544782)--Thread(Thread[http-bio-8980-exec-3,5,main])--Connected: jdbc:hsqldb:file:\Users\nly31175\hsqldb;shutdown=true
    User: proxi
    Database: HSQL Database Engine  Version: 2.2.6
    Driver: HSQL Database Engine Driver  Version: 2.2.6
INFO : hsqldb.db.HSQLDB36EB6EA7CB.ENGINE - Database closed
[EL Info]: 2012-04-26 15:17:37.328--ServerSession(313687096)--Thread(Thread[http-bio-8980-exec-3,5,main])--file:/C:/Users/nly31175/workspace/spring/.metadata/.plugins/org.eclipse.wst.server.core/tmp1/wtpwebapps/proxi/WEB-INF/classes/_default login successful
Apr 26, 2012 3:17:37 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [appServlet] in context with path [/proxi] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: Object: com.proxi.user.User@5ca3ce3f is not a known entity type.] with root cause
java.lang.IllegalArgumentException: Object: com.proxi.user.User@5ca3ce3f is not a known entity type.
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerNewObjectForPersist(UnitOfWorkImpl.java:4128)
    at org.eclipse.persistence.internal.jpa.EntityManagerImpl.persist(EntityManagerImpl.java:406)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
    at $Proxy23.persist(Unknown Source)
    at com.proxi.user.UserService.save(UserService.java:27)
    at com.proxi.user.UserService.addUser(UserService.java:39)
    at com.proxi.controller.HomeController.home(HomeController.java:51)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:213)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:405)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:964)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:515)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)

root-context.xml文件:

<?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:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
                        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

    <!-- Root Context: defines shared resources visible to all other web components -->
    <bean id="userService" class="com.proxi.user.UserService" >
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

    <!-- Starting with Spring 3.1, the persistence.xml XML file is no longer 
        necessary. The LocalContainerEntityManagerFactoryBean now supports a ‘packagesToScan’ 
        property where the packages to scan for @Entity classes can be specified. -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="jpaDialect" ref="jpaDialect" />
        <property name="dataSource" ref="dataSource" />
        <property name="packagesToScan" value="com.proxi.user" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
                <property name="showSql" value="true" />
                <property name="generateDdl" value="true" />
                <property name="databasePlatform" value="org.eclipse.persistence.platform.database.HSQLPlatform" />
            </bean>
        </property>
        <property name="loadTimeWeaver">
            <bean class="org.springframework.instrument.classloading.SimpleLoadTimeWeaver" />
        </property>
    </bean>

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

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="org.hsqldb.jdbcDriver" />
        <property name="url" value="jdbc:hsqldb:file:\Users\nly31175\hsqldb;shutdown=true" />
        <property name="username" value="proxi" />
        <property name="password" value="" />
    </bean>

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

</beans>

User.java类:

/**
 * 
 */
package com.proxi.user;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Table;

import javax.persistence.Id;

    /**
     * Represents an application user.
     */
    @Entity
    @Table(name = "user")
    public class User {

        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id")
        private Long id;

        @Column(name = "first_name")
        private String firstName;

        @Column(name = "last_name")
        private String lastName;

        // /////// GETTERS AND SETTERS ///////////

        public String getFirstName() {
            return firstName;
        }

        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }

        public String getLastName() {
            return lastName;
        }

        public void setLastName(String lastName) {
            this.lastName = lastName;
        }

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }
    }

这是UserService.java

package com.proxi.user;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;

import org.springframework.transaction.annotation.Transactional;

/**
 * Performs user related operations.
 * 
 */
public class UserService {

    @PersistenceUnit
    private EntityManagerFactory entityManagerFactory;

    @Transactional
    public User save(User user) {
        EntityManager entityManager = entityManagerFactory.createEntityManager();

        if (user.getId() == null) {
            entityManager.persist(user);
            return user;
        } else {
            return entityManager.merge(user);
        }
    }

    public User findUser(String userid) {
        return null;
    }

    public User addUser(User user) {
        return save(user);
    }

    // /////////////////////// GETTERS AND SETTERS //////////////////////

    public EntityManagerFactory getEntityManagerFactory() {
        return entityManagerFactory;
    }

    public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
        this.entityManagerFactory = entityManagerFactory;
    }
}

4 个答案:

答案 0 :(得分:1)

  

内部异常:java.sql.SQLSyntaxErrorException:对象名称   已存在:USER in statement [CREATE TABLE user(id BIGINT   由默认为身份生成(从1开始,由1增加)不   NULL,first_name VARCHAR(255),last_name VARCHAR(255),PRIMARY KEY   (ID))]

这似乎是问题所在:Spring / EclipseLink正在尝试创建一个已经存在的表。

尝试从xml上下文中删除此行:

<property name="generateDdl" value="true" />

答案 1 :(得分:1)

我已经在这个问题上搜索了好几天了,我能想到的最好的是关于JPA在本教程中的限制的小注释:EclipseLink JPA Deployed on Tomcat 6 using Eclipse WTP。相关部分说:

  

由于Tomcat不是Java EE 5兼容服务器,因此有一些   对JPA的限制。

     
      
  • 没有动态编织(仪器) - 通过EclipseLink仍然可以实现静态编织实体。
  •   
  • 没有@EJB注入会话bean(包含EntityManager) - 直接使用持久性工厂和经理。
  •   
  • 没有@PersistenceContext注入容器管理的持久性单元 - 使用   Persistence.createEntityManagerFactory(JTA_PU_NAME)
  •   

我认为后两点适用于我所遇到的问题。正如我所说,我可以让它工作没有测试代码片段的问题,但我尝试正确连接它的那一刻我遇到了问题。因此,没有任何其他答案,我认为这是我必须解决的问题。任何进一步的见解都欢迎,因为我觉得这不是一个非常令人满意的答案。

答案 2 :(得分:0)

项目中是否存在persistence.xml文件?
如果是这种情况,请从项目中完全删除persistence.xml。此文件以某种方式与packagesToScan属性冲突,即使您未在配置中的任何位置明确提及它。我自己也遇到过这种特殊性。

答案 3 :(得分:0)

@chrisjleu你非常接近。我通过设置eclipse链接使用静态编织来实现它:

private static final Properties jpaProperties = new Properties();
static {
    jpaProperties.put("eclipselink.logging.level", "INFO");
    jpaProperties.put("eclipselink.weaving", "static");
}

并将其添加到LocalContainerEntityManagerFactoryBean.setJpaProperties(jpaProperties)

要使静态编织工作,我使用的是AspectJ。我的项目是在Maven中,所以我使用以下插件:

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.2</version>
                <!-- NB: do not use 1.3 or 1.3.x due to MASPECTJ-90 and do not use 1.4 
                    due to declare parents issue -->
                <dependencies>
                    <!-- NB: You must use Maven 2.0.9 or above or these are ignored (see 
                        MNG-2972) -->
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjrt</artifactId>
                        <version>${version.aspectj}</version>
                    </dependency>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjtools</artifactId>
                        <version>${version.aspectj}</version>
                    </dependency>
                </dependencies>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <outxml>true</outxml>
                    <aspectLibraries>
                        <aspectLibrary>
                            <groupId>org.springframework</groupId>
                            <artifactId>spring-aspects</artifactId>
                        </aspectLibrary>
                    </aspectLibraries>
                    <source>${version.java}</source>
                    <target>${version.java}</target>
                </configuration>
            </plugin>