1

我确实有一个问题,我无法弄清楚它会发生什么...... GWT 初学者,从事个人项目。

环境:

  • 具有两个模块的maven项目

    • 一个模块是“模型”,具有HibernateHSQLDBSpring依赖项。HSQLDB 在内存中运行嵌入式,从 spring applicationContext.xml 配置

    • 另一个模块是“网络”,并具有所有GWT 依赖项

该应用程序是使用一些 Spring Roo 生成的代码作为基础构建的,随后对其进行了修改和扩展。

问题是,当编辑一些实体字段并按下保存时,什么也没有发生。创建新实体实例时没问题,仅在编辑更改某些字段并按“保存”时基本上会覆盖新值。所以我开始彻底调试客户端代码,启用休眠和 Spring 详细日志记录,但仍然......什么都没有。

然后我做了一个(对我来说)令人惊讶的发现。检查 GWT 响应负载,我看到了这个:

    {"S":[false],"O":        [{"T":"663_uruC_g7F5h5IXBGvTP3BBKM=","V":"MS4w","S":"IjMi","O":"UPDATE"}],"I":[{"F":true,"M":"Server Error: org.hibernate.PersistentObjectException: detached entity passed to persist: com.myvdm.server.domain.Document; nested exception is javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.myvdm.server.domain.Document"}]}  

啊哈,分离的实体通过坚持!请注意,gwt 客户端代码使用此代码段来调用服务:

requestContext.persist().using(代理);

可以说这可能会触发异常,调用 merge() 可以解决问题,但是,请继续阅读问题 3...

现在出现三个问题:

  • 为什么不以某种方式将其作为错误/异常发送给客户端?
  • 为什么 Hibernate 不记录这个?
  • Spring Roo 生成的代码(如我所说,用作基础)如何在没有表现出这个问题的情况下工作?

非常感谢,

等待一些意见/建议。


在 T. BROYER 的回应后编辑::

嗨,托马斯,感谢您的回复。

我有一个实现 RequestTransport 并实现 send() 的自定义类。这就是我收集响应负载的方式。实施如下:

public void send(String payload, final TransportReceiver receiver) {
    TransportReceiver myReceiver = new TransportReceiver() {

        @Override
        public void onTransportSuccess(String payload) {
            try {
                receiver.onTransportSuccess(payload);
            } finally {
                eventBus.fireEvent(new RequestEvent(RequestEvent.State.RECEIVED));
            }
        }

        @Override
        public void onTransportFailure(ServerFailure failure) {
            try {
                receiver.onTransportFailure(failure);
            } finally {
                eventBus.fireEvent(new RequestEvent(RequestEvent.State.RECEIVED));
            }
        }
    };

    try {
        wrapped.send(payload, myReceiver);
    } finally {
        eventBus.fireEvent(new RequestEvent(RequestEvent.State.SENT));
    }
}

以下是在编辑模式下单击“保存”按钮时执行的代码:

RequestContext requestContext = editorDriver.flush();
    if (editorDriver.hasErrors()) {
        return;
    }

    requestContext.fire(new Receiver<Void>() {
        @Override
        public void onFailure(ServerFailure error) {
            if (editorDriver != null) {
                setWaiting(false);
                super.onFailure(error);
            }
        }

        @Override
        public void onSuccess(Void ignore) {
            if (editorDriver != null) {
                editorDriver = null;
                exit(true);
            }
        }

        @Override
        public void onConstraintViolation(Set<ConstraintViolation<?>> errors) {
            if (editorDriver != null) {
                setWaiting(false);
                editorDriver.setConstraintViolations(errors);
            }
        }
    });

根据您所说的,应该调用 onSuccess() ,它被称为

那么如何准确地隔离产生问题的代码呢?我有这个方法可以创建一个新的请求上下文以持久化对象

        @Override
        protected RequestContext createSaveRequestContextFor(DocumentProxy proxy) {
            DocumentRequestContext request = requests.documentRequestContext();
            request.persist().using(proxy);
            return request;
        }

这就是它的名称::

 editorDriver.edit(getProxy(), createSaveRequestContextFor(getProxy()));

至于 Spring 问题,您是说在两个后续请求 find() 和 persist() 之间,不应关闭 JPA entityManager。我仍在调查此问题,但在按下编辑按钮后,我看到消息“org.springframework.orm.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager”,这是不对的,可能没有应用 @Transactional 注释...

4

2 回答 2

2

为什么不以某种方式将其作为错误/异常发送给客户端?

这是。表示第"S": [false]一个(也是唯一一个)方法调用(记住,aRequestContext是一个批处理!)失败。onFailure调用的方法将Receiver被调用。

的then 说这是一个"F": true致命错误,所以默认实现会抛出一个. 但是,由于您根本不使用 a ,因此不会发生任何事情,并且会默默地忽略该错误。ServerFailureReceiver#onFailureRuntimeExceptionReceiver

请注意,批处理请求本身已成功,因此全局Receiver(您将传递给的那个RequestContext#fire)将onSuccess调用其方法。
另请注意,它Request#fire(Receiver)Request#to(Receiver)后跟RequestContext#fire()(不带参数)的简写。

为什么 Hibernate 不记录这个?

这个我不知道,对不起。

Spring Roo 生成的代码(如我所说,用作基础)如何在没有表现出这个问题的情况下工作?

好的,让我们来探讨一下异常的根本原因:实体是由您Locator(或实体类的findXxx静态方法)加载的,然后persist在实例上调用该方法。如果您不在and方法中使用相同的 JPA EntityManager/ Hibernate 会话,那么您将遇到问题。 请求工厂希望您使用视图模式中的打开会话来克服这个问题。不幸的是,我不知道 Spring Roo 生成什么样的代码。findpersist

于 2012-07-27T14:49:25.983 回答
2

关于Thomas 提到的视图模式中的打开会话web.xml,只需将此过滤器定义添加到您的 Spring 应用程序中即可打开该模式:

<filter>
    <filter-name>
        Spring OpenEntityManagerInViewFilter
    </filter-name>
    <filter-class>
         org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
    </filter-class>
</filter>
<filter-mapping>
    <filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
于 2012-07-30T08:45:19.283 回答