Objectify:如何禁用会话缓存?

Objectify: How can I disable session cache?

我喜欢 Objectify "just use ofy()" 获取 Objectify 实例的便利,但我 运行 进入了一个可以使用一些建议的用例。

我的数据存储用例是这样的,在我的流程的一部分中,我将在一个很长的 运行 流程中编写实体。数十万个实体。它们将很好地分散在时间/实体组中(因此数据存储争用对我来说并不是真正的问题)。在这个漫长的 运行 过程中,我将不需要多次 读取 数据存储实体。

我知道我可以通过使用 Objectify.cache(false) 创建一个不使用 memecache 的实例来禁用 "second level" 缓存。太棒了

我担心的是会话缓存。我只是稍微查看了 Objectify 代码,似乎在 WriteEngine.java 中,当我们为遇到的实体执行 "save()" 时:

                // Also stuff this in the session
                session.addValue(key, obj);

所以 objectify 正在保留我在内存中的项目?我想关闭在任何可能的缓存中保存实体。

不幸的是,目前唯一的方法是定期调用 ofy().clear()。我看到你在 github 跟踪器中添加了一个问题,这很好。

所以要清楚...@stickfigure 的答案是标准 Objectify 的最终答案。我希望他能查看这段代码并发表评论。我希望 Objectify 将来可能有更多的缓存选项……甚至可能在实体级别!在那之前,下面是我正在使用的技巧,也许其他人会觉得有用。

那些已经使用 Objectify 一段时间的人可能会记得这个服务模型的想法。您通过包含

使用此 OfyService
import static com.industryopenings.seeker.shared.OfyService.ofyw;

在您 class 的顶部。然后你只需在通常调用 ofy() 的地方调用 ofyw()。请注意...混合 ofyr()ofyw() 不是我对这段代码的意图。混合可能会产生奇怪的结果。特别是在交易中。

OfyService 做了两件事...

  1. 确保使用 ofyw() 创建的 Objectify 的实例具有 cache(false) 规范而不是默认的 cache(true)
  2. OFYW_USE_COUNT_THRESHOLD 调用 ofyw()
  3. 之后,定期为您调用 clear() 方法

请记住,我们实际上没有太多能力来检查对象化会话...这里没有对象大小或对象计数逻辑。它假定您定期调用 ofyw()(不保留 Objectify 实例)并定期为您清除会话。

import com.googlecode.objectify.*;
import com.googlecode.objectify.impl.ObjectifyImpl;

public final class OfyService {
    public final static int OFYW_USE_COUNT_THRESHOLD = 10;
    public static int currentReferenceCount = 0;
    private static ObjectifyFactory defaultFactory = new ObjectifyFactory();
    private static ObjectifyFactory noCacheFactory = new NoCacheFactory();

    // This factory always returns a no-cache instance.
    // BUT: end users can be foolish and turn it back on if they want... having potentially ripple effects downstream
    // Best practice if you're going to use this OfyService is to never call the cache(boolean) method
    private static class NoCacheFactory extends ObjectifyFactory {
        @Override
        public Objectify begin() {
            return new ObjectifyImpl<>(this).cache(false);
        }
    }

    // Note!  We probably need to register our classes in both factories
    static {
        defaultFactory.register(Doc.class);
        defaultFactory.register(SiteLogEntry.class);
        defaultFactory.register(SiteLogRunSummary.class);

        noCacheFactory.register(Doc.class);
        noCacheFactory.register(SiteLogEntry.class);
        noCacheFactory.register(SiteLogRunSummary.class);
    }

    // ofyr to get an Objectify... with the "r" to denote read / caching enabled.
    public static Objectify ofyr() {
        ObjectifyService.setFactory(defaultFactory);
        return ObjectifyService.ofy();
    }

    // ofyr to get an Objectify... with the "w" to denote writing / no caching enabled.
    public static Objectify ofyw(){
        // This will ensure we're not using second level cache (memecache)
        ObjectifyService.setFactory(noCacheFactory); 

        // In lieu of a true solution we're simply going to clean house every X times ofyw() is called
        currentReferenceCount++;
        Objectify o = ObjectifyService.ofy();
        if(currentReferenceCount > OFYW_USE_COUNT_THRESHOLD){
            o.clear();
            currentReferenceCount = 0;
        }
        return o;
    }
}

希望这对其他人有帮助。