【问题标题】:Wicket LoadableDetachableModel - unnecessary detaching during ajax requestsWicket LoadableDetachableModel - 在 ajax 请求期间不必要的分离
【发布时间】:2014-12-12 11:11:24
【问题描述】:

我注意到 Wicket 的 LoadableDetachableModel (LDM) 会根据设计(通过 RequestCycle.processRequestAndDetach())分离每个请求。这在特定情况下可能会导致性能问题,我希望在保留缓存数据的同时仍然使用 LDM 的优势。

假设您有一个带有 id 的实体的详细信息页面。该页面分为选项卡 (AjaxTabbedPanel)。 如果您打开页面,则会从 DB 中读取给定 id 的实体(进入 LDM)。 如果单击第二个选项卡,模型已经分离,将再次重新加载。 在我的情况下这不是必需的,因为我不想刷新每个请求的数据。

我想要页面上的 LDM,以便页面历史记录能够正常工作(只有实体 ID 会被序列化并按需重新加载数据)。

那么如何修复不必要的重载?

我想出了两个解决方案:

  1. 将 LDM 包装到静态模型中,使其不会自动分离,仅在需要时手动分离(=重新加载)。
  2. 实现 LDM 的子实现,它将保留瞬态数据并仅在为 null 时重新加载(如恢复序列化页面时)。然后可以重复使用此通用模型。

我认为在检票口中已经为此实施了解决方案,但我没有找到任何解决方案。您知道实现此目的的任何其他(标准)方法吗?

非常感谢您的回答。

PS:2) 的示例实现

    private class MyEntityModel extends LoadableDetachableModel<MyEntity> {
    private String entityId;
    private transient MyEntity modelObject;

    public MyEntityModel(String entityId) {
        this.entityId = entityId;
    }

    //call this for explicit reload
    public void forceDetach() {
        modelObject = null;
        detach();
    }

    @Override
    protected MyEntity load() {
        if (modelObject != null) {
            return modelObject;
        }
        MyEntity entity = getData(entityId);
        modelObject = message;
        return message;
    }
}

更新: 看来我原来的问题还不够清楚。对此感到抱歉。 当前行为:

  1. 使用作为参数传递的 entityID 加载检票口页面
  2. 创建了一个新的 LDM 实例,并将 entityID 传递给它
  3. 当(在响应呈现期间)调用 LDM.getObject() 时,从数据库中加载实体
  4. 响应呈现后,调用 LDM.detach()
  5. 加载了带有 ajax 控件的页面
  6. 当用户点击任何控件(如选项卡开关)时,会向服务器生成一个新请求
  7. 服务器交换选项卡,尝试用数据填充新选项卡,因此它调用已在 4. 中分离的 LDM.getObject(),并再次加载数据
  8. 响应发送到客户端并调用 LDM.detach()

期望的行为: 广告 4 - 当 LDM.detach() 被调用时,瞬态模型对象被保留 广告 7 - 如果瞬态模型对象仍在内存中,请使用它。否则加载数据

上面我描述了两种方法,如何实现这种行为。有什么标准或者更好的方法吗?

【问题讨论】:

  • 如果数据没有在某些 Ajax 请求中分离,那么如果下一个请求是通过 BookmarkablePageLink 到另一个页面,那么这个数据根本不会从第一页分离,并将与其余的一起序列化.当使用 LDM 时,payload 很可能没有实现 java.io.Serializable!
  • @RobertNiestroj 这可能是最正确的答案。 LDM 似乎真的被实现为在每次请求后分离,所以改变它(不分离)可能是一种误用。所以我需要的是一个具有瞬态对象的模型,它是不可分离的,并且在瞬态对象为空时(例如反序列化之后)会重新加载。 AbstractReadOnlyModel 可能更适合这个。
  • 我遇到了同样的问题,下面提供的答案不是解决这个问题的方法。
  • 嗨,到目前为止,我没有看到任何标准模型实现包含在检票口中。 LDM 确实适用于不同的用例,因此您可能需要实现自己的东西。您可以使用我的代码(简单、有效,但扩展了 LDM,这在语义上不正确),或扩展其他代码(如 AbstractReadOnlyModel,...)。

标签: ajax performance wicket


【解决方案1】:

有几个选项可以实现您想要的:

  1. 长时间运行的休眠会话
  2. 从会话或实体管理器中分离实体
  3. 使用 CDI 并将实体存储在对话范围的对象中

我没有使用过 1 和 2,但 2 可能是您当前使用的最接近的替代方案(并且实施起来更快)。 3 可能是您实际想要实现的最接近的替代方案,但需要您向应用程序添加全新的基础架构 - 取决于您的容器更容易(JavaEE7)或更难(像 Tomcat/Jetty 这样的普通旧 servlet 容器)。

【讨论】:

  • 我用更清晰的问题定义更新了我的问题。它与持久层无关,仅与检票口的行为有关。无论如何感谢您的回答。
【解决方案2】:

我注意到 Wicket 的 LoadableDetachableModel (LDM) 通过设计(通过 RequestCycle.processRequestAndDetach())在每个请求上分离。这在特定情况下可能会导致性能问题,我希望在保留缓存数据的同时仍然使用 LDM 的优势。

您知道它实际上会导致您的性能问题吗?

听起来您正在尝试通过构建缓存机制来优化性能。如果事实上您确实有问题并且需要它,那么可能有比构建自己的缓存更好的解决方案。

如果您使用的是 hibernate,您可能希望查看将 hibernate 配置为使用 Second Level Cache

如果您没有使用休眠,那么您正在 用于持久性的任何机制都可能具有类似的缓存。或者,如果您实际上需要添加自己的内容,则可能应该基于现有的缓存机制,例如 ehcache

【讨论】:

  • 您好,好的,“性能问题”可能是一个强词。我们称之为对数据库的不必要的冗余调用。我基本上想要的是防止在不需要时重新加载数据。在同一个已加载页面上单击选项卡并不是在整个页面上重新加载数据的任何好理由。在我目前的情况下,我正在加载相当大的数据,您可以下载 BLOB 中的文件。这是一个传递大量消息的系统。因此,hibernate 上的二级缓存没有任何好处,它不会解决我的问题。
【解决方案3】:

大多数人会使用 ORM,无论是 JDO 还是 JPA 的实现,最有用的用例是“在视图中打开持久性管理器/会话”。相信我,它是最有用的——我很长一段时间都试图通过尝试所有其他化身来避免它,但它们只是以泪水和许多额外的错误代码告终。

“在视图中打开持久性管理器/会话”意味着当您的应用收到 HTTP 请求时,它会获得一个新的持久性管理器/会话(具有自己的 L1 缓存),然后您的代码会根据需要使用它来加载对象,通过 IModel 向 Wicket 组件提供内容,然后在 http 请求周期期间调用其 onDetach 方法时,Wicket 组件分离它们拥有的模型引用。在请求结束时,持久性管理器/会话关闭。当然,我们丢失了 L1 缓存,但它的大部分内容仍然缓存在 L2 缓存中。

您确实有 L2 缓存,不是吗?

任何好的 ORM 都会有一个 2 级 (L2) 缓存,它将缓存持久性管理器在之前的 HTTP 请求期间加载的所有对象(当然受内存容量限制)。

鉴于这些已经在内存中,因此可以非常快速地将它们复制到为新 HTTP 请求服务而创建的新持久性管理器的 L1 缓存中。即,如果对象在 L2 缓存中,ORM 不必从数据库中重新加载对象。

运行没有配置 L2 缓存的 ORM 的任何人都需要回到 ORM 学校的第一天,第 1.0.1 课。

当一个持久对象被加载时,它被“附加”到加载它的持久性管理器。重要的是不要将此类对象与新的持久性管理器一起使用,除非它首先与原始持久性管理器分离,然后重新附加到新持久性管理器。

这就是 Wicket 的 onDetach 为您节省的地方 - 并且(最后回答了这个问题;))这就是为什么需要在每个 HTTP 请求结束时进行分离:这就是您执行所有 ORM 分离的地方,它必须发生在每个请求结束,否则您将在后续 HTTP 请求中跨不同的持久管理器交叉轮询您的对象 - 结果总是很糟糕!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-23
    • 2021-12-28
    • 1970-01-01
    • 1970-01-01
    • 2015-07-15
    • 2016-09-20
    • 1970-01-01
    • 2023-03-14
    相关资源
    最近更新 更多