GWT 和 JPA 并发,@PersistenceContext,NullPointerException
GWT and JPA concurrency, @PersistenceContext, NullPointerException
我有一个纯粹的 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 项目中时,我遇到了一些非常难以 debug/solve 的问题。
问题 1:
如果我使用上面的 JPAUtil class 实例化 EntityManagers 以用于每个 RPC 请求,它就可以工作。但是,如果 GWT 客户端开始向服务器端发出多个请求,而服务器端又试图从 JPA 层拉取数据,则读取时会发生多个神秘的 ConcurrencyException(有或没有延迟加载 - 似乎没有区别) .
当我不使用上述 class 时,我尝试 "inject" 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
您需要同步对 HashMap
的访问,因为许多 RPC 请求可以由多个线程并行处理。建议您将 HashMap
替换为 ConcurrentHashMap
或将同步放在 em
方法上。
@Inject
可能无法工作,因为 GWT servlet 不支持 CDI。
我有一个纯粹的 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 项目中时,我遇到了一些非常难以 debug/solve 的问题。
问题 1:
如果我使用上面的 JPAUtil class 实例化 EntityManagers 以用于每个 RPC 请求,它就可以工作。但是,如果 GWT 客户端开始向服务器端发出多个请求,而服务器端又试图从 JPA 层拉取数据,则读取时会发生多个神秘的 ConcurrencyException(有或没有延迟加载 - 似乎没有区别) .
当我不使用上述 class 时,我尝试 "inject" 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
您需要同步对 HashMap
的访问,因为许多 RPC 请求可以由多个线程并行处理。建议您将 HashMap
替换为 ConcurrentHashMap
或将同步放在 em
方法上。
@Inject
可能无法工作,因为 GWT servlet 不支持 CDI。