【问题标题】:Hibernate Second Level Cache and HudsonHibernate 二级缓存和 Hudson
【发布时间】:2023-10-29 03:53:01
【问题描述】:

我将 SecondLevelCache 与休眠一起使用。这是我的xml配置文件:

    <persistence-unit name="EntityTestHibernate" transaction-type="RESOURCE_LOCAL">
        <properties>
            <property name="hibernate.show_sql" value="false"/>
            <property name="hibernate.format_sql" value="false"/>
            <property name="hibernate.connection.url" value="jdbc:postgresql://localhost:5432/DB_NAME"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
            <property name="hibernate.connection.driver_class" value="org.postgresql.Driver"/>
            <property name="hibernate.connection.username" value="USERNAME"/>
            <property name="hibernate.connection.password" value="PASSWORD"/>            
            <property name="hibernate.cache.use_second_level_cache" value="true"/>             
            <property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.EhCacheProvider" />


我的 ehcache.xml:

<ehcache name="cacheTest" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
    <defaultCache eternal="true" maxElementsInMemory="100" overflowToDisk="false" />
    <cache  name="entityCache" 
            maxEntriesLocalHeap="50"
            eternal="false"
            timeToLiveSeconds="120"         
    />
</ehcache>

在我的实体上有这样的注释

@Cache(region="entityCache", usage=CacheConcurrencyStrategy.READ_WRITE )

当我在本地运行我的 UnitTest 时,我没有问题。所有测试都通过了,但是如果我在 Hudson continuos 集成上运行测试,我会遇到以下错误(如果我在 @DirtiesContext 上设置或没有注释,问题是相同的):

>     javax.persistence.PersistenceException: org.hibernate.cache.CacheException: java.lang.IllegalStateException:
> The cacheTest Cache is not alive (STATUS_SHUTDOWN)    at
> org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1167)
>   at
> org.hibernate.ejb.AbstractEntityManagerImpl.refresh(AbstractEntityManagerImpl.java:673)
>   at
> org.hibernate.ejb.AbstractEntityManagerImpl.refresh(AbstractEntityManagerImpl.java:641)
> Caused by: org.hibernate.cache.CacheException:
> java.lang.IllegalStateException: The cacheTest Cache is not alive
> (STATUS_SHUTDOWN)     at
> net.sf.ehcache.hibernate.regions.EhcacheTransactionalDataRegion.remove(EhcacheTransactionalDataRegion.java:164)
>   at
> net.sf.ehcache.hibernate.strategy.AbstractEhcacheAccessStrategy.evict(AbstractEhcacheAccessStrategy.java:119)
>   at
> net.sf.ehcache.hibernate.nonstop.NonstopAwareEntityRegionAccessStrategy.evict(NonstopAwareEntityRegionAccessStrategy.java:96)
>   at
> org.hibernate.event.def.DefaultRefreshEventListener.onRefresh(DefaultRefreshEventListener.java:144)
>   at
> org.hibernate.event.def.DefaultRefreshEventListener.onRefresh(DefaultRefreshEventListener.java:62)
>   at org.hibernate.impl.SessionImpl.fireRefresh(SessionImpl.java:1118)
>   at org.hibernate.impl.SessionImpl.refresh(SessionImpl.java:1098)    at
> org.hibernate.ejb.AbstractEntityManagerImpl.refresh(AbstractEntityManagerImpl.java:666)
> Caused by: java.lang.IllegalStateException: The cacheTest Cache is
> not alive (STATUS_SHUTDOWN)   at
> net.sf.ehcache.Cache$CacheStatus.checkAlive(Cache.java:3946)  at
> net.sf.ehcache.Cache.checkStatus(Cache.java:2664)     at
> net.sf.ehcache.Cache.removeInternal(Cache.java:2288)  at
> net.sf.ehcache.Cache.remove(Cache.java:2207)  at
> net.sf.ehcache.Cache.remove(Cache.java:2125)  at
> net.sf.ehcache.hibernate.regions.EhcacheTransactionalDataRegion.remove(EhcacheTransactionalDataRegion.java:160)

我该如何解决这个问题? 为什么这只发生在哈德逊?


更新

正如@lanimall 所建议的,我有:

  • 已禁用 Hudson 上的所有节点;
  • 修改persistence.xml。

更换

< property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.EhCacheProvider" />

<property name="hibernate.cache.region.factory_class" value="net.sf.ehcache.hibernate.SingletonEhCacheRegionFactory" />

但这并不能解决我的问题(但这是一个很好的开始:-)...错误是一样的)。

我的环境配置是hibernate3和ehcache-2.7.2

【问题讨论】:

    标签: java hibernate hudson ehcache second-level-cache


    【解决方案1】:

    你使用的是什么版本的休眠?和Ehcache? 我认为可能发生的情况是 hudson 正在某些应用程序服务器上运行(例如 Glassfish、Tomcat 5、JBoss、Jetty 6 等),并且它可能有一些 ehcache 或 hibernate lib 版本与您正在竞争的那些嵌入到您的应用程序中......因此问题仅在哈德逊运行测试时发生。一定要调查一下……

    另外,根据 ehcache/hibernate 文档 (http://ehcache.org/documentation/user-guide/hibernate#Configure-Ehcache-as-the-Second-Level-Cache-Provider),请尝试使用“hibernate.cache.region.factory_class”设置而不是“hibernate.cache.provider_class”...

    而且我通常也使用单例工厂(否则您的 JUNIT 测试将无法正常工作......)。基于休眠版本,使用 hibernate.cache.region.factory_class=net.sf.ehcache.hibernate.SingletonEhCacheRegionFactory

    或(对于休眠 4.x 及更高版本)

    hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory

    希望对您有所帮助...

    【讨论】:

    • 按照你的建议,我有:禁用 Hudson 上的所有节点修改persistence.xml&lt;property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.EhCacheProvider" /&gt; 替换为&lt;property name="hibernate.cache.region.factory_class" value="net.sf.ehcache.hibernate.SingletonEhCacheRegionFactory" /&gt;;但这并不能解决我的问题(但这是一个很好的开始:-)...错误是一样的)。我的环境配置是hibernate3和ehcache-2.7.2
    • 有趣...你在哪个应用服务器上运行 hudson?
    • 看起来哈德森的某些东西正在(错误地)关闭缓存管理器......现在我正在考虑更多,用于哈德森测试的单例工厂可能不适合使用...因为 hudson 可能会在每次测试结束时关闭缓存管理器...如果您使用单例,那么这意味着实例此后保持关闭状态?我会尝试非单例工厂:net.sf.ehcache.hibernate.EhCacheRegionFactory.
    • AppServer 是 Tomcat 6。我也曾想过 Hudson 每次测试都会关闭缓存,但这种行为在本地应该是相同的。显然这个其他配置(EHCacheRegioFactory)的问题是:Another CacheManager with same name 'cacheTest' already exists in the same VM. Please provide unique names for each CacheManager in the config or do one of following: [junit] 1. Use one of the CacheManager.create() static factory methods to reuse same CacheManager with same name or create one if necessary [junit] 2. Shutdown the earlier cacheManager before creating new one with same name.
    【解决方案2】:

    我找到了解决办法!

    在我的 persistence.xml 中,我将 2 个持久性单元配置为单例,并且在某些测试中两者都使用了。这样,那些共享 EhCacheSingleton。

    然后发生的情况是,当与其中一个关联的 EntityFactory 被关闭时,导致另一个被另一个使用的 ehcache 关闭(因为在这两个实体管理器之间共享一个 Singleton 实例)。

    非常感谢@lanimall 让我敞开心扉!

    【讨论】:

      【解决方案3】:

      JUnit 共享 Spring 上下文以提高速度。在我的一项测试中明确删除 Spring 上下文关闭时,我避免了此异常。

      【讨论】: