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
做了两件事...
- 确保使用
ofyw()
创建的 Objectify
的实例具有 cache(false)
规范而不是默认的 cache(true)
- 在
OFYW_USE_COUNT_THRESHOLD
调用 ofyw()
之后,定期为您调用 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;
}
}
希望这对其他人有帮助。
我喜欢 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
做了两件事...
- 确保使用
ofyw()
创建的Objectify
的实例具有cache(false)
规范而不是默认的cache(true)
- 在
OFYW_USE_COUNT_THRESHOLD
调用ofyw()
之后,定期为您调用
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;
}
}
希望这对其他人有帮助。