Search code examples
javajpaeclipselinkweblogic12c

JAX-WS Webservice with JPA transactions


I'm going to become mad with JPA...

I have a JAX-WS Webservice like that

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

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

My EJB contains

@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;
}

In my persistence.xml the mypu has transaction-type="JTA" and a jta-data-source

If I call the webservice, it's working. The entity is retrieved from the db.

Now, using an external tool, I'm changing the value of one field in my record.

I'm calling the webservice again and ... the entity displayed contains the old value.

If I'm deploying again, or if I'm adding a entityManager.refresh(myEntity) after the request, I have the good value again.


Solution

  • In @MyTwoCents answer, Option 2 is to NOT use your 'external' tool for changes, use your application instead. Caching is of more use if your application knows about all the changes going on, or has some way of being informed of them. This is the better option, but only if your application can be the single access point for the data.

    Forcing a refresh, via EntityManager.refresh() or through 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 is another option. This forces JPA to go past the cache and access the database on the specific query. Problems with this are you must either know when the cache is stale and needs to be refreshed, or put it on queries that cannot tolerate stale data. If that is fairly frequent or on every query, then your application is going through all the work of maintaining a cache that isn't used.

    The last option is to turn off the second level cache. This forces queries to always load entities into an EntityManager from the database data, not a second level cache. You reduce the risk of stale data (but not eliminate it, as the EntityManager is required to have its own first level cache for managed entities, representing a transactional cache), but at the cost of reloading and rebuilding entities, sometimes unnecessarily if they have been read before by other threads.

    Which is best depends entirely on the application and its expected use cases.