【问题标题】:how to implement a cache in ejb 3.0?如何在 ejb 3.0 中实现缓存?
【发布时间】:2013-12-26 09:29:03
【问题描述】:

我有一个客户被困在 EJB 3.0 环境中。没有@Singleton,没有 bean 管理的并发 :-(

考虑到ejb规范禁止线程管理和同步,如何实现缓存?本质上,我想要一个非同步对象缓存来处理一些昂贵的操作。

【问题讨论】:

  • 不确定我是否完全理解 segaste,但 applicationscoped cdi bean 会这样做吗?
  • 不,这个 Java EE 5 环境中没有 CDI,这不能解决同步问题。我不需要单例,只需 @Singleton 形成 ejb 3.1 + bean-managed concurrency 就可以解决问题。
  • 您是否考虑过使用池大小最大值 = 1 的无状态?
  • 嗯,这是一个有趣的想法,但我不想让所有无状态 bean 的池大小为 1 ;-)
  • @ymajoros 您可以为特定的 bean 定义此属性,您使用的是哪个服务器?

标签: jakarta-ee concurrency ejb ejb-3.0 java-ee-5


【解决方案1】:

使用静态字段和同步的限制在 EJB 3.0 规范第 21.1.2 章中说明。它还解释了原因。

• 企业 bean 不得使用读/写静态字段。使用 允许只读静态字段。因此,建议 企业 bean 类中的所有静态字段都声明为 final。

需要此规则以确保一致的运行时语义,因为 而一些 EJB 容器可能使用单个 JVM 来执行所有 企业 bean 的实例,其他人可以分发实例 跨多个JVM。

• 企业 bean 不得使用线程 同步原语同步执行多个 实例。

这与上面的原因相同。同步不起作用 如果 EJB 容器将企业 bean 的实例分布在 多个 JVM。

如果您通过单例 POJO 实现缓存,如果 EJB 容器将 EJB 实例分布在多个 JVM 上,例如在集群环境中,您可能会面临每个 JVM 中实际上存在多个缓存实例的风险。

这要看情况,

  • 如果应用程序未部署在集群环境中,您可以这样做。据我所知,WebLogic 和 GlassFish 在一个 JVM 中运行一个服务器实例。
  • 如果不严格要求数据一致性,您也可以这样做。通常在谈论“缓存”时是允许的。

如果它不适合您,您可能应该考虑在 EJB 容器之外缓存数据,例如放入 Redis 或 Hazelcast。

【讨论】:

  • 感谢您指出原因,这真的很有趣。我宁愿遵守规则:不要自己处理同步。您无法确定容器是否会很好地使用它,并且您无法完美测试,因为它只能在极少数情况下“失败”(=死锁)。我想我会选择一个不一致但不同步的缓存。
【解决方案2】:

我怀疑我是否清楚地理解了你的问题!以下示例基于weblogiceclipselink

如果您为 EJB 使用 eclipselink JPA,您可以像这样分别为每个实体使用缓存:

@Entity
@Cache(type=CacheType.SOFT)

如果需要,您还可以为 persistence.xml 文件中的所有实体启用缓存。属性字段内会是这样的(oracle doc's link):

<persistence-unit name="XYZ">
...
    <class>com.stack.Test</class>
    <properties>
        ...
        <property name="toplink.cache.type.default" value="Soft"/>
        ...
    </properties>
</persistence-unit>

缓存类型可以是不同的,如软、硬、弱、完整等。它们中的每一个都有自己的含义。您可以从here 找到有关此缓存类型的更多信息。

【讨论】:

  • 您的示例不是特定于 weblogic 的(但仅适用于 eclipselink)。但它适用于 JPA 实体,我正在寻找通用缓存。 Eclipselink 缓存也只会缓存以主键为键的实体,这在我的情况下是不够的。我更多的是寻找线程问题的通用解决方案。
【解决方案3】:

在 EJB 容器中是否禁止使用 volatile 变量? volatile int 变量提供了一些对多线程代码有用的保证。如果一个线程看到一个 volatile 变量的变化,那么可以安全地假设它看到了之前发生的一切。

另一个想法是只实例化一次的@Stateful bean(调用将由容器序列化)。不过,我不确定实施细节。

【讨论】:

  • “易失性变量”是指易失性字段。不能在无状态 bean 中使用。你有原子性问题。它根本没有解决问题:你仍然需要一个共享缓存,我的问题是关于它的实现。有状态会话 bean 不是由您实例化的,而是与状态相关的。因此,您最终会得到多个会话 bean(每个用户会话至少一个)。感谢您的建议,但他们没有回答问题。
  • 我想知道你是怎么做的。当您完成某种方式时,请告诉我们。
  • 所以我的想法用完了......这可能吗?
  • 我建议我的客户使用 ConcurrentSkipListMap,看我的回答。
【解决方案4】:

嗯,我认为ConcurrentSkipListMap 可能是解决方案:没有同步但仍然是线程安全的。

【讨论】:

    【解决方案5】:

    我将 Redis 与 Jedis 一起用于内存中的临时值。

    请看下面的链接

    https://redislabs.com/lp/redis-java/

    Redis 带有适用于多个操作系统的安装程序。

    例子:

    import redis.clients.jedis.Jedis; 
    
    public class RedisStringJava { 
       public static void main(String[] args) { 
          //Connecting to Redis server on localhost 
          Jedis jedis = new Jedis("localhost"); 
          System.out.println("Connected"); 
          //set the data in redis string and expire in default time
          jedis.set("param_name", "Param value"); 
          // Get the stored data and print it 
          System.out.println("Stored string in redis:: "+ jedis.get("param_name")); 
       } 
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-16
      • 1970-01-01
      • 1970-01-01
      • 2011-10-27
      • 1970-01-01
      相关资源
      最近更新 更多