如何在Java中实现规范化映射?

12

我目前正在开发自己的ORM,发现自己面临着创建规范化映射的任务,以便防止从数据库中加载相同的实体超过一次。

我的当前做法是使用一个HashMap<Object, WeakReference<Object>>。键是映射的数据库实体的主键(如果是组合键,则为ArrayList<Object>),值是WeakReference<Object>

我的主要问题是如何清理地图?当对象不再使用时,映射中的弱引用将变为null,并且我只会在下一次查找时发现此情况(或者永远不会,如果我再也不查找该对象)。我可以使弱引用在被清除时向ReferenceQueue注册,然后每次查找时都检查该队列。清除的引用不会提示我哪个对象已清除,因此我想我必须对WeakReference进行子类化以将键存储在映射中,这样我就可以在引用被清除后将其删除。

这是正确的方法,还是有更简单的方法实现呢?

1个回答

16

我建议使用Guava的MapMaker,或者r10中的CacheBuilder

它们允许自动*基于时间和大小进行清除,同时支持弱键或值。(即将推出的CacheBuilder专为此类用例而设计。)

因此,您可以初始化您的映射:

ConcurrentMap<Key, Object> cache = new MapMaker()
        .weakValues()
        .makeMap();

直接的好处是,当一个值被垃圾回收时,整个条目都将被删除。此外,您可以使用计算映射:

ConcurrentMap<Key, Object> cache = new MapMaker()
        .weakValues()
        .makeComputingMap(loadFunction);

这里的loadFunction是一个从数据库中加载对象的Function<Key, Object>函数。这样做的好处是,地图将处理对特定对象的并发请求,确保查询仅被调用一次。此外,请求代码只需调用get(),无论是从缓存还是从数据库返回对象。

这些示例使用的是MapMaker - 我还没有使用CacheBuilder进行尝试。

请参阅我的问题my ideal cache using guava以获取更多示例。该帖子讨论如何将基于时间的驱逐与规范化相结合。


2
一开始我有些犹豫是否要添加这个库,但现在我添加了之后,我想知道为什么我以前没有这样做。感谢这个很棒的答案! - Björn Pollex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接