【问题标题】:Java cache and update dynamicallyJava缓存和动态更新
【发布时间】:2012-01-30 18:37:40
【问题描述】:

我需要在 servlet 启动时从数据库中“预加载”一些数据。

所以我想创建一些缓存,例如使用HashMap 或一些类似的同步版本。

我还需要在数据库更新更改时更新缓存。
所以我想添加某种“听众”。

我的问题是:这是以某种方式可用还是我必须实际实现它?

如果是,哪种设计模式是最好的方法?

更新:
没有使用 JPA 或 ORM。但是Spring可用

【问题讨论】:

  • 您是否使用库来实现持久性?它们中的大多数已经支持各种形式的缓存,无需重新发明轮子。
  • 否。直接 SQL 调用数据库
  • 您的缓存是否需要分布到多个进程?写入操作是否需要更新其他缓存实例(或导致它们更新)还是仅与正在执行写入的进程相关?
  • @philwb:没有多个进程。仅与执行写入的进程相关。
  • 还有一个问题 - 您的进程需要多快才能从数据库接收更改?轮询线程每分钟检查一次的时间是否足够长,或者您是否需要在数据库中有效地触发来广播更改?

标签: java design-patterns caching tomcat servlets


【解决方案1】:

是的,你当然可以实现它
我会画一个小架构然后给你解释一下:

首先,您可以了解 Mappers here 和 TDGs here。 映射器有一个名为 cacheAll() 的方法,该方法调用并委托给 TDG 的方法 cacheAll(),后者的任务是从数据库中获取表中的所有行(您要在缓存对象中缓存的行)。

所以基本上首先你必须创建一个实现 "ServletContextListener" 的监听器 这意味着它是整个 servlet 上下文的侦听器,并且在它的 contextInitialized 内你必须调用 mp.fill(Mapper.cacheAll()),所以它有点像 (这是通用代码,当然写得更好,优化一下)

public class myServletContextListener implements ServletContextListener{

@Override
public void contextInitialized(ServletContextEvent sce) {
        mp.fill(Mapper.cacheAll());
 }

//
}

别忘了在 web.xml 中添加你的监听器:

<listener>
    <listener-class>myServletContextListener </listener-class>
</listener>

所以这会做什么,在服务器启动时,会将所有记录缓存到缓存对象中的 hashmap mp 中。

至于根据数据库更改更新缓存,您将不得不使用observer pattern

更新
我忘了提到,关于缓存对象,我假设您希望所有用户或您的应用程序都可以访问它,因此您应该将其编码为单例(单例模式),如下代码:

 public class cacheObject
{
    private static Map cMap;
    private static cacheObject cObject;
    private cacheObject()
    {
        cMap = Mapper.cacheAll();
    }
    public static synchronized cacheObject getInstance()
    {
        if (cObject == null){
            cObject = new cacheObject();
        }
        return cObject;
    }

}

此外,如果您要缓存的数据可以由用户更改,则将其设为 Threadlocal 单例。

【讨论】:

    【解决方案2】:

    Guava 在这里可以满足您的需求。 Caches 上的 wiki article 可能与您最相关,但这里的确切方法很大程度上取决于数据库更新更改的条件。如果您想在数据库更新更改时刷新整个缓存——或者至少使旧条目无效——您可以在数据库更新发生时调用Cache.invalidateAll()。如果您愿意让缓存稍微落后于时代,使用CacheBuilder.refreshAfterWrite(long, TimeUnit) 可能对您很有效。

    【讨论】:

    • @LuisWasserman:我以前从未使用过 Guava。它只有 1 个 jar 还是它有很多依赖项?我问是因为项目很小。我无法展示例如由于依赖于其他库,额外增加了 20 MB
    • 我相信它最多有一个依赖项,即(微小的)JSR-305。这甚至可能不是绝对必要的。如果您担心输出 JAR 大小,我们推荐proguard.sourceforge.net
    • 根据您的需求,这是一种低复杂度的方法,是一个很好的起点。
    【解决方案3】:

    Hashmap 和它的线程安全变体 ConcurrentHashMap 已经可用。

    有一些可用的缓存解决方案,例如 ehcache,它还提供高级支持,例如驱逐策略等等。

    至于设计模式,请阅读观察者设计模式。

    【讨论】:

      【解决方案4】:

      我实际上有一个生产级项目,我需要做这样的事情。我的解决方案是(这只是我的解决方案)是在 servlet 启动时将对象(您的“数据”)加载到内存中。做出这个决定是因为该对象足够大,以至于客户端请求从数据库中提取它的速度很慢,而且我有少量并发用户。任何会更改数据库中该对象的数据的请求也会更改内存中的对象。如果您与很多用户一起工作,您当然需要使用同步对象来执行此操作。如果数据量不是很大,那么每次用户请求有关数据的信息时,您总是可以从数据库中提取。

      祝你好运。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-12-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-02
        相关资源
        最近更新 更多