具有 JPA 事务的 JAX-WS Web 服务

JAX-WS Webservice with JPA transactions

我要为 JPA 疯狂了...

我有一个类似的 JAX-WS Webservice

@WebService
public class MyService
{
    @EJB private MyDbService myDbService;

    ...
    System.out.println(dmrService.read());
    ...
}

我的 EJB 包含

@Stateless
public class MyDbService
{
    @PersistenceContext(unitName="mypu")
    private EntityManager entityManager;

    public MyEntity read()
    {
    MyEntity myEntity;

    String queryString = "SELECT ... WHERE e.name = :type";

    TypedQuery<MyEntity> query = entityManager.createQuery(queryString,MyEntity.class);
    query.setParameter("type","xyz");

    try
    {
        myEntity= query.getSingleResult();
    }
    catch (Exception e)
    {
        myEntity= null;
    }

    return myEntity;
}

在我的 persistence.xmlmyputransaction-type="JTA"jta-data-source

如果我调用网络服务,它就可以工作。从数据库中检索实体。

现在,我正在使用外部工具更改记录中一个字段的值。

我正在再次调用网络服务并且...显示的实体包含旧值。

如果我再次部署,或者如果我在请求后添加一个 entityManager.refresh(myEntity),我又得到了很好的价值。

别生气很好

流程是这样的。

  • 你发出了一个查询,说 where type="xyz"
  • 现在 Hibernate 将此查询或状态保存在缓存中,这样如果您再次触发查询,如果状态未更改,它将return相同的值。
  • 现在您正在从一些外部资源更新详细信息。
  • Hibernate 对此一无所知
  • 因此,当您再次触发查询时,它 returns 来自 catch
  • 当您进行刷新时,休眠会从数据库中获取详细信息

解决方案:

  1. 因此您可以在调用 get 调用之前添加刷新

  1. 在应用程序中使用 Hibernate 方法更改 Table 值,以便 Hibernate 了解更改。

  1. 禁用 Hibernate 缓存以每次从数据库查询(不推荐,因为它会减慢速度)

在@MyTwoCents 中,选项 2 是不使用您的 'external' 工具进行更改,而是使用您的应用程序。如果您的应用程序知道所有正在发生的更改,或者有某种方式可以了解这些更改,则缓存会更有用。这是更好的选择,但前提是您的应用程序可以成为数据的单一访问点。

强制刷新,通过 EntityManager.refresh() 或通过 provider specific query hints on specific queries, or by invalidating the cache as described here https://wiki.eclipse.org/EclipseLink/Examples/JPA/Caching#How_to_refresh_the_cache 是另一种选择。这会强制 JPA 越过缓存并根据特定查询访问数据库。这样做的问题是您必须知道缓存何时过时并且需要刷新,或者将其放在不能容忍过时数据的查询上。如果这种情况相当频繁或在每个查询中都出现,那么您的应用程序将完成维护未使用的缓存的所有工作。

最后一个选项是turn off the second level cache。这会强制查询始终将实体从数据库数据加载到 EntityManager 中,而不是二级缓存。您降低了过时数据的风险(但不是消除它,因为 EntityManager 需要为托管实体拥有自己的一级缓存,代表事务缓存),但是以重新加载和重建实体为代价,如果它们有,有时是不必要的之前被其他线程阅读过。

哪个最好完全取决于应用程序及其预期用例。