【问题标题】:GWT and JPA concurrency, @PersistenceContext, NullPointerExceptionGWT 和 JPA 并发,@PersistenceContext,NullPointerException
【发布时间】:2015-01-11 06:01:16
【问题描述】:

我有一个纯 JAVA 项目,我在 Eclipse 中使用 maven 开发该项目。它具有使用 JPA 和 EclipseLink 的持久性功能,可将数据保存到 Apache Derby。该项目在单元测试和独立的 java 应用程序中完美运行,我直接从我的代码中实例化 EntityManagerFactory:

public class JPAUtil
{
    private static EntityManagerFactory     factory                 = Persistence.createEntityManagerFactory("unit-name");
    private static Map<Long, EntityManager> ems                     = new HashMap<Long, EntityManager>();

    private JPAUtil(){}

    /**
     * Get an entity manager
     */
    public static EntityManager em(Long id)
    {       
        EntityManager result = null;
        if (ems.containsKey(id))
        {
            result = ems.get(id);
            if(!result.isOpen())
            {
                result = createEntityManager();
                ems.put(id, result);
            }
        }
        else
        {
            result = createEntityManager();
            ems.put(id, result);
        }

        return result;
    }

    private static EntityManager createEntityManager()
    {
        EntityManager result =
                    // factory.createEntityManager(SynchronizationType.SYNCHRONIZED);
                    factory.createEntityManager();
        return result;
    }
}

现在,当我将它添加到 GWT 项目中时,我遇到了一些非常难以调试/解决的问题。

问题一:

如果我使用上面的 JPAUtil 类来实例化 EntityManagers 以用于每个 RPC 请求,它就可以工作。但是,如果 GWT 客户端开始向服务器端发出多个请求,而服务器端又试图从 JPA 层提取数据,则读取时会发生多个神秘的 ConcurrencyException(有或没有延迟加载 - 似乎没有区别) .

当我不使用上述类时,我尝试使用以下行将 EntityManager“注入”到 GWT ServiceImpls(servlet)中,尝试访问数据层时会发生 NullPointerException 崩溃:

@PersistenceContext(unitName = "unit-name")
transient protected EntityManager   em;

我显然在想,这将是从 GWT 访问持久层的更合适的方式。但是,我在访问 EntityManager 时得到 NullPointerExceptions,因此 GWT 的开发 Jetty 服务器无法自行注入 EntityManager。我处理这类问题的能力似乎有限,我的 Google-FU 似乎也很无奈。所以提出一个具体的问题:

在后端使用 JPA 创建快速、稳定的 GWT 应用程序的最佳方法是什么?

提前谢谢你, el.nicko

【问题讨论】:

    标签: java jpa gwt eclipselink


    【解决方案1】:

    您需要同步您对HashMap 的访问,因为多个 RPC 请求可以由多个线程并行处理。建议您将HashMap 替换为ConcurrentHashMap 或将同步放在em 方法上。

    @Inject 可能无法工作,因为 GWT servlet 不支持 CDI。

    【讨论】:

    • 感谢您的回答!不知道我是怎么错过的。您提出的更改减少了向用户抛出的 ConcurrencyExceptions。它似乎没有完全解决这个问题。然而,更深入地挖掘一天:它解决了同时写入数据库的问题,但不是读取,这是最令人沮丧的部分,因为它根本不应该发生。并发读取问题隐藏在 DAO 层的深处,其中一个 DAO 拥有 EntityManager 的本地副本。删除它解决了问题。愚蠢的人为错误 :-) 非常感谢,标记为已解决。
    • 关于一个稍微相关的主题 - 启用 EntityManager 注入而不是由应用程序控制它的最合适的方法是什么?春天?如果它适用于所有应用程序容器,那将是最好的。
    • 很高兴听到。我在 gwt plus spring 方面的经验不足,尽管这可能是可行的。建议您将此作为一个新问题提出。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 2018-01-20
    • 1970-01-01
    • 2011-06-10
    • 1970-01-01
    • 2016-09-04
    相关资源
    最近更新 更多