【问题标题】:Entity Manager not working in JavaFX实体管理器在 JavaFX 中不起作用
【发布时间】:2013-05-05 23:24:53
【问题描述】:

我在 JavaFx fxml 应用程序中使用数据库中的持久性单元和实体类,我成功地将所有表作为实体导入模型中,问题是当我尝试插入时出现异常和错误一个实体,这是我的全部代码

 public class SampleController implements Initializable {
     @PersistenceContext(unitName="RawdaPU")
     private EntityManager em;

     @FXML
     private Label label;

     @FXML
     private void handleButtonAction(ActionEvent event)
     {
         Moyendidactique moyenDidactique = new Moyendidactique("1", "moyen1", "Type1");
         em.persist(moyenDidactique);
         em.close();
     }

     @Override
     public void initialize(URL url, ResourceBundle rb)
     {
         // TODO
     }     
}

这是我按下按钮时得到的全部错误(触发 handleButtonAction 时)

java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1440)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:69)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:217)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:170)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:38)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:37)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:53)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:28)
    at javafx.event.Event.fireEvent(Event.java:171)
    at javafx.scene.Node.fireEvent(Node.java:6863)
    at javafx.scene.control.Button.fire(Button.java:179)
    at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:193)
    at com.sun.javafx.scene.control.skin.SkinBase$4.handle(SkinBase.java:336)
    at com.sun.javafx.scene.control.skin.SkinBase$4.handle(SkinBase.java:329)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:64)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:217)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:170)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:38)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:37)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:53)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:33)
    at javafx.event.Event.fireEvent(Event.java:171)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3324)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3164)
    at javafx.scene.Scene$MouseHandler.access$1900(Scene.java:3119)
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1559)
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2261)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:228)
    at com.sun.glass.ui.View.handleMouseEvent(View.java:528)
    at com.sun.glass.ui.View.notifyMouse(View.java:922)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:29)
    at com.sun.glass.ui.win.WinApplication$2$1.run(WinApplication.java:67)
    at java.lang.Thread.run(Thread.java:722)
Caused by: java.lang.reflect.InvocationTargetException
    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 javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1435)
    ... 41 more
Caused by: java.lang.NullPointerException
    at rawda.Controller.SampleController.handleButtonAction(SampleController.java:37)
    ... 46 more

我在已经存在的类似问题中找不到答案,无法确切知道我错过了什么,提前感谢您的帮助。

【问题讨论】:

  • 这里有空指针异常:rawda.Controller.SampleController.handleButtonAction(SampleController.java:37) 它是你的代码...看起来 em 为空...
  • @PersistenceContext 初始化的规则是什么?
  • 确实它是空的,我刚刚检查了它,但问题是我有很多教程只是使用我正在做的 EntityManager,但我确实错过了一些东西,需要提一下,我使用 Java 才两周,对它有点陌生
  • 我不熟悉持久化API等,但我认为你应该研究一下,控制器类是如何实例化和初始化的,以及关于pirsistance的东西初始化过程的规则是什么。

标签: java jpa persistence javafx-2 entitymanager


【解决方案1】:

为什么您的代码中会出现 NullPointerException

@PersistenceContext 注释“表示对容器管理的 EntityManager 及其关联的持久性上下文的依赖。”

默认情况下,FXML 控制器不是容器管理的,这意味着它们不会设置容器管理的成员,例如标有 @PersistenceContext 的成员。

您可以通过为 FXMLLoader 定义 controller factory 来在容器管理的环境中使用 FXML 控制器(例如,InjectionProvider 用于将值注入到 Afterburner.fx framework 中)。

但实际上,如果您刚开始使用 Java,则不需要进行这种注入。在您习惯之前,inversion of control stuff 可能会增加一点魔力。

推荐 JPA 初学者尝试的 JavaFX 集成方法

相反,不要依赖@PersistenceContext 注释。直接从实体管理器工厂参考中获取实体管理器。在 java2s 示例 Create Query From Entity Manager 中有一个在容器管理环境之外使用 EntityManager 的好例子。

在您的应用程序中提供获取实体管理器的机制:

public class SampleApplication extends Application {
  static private EntityManagerFactory emf;
  static {
    try {
      emf = Persistence.createEntityManagerFactory("RawdaPU");
    } catch (Exception e) {
      System.out.println("Fatal: Unable to create entity manager factory");
      e.printStackTrace();
    }  
  }

  static public EntityManager createEntityManager() {
    return emf.createEntityManager();
  }

  @Override 
  public void start(Stage stage) {
    . . .
  }
}

在您的控制器中,从应用程序中获取一个实体管理器并根据需要使用它。

class SampleController implements Initializable {
  @FXML
  private Label label;

  @FXML 
  private void handleButtonAction(ActionEvent event) {
    EntityManager em = SampleApplication.createEntityManager();
    Moyendidactique moyenDidactique = new Moyendidactique("1", "moyen1", "Type1");
    em.persist(moyenDidactique);
    em.close();
  }

  @Override
  public void initialize(URL location, ResourceBundle resources) {}
}

关于关闭和实体管理器的生命周期

因为您的原始示例在 persist 语句之后关闭了实体管理器,所以我将实体管理器的创建移到与 close 方法相同的方法中,以便它们匹配。关闭意味着实体管理器无法再次使用,因此您不妨在关闭它的同一个地方创建它 - 这样您就不会在其他地方错误地重用它。请注意,您不需要像那样关闭并且可以根据需要重用实体管理器,但是对于开始使用 jpa,只需按照此示例答案进行操作就可以了,您可以查看更复杂的实体管理器重用场景,让您获得更多的技术经验和信心。

并发问题

您还需要了解应用程序中 JPA 使用的并发集成。直接在按钮的操作处理程序中执行诸如 JPA 调用之类的操作通常不是一个好主意,因为这些调用会阻塞 I/O,这将停止 JavaFX 应用程序线程并在一段时间内冻结您的应用程序 UI。相反,最好使用JavaFX task and service concurrency utilities 来处理JPA 交互,类似于从JavaFX JDBC task sample 中的UI 线程中抽象出数据库工作的方式。

对于小型本地数据库,并发性可能不是那么重要,因此您可以先尝试您的应用程序单线程,如果它工作正常,那就太好了,但如果它被冻结然后查看并发实用程序。

后续步骤

上面的方法确实是一个快速入门的东西。

一旦您了解了这种简单的方法,您可能想要研究在afterburner.fxairhacks-control 框架或(更重量级的)javafx/jpa/spring framework integration 中展示的更结构化的设计。

【讨论】:

  • 我完全理解了您的解释,但您添加到 SampleApplication 类的静态代码仍然抛出异常:致命:无法创建实体管理器工厂本地异常堆栈:异常 [EclipseLink-30005] (Eclipse Persistence Services - 2.3.2.v20111125-r10461):... org.eclipse.persistence.exceptions.EntityManagerSetupException 异常描述:PersistenceUnit [RawdaPU] 的预部署失败。这阻止了 emf 被分配,因此之后的 entitymanager 也被分配了,提到我正在使用 NetBeans,我只是按照你的解释进行操作。
  • 几乎所有东西都试过了,无法正确初始化 emf
  • 这与最初发布的问题不同。创建一个新问题,其中包括sscce、完整的环境描述(Eclipselink 版本等)和完整的堆栈跟踪。看看你是否可以独立获得我在我的回答中链接的 java2s 示例。
  • 我刚刚注意到创建持久性单元而不将 EntityClasses 导入我的模块会使 SampleApplication 类代码工作得很好,当我添加实体类时会开始混乱
猜你喜欢
  • 2013-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-29
  • 2015-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多