当插入新记录时,Hibernate缓存的查询未更新。

6
我们拥有一个EHCache集群,使用Hibernate和Mysql。
一切都运作得几乎完美。标准查询被缓存,并且当其他集群成员上的记录被修改时,缓存的查询会立即在其他服务器上更新。
然而,我的问题是当插入新记录时,那个表上的缓存查询不知道它,直到缓存查询过期。
我可能在我的EHcache.xml配置中漏掉了某些内容,但我不知道可能是什么。
有任何想法吗?
以下是EHCache.xml文件:
<!--<diskStore path="java.io.tmpdir"/>-->

<!-- means for cache replication -->

<cacheManagerPeerProviderFactory
    class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory"
    properties="connect=
        TCP(bind_port=10700):
        S3_PING(...):
        MERGE2(max_interval=30000;min_interval=10000):
        FD_SOCK(start_port=0):
        FD(timeout=3000;max_tries=3):
        VERIFY_SUSPECT(timeout=1500):
        BARRIER():
        pbcast.NAKACK(use_mcast_xmit=false;gc_lag=0;retransmit_timeout=300,600,1200,2400,4800;discard_delivered_msgs=true):
        UNICAST(timeout=300,600,1200):
        pbcast.STABLE(stability_delay=1000;desired_avg_gossip=50000;max_bytes=400K):
        pbcast.GMS(print_local_addr=true;join_timeout=300;view_bundling=true):
        FC(max_credits=2M;min_threshold=0.10):
        FRAG2(frag_size=60K):
        pbcast.STREAMING_STATE_TRANSFER()"
    propertySeparator="::" />    

<!-- default query cache to be used for all queries without an explicit cache -->

<cache
    name="org.hibernate.cache.StandardQueryCache"
    maxElementsInMemory="100"
    eternal="false"
    timeToLiveSeconds="600"
    overflowToDisk="false"
    statistics="true">
    <cacheEventListenerFactory
        class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory"
        properties="replicateAsynchronously=true, replicatePuts=true,
        replicateUpdates=true, replicateUpdatesViaCopy=false, replicateRemovals=true" />
</cache>    

<!-- timestamps of particular last update time to tables -->

<cache
    name="org.hibernate.cache.UpdateTimestampsCache"
    maxElementsInMemory="5000"
    eternal="true"
    overflowToDisk="false"
    statistics="true">
    <cacheEventListenerFactory
        class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory"
        properties="replicateAsynchronously=true, replicatePuts=true,
        replicateUpdates=true, replicateUpdatesViaCopy=false, replicateRemovals=true" />
</cache>

<!-- default cache to use for all cacheable entities without an explicit cache -->

<defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="600"
        timeToLiveSeconds="600"
        overflowToDisk="false"
        maxElementsOnDisk="10000000"
        diskPersistent="false"
        diskExpiryThreadIntervalSeconds="600"
        memoryStoreEvictionPolicy="LRU"
        statistics="true">
        <cacheEventListenerFactory
            class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory"
            properties="replicateAsynchronously=true, replicatePuts=true,
            replicateUpdates=true, replicateUpdatesViaCopy=false, replicateRemovals=true" />
</defaultCache>

`


我可以通过使用ehcache调试日志级别实际看到,在缓存了条件查询的主机中接收到了插入(put)消息。但由于某种原因,查询没有过期。 - Rafael
以及 Hibernate 的配置呢? - matt b
前段时间,我们花费了很多时间尝试让Hibernate与分布式写缓存一起工作,但是没有成功。也许在过去的几年里它已经变得更好了,但我仍然建议您保留备选方案。例如,专门的应用程序缓存。Memcached或类似的东西。 - Alex Gitelman
2
你如何进行插入操作?你是否尝试通过JDBC而不是Hibernate进行记录的插入? - joostschouten
这里没有指定缓存类型。你确定你使用的是read-write而不是nonstrict-read-write或其他类型吗?在非read-write缓存上,数据保存可能会延迟。此外,显式刷新缓存也可以帮助解决问题。请务必检查设置。 - mico
显示剩余5条评论
2个回答

7
很抱歉,对于作者来说可能为时已晚,但是我认为我的答案可能对其他遇到同样问题的人有用。
您应该记住StandardQueryCacheUpdateTimestampsCache的工作原理。当查询缓存被检查一个查询时,查询被缓存的时间会与查询中所有表格的最后更新时间戳进行比较。如果任何表在查询被缓存之后进行了更新,则缓存结果将被丢弃并使用数据库。每个表的最后更新时间戳都存储在UpdateTimestampsCache中。
在上述配置中,UpdateTimestampsCache中的值未复制到群集的其他成员,因此Hibernate查看旧时间戳并认为缓存的查询是最新的。因此,新插入的记录被忽略了。要解决此问题,只需将UpdateTimestampsCachereplicateUpdatesViaCopy设置为true即可。

我有完全相同的问题。 "replicateUpdatesViaCopy" 设置为 true。 "eternal" 设置为 false。 仍然无法使查询缓存/更新时间戳缓存失效/复制。还有其他想法吗? - lars
@lars 首先,检查复制是否正常工作。如果您使用JGroups,请参见此处的“运行演示程序”(http://jgroups.org/manual4/index.html)。请注意`-Djava.net.preferIPv4Stack=true`部分,如果您无法在没有它的情况下运行演示,则还应将其添加到配置中。其次,您Ehcache配置中的其他内容可能有误。这里是一个对我有效的示例(http://pastebin.com/KEYCZdqm)。 - John29
明白了,是基本错误。我使用的时间戳缓存名称是"org.hibernate.cache.UpdateTimestampsCache",而不是正确的"org.hibernate.cache.spi.UpdateTimestampsCache"。 - lars

0

参考:Ehcache配置

请注意,当eternal属性设置为“true”时,它会覆盖timeToLive和timeToIdle,因此不会发生任何过期。

您有1个永久属性设置为true。也许您可以尝试将其设置为false,看看是否有帮助?


查询过期后,插入的行才被发现。我已经设置了120秒的过期时间。两分钟后,查询将获取插入的行。然而,我认为EHCache应该更加智能化,并找出新记录已被插入并使缓存表上的查询失效...或类似的操作... - Rafael

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