PersistenceException:没有名为EntityManager的持久性提供程序

时间:2016-01-13 17:52:44

标签: java eclipse jpa command-line

我已经(使用Eclipse)编写了一个使用JPA的小程序。现在我想使用命令行手动编译和运行该程序。我还将所有源文件放在一个单独的目录中(不在Eclipse的工作空间内)。该目录如下所示:

directory
  |- src
  |   |- javax
  |   |   |- persistence
  |   |        |- <...>
  |   |- main
  |   |- META-INF
  |   |   |- javax
  |   |   |    |- persistence
  |   |   |- persistence.xml
  |   |
  |   |- <..>
  |- run.bat

注意:我故意有2个javax目录,其中包含所有类文件。

run.bat包含行:

javac -cp ./src ./src/main/Main.java
java -cp ./src main.Main

据我所知,我收到的错误不是因为META-INF / persistence.xml文件的问题(与stackoverflow上的许多其他人不同)。我是这样说的,因为我在我的主要内容中写了以下几行:

<...>
Thread.currentThread().setContextClassLoader(new ClassLoader() {
            @Override
            public Enumeration<URL> getResources(String name) throws IOException {
                System.out.println("resource requested=" + name);
                if (name.equals("META-INF/services/javax.persistence.spi.PersistenceProvider")) {
        <--- MARK --->     return Collections.enumeration(Arrays.asList(new File("src/javax/persistence/spi/PersistenceProvider.class")
                            .toURI().toURL()));
                } else if (name.equals("META-INF/persistence.xml")) {
                    return Collections.enumeration(Arrays.asList(new File("src/META-INF/persistence.xml")
                            .toURI().toURL()));
                }
                return super.getResources(name);
            }
        });
emFactory = Persistence.createEntityManagerFactory("uzduotis");
<...>

因此,当我启动run.bat时,程序会打印出来:

resource name=name=META-INF/services/javax.persistence.spi.PersistenceProvider

(它永远不会到达程序要求“META-INF / persistence.xml”资源的部分)

然后它打破并给我一个错误:

enter image description here

如果我将MARKED语句更改为

return super.getResources("src/" + name);

然后错误只说:

enter image description here

我缺少什么?

Peristence.xml:

enter image description here

修改 程序prety简单:没有hibernate,只有几个类从REST服务中检索一些信息并使用它,主要使用javax和w3c外部库。项目探险家的照片描绘了它的简洁。

enter image description here

编辑2.解决方案

虽然我不完全确定原因,但我找到了一种方法让它发挥作用。所以如果有人能回答为什么以下更改解决了这个问题,我很乐意将其标记为答案

我将eclipselink和mysql-connector-java jars添加到 src 目录中。 eclipselink.jar修复了这个问题,需要mysql-connector-java.jar,因为我收到了其他错误(我正在使用数据库afterall)。最后,我在

的run.bat文件中更改了一行
java -cp ./src main.Main

java -cp ./src;./src/eclipselink.jar;./src/mysql-connector-java.jar; main.Main

1 个答案:

答案 0 :(得分:0)

您的应用程序似乎是标准的Java SE应用程序。 JPA不能自动运行,因为标准Java SE环境不包含JPA接口的任何实现。似乎Eclipse将eclipselink添加到封面下的类路径中,因此当您从Eclipse中运行它时,您的程序可以正常工作。但是当您从命令行运行程序时,需要添加eclipselink,这是一个包含JPA接口功能的库。

您可以尝试从eclipse项目生成Ant构建文件,您会看到它是否将eclipselink添加到build.xml文件的类路径中。或者甚至更好,我建议使用Maven构建将项目转换为项目 - 您将能够使用Maven命令构建和运行项目,就像Eclipse执行它一样(因为Eclipse在Maven的封面下使用Maven)项目)。

编辑 - 解释eclipselink在JPA中的作用

javax.persistence开头的软件包主要是接口,注释,实际上它们的类很少。它们仅定义应用程序如何以标准方式与底层持久性机制进行通信。另一方面,您还需要在库中包含标准JPA接口的实现(类)。 javax.persistence.Persistence只是一个外观,它将所有艰苦的工作委托给一个实现,可能是Eclipselink,Hibernate或其他东西。

javax.persistence和EclipseLink之间的关系类似于接口和类之间的关系。您可以在代码中使用接口,但只有在某些时候为实际类提供接口时,您的应用程序才会起作用。

也可以直接使用Eclipselink并跳过整个javax.persistence层,类似于可以直接使用实际类而无需通过接口。但是,您需要学习Eclipselink的内部API,并且不可能为Hibernate等替代品更改Eclipselink库。您也不能将Eclipselink特定API的知识重用于使用Hibernate的项目。标准API的可重用性是标准化javax.persistence接口最重要的情况。

也许您想知道,持久性API如何知道它应该委派所需功能的位置。它有多个钩子,它是如何找到的。可以使用persistence.xml元素在provider中包含主实现类的路径。或者,如果您将Eclipselink包含在类路径中,它就会起作用,因为Eclipselink库在标准化路径中包含特殊文本文件,其中包含所需信息。这个特殊文件位于路径META-INF/services/javax.persistence.spi.PersistenceProvider的Eclipselink JAR中 - 是否响铃?