Hibernate refresh() or getSingleResult() returns a cached entity (?)

Viewed 164

I am using Hibernate 2.1 on a Wildfly (JBoss) 10 to fetch an entity from the Database. Here is the model of the entity:

@Entity
@Table(name = "account")
@NamedQuery(name = "Account.findAll", query = "SELECT a FROM Account a")
public class Account implements Serializable {

     private int id;
     private double balance;
     private double bonus;

     @Id
     public int getId() {
        return this.id;
     }
     // Rest of the fields/setters/getters ommited
}

I have implemented a REST API call that updates the balance of a given account. The account is first retrieved from the database, validated, then the balance is updated through a separate bean-managed transaction in MySQL. After this completes I am asked to do some other operation on the account, on which I need the (new) updated balance. Find code attached below:

@Stateless
@Path("/financial")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class FinancialApi {
   
   @Inject private AccountBean accountBean;
   @Inject private AccountBalanceBean accountBalanceBean;

   @POST
   @Path("/balance/add")
   public Response addBalance(TransactionProperties properties) {
      Account account;
      try {
         account = accountBean.get(properties.getAccountId());
         validateAccount(account);
      } catch (ValidationException ex) {
          return Response.status(Response.Status.BAD_REQUEST).build();
      }
      // Update balance
      accountBalanceBean.updateBalance(account.getId(), properties.getAmount());
      // Refresh from DB to retrieve updated balance
      accountBean.refresh(account);
      // Do stuff with refreshed account data here
      return Response.ok().build();
   }
}

The "DAO" EJB handling the account

@Stateless
@LocalBean
public class AccountEJBean {
   
    @PersistenceContext(unitName = "my-unit-name")
    private EntityManager em;

    public Account get(int id) {
        try {
           return (Account) em.createQuery("SELECT a FROM Account a WHERE a.id = :id")
                        .setParameter("id", id)
                        .setMaxResults(1)
                        .getSingleResult();
        } catch (NoResultException ex) {
            return null;
        }
    }

    public void refresh(Account account) {
         em.refresh(account);
    }

}

and a (severely reduced) sample of the EJB that uses bean-managed transactions to update account balance:

@Stateless
@LocalBean
@TransactionManagement(TransactionManagementType.BEAN)
public class AccountBalanceEJBean {

        @PersistenceContext(unitName = "my-unit-name")
        private EntityManager em;
        @Resource
        private UserTransaction transaction;
         
        public boolean updateBalance(int id, float price) {
            try {
                transaction.begin();
                getUpdateQuery(id, price).executeUpdate();
                transaction.commit();
            } catch (Exception ex) { 
                transaction.rolloback();
            }
        }
}

and here is my persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence">
  <persistence-unit name="my-unit-name" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:/jboss/datasources/SQLDatasource</jta-data-source>
    <class>mypackage.Account</class>
    <properties>
      <property name="hibernate.generate_statistics" value="false"/>
      <property name="hibernate.connection.useUnicode" value="true"/>
      <property name="hibernate.connection.characterEncoding" value="UTF-8"/>
    </properties>
    </persistence-unit>
</persistence>

This works perfectly fine until the part where I am trying to refresh account data from the database. At this point the account is refreshed with no issue on every case I have tried but the data of the account do not get updated. I am still retrieving the "stale" data that the account had when retrieved initially. After looking around for some time I figured it may be related to Hibernate caching mechanism. I have tried the following:

  1. Detaching the entity on the get() method from the EntityManager and replacing refresh() with get()
  2. Calling em.clear() and then retrieving the entity with a get() call again.
  3. Attempting to clear the cache using em.getEntityManagerFactory().get().evictAll()
  4. Setting hints "javax.persistence.cache.retrieveMode" and "javax.persistence.cache.storeMode" to BYPASS on the query of the get() method.

None of those seems to be working. I have tried updating the entity in my code and setting random values and every time the entity is refreshed in the initial retrieval state (not the one that is in the database, even if I alter different fields than balance not mentioned here).

From my understanding second-level cache is disabled by default on Hibernate and as far as I can tell that's not the case here. With this in my mind I move to the first-level cache but I can't seem to understand how to retrieve a Session (or if a session even exists here) from the entity manager in order to clear that cache which seems to be causing the problem. As a side note I am not sure of what's the point of having a first-level cache that doesn't get overriden by refresh() method and how this works in a distributed environment.

If that helps the Instance of the EntityManager that is injected is an instance of class org.jboss.as.jpa.container.TransactionScopedEntityManager.

Any ideas?

UPDATE: I have replicated the get() code in a second bean, let's call it AccountBean2 that's also injected into the API class. It seems to be working now. I am pretty confident it's a caching issue at this point but I am still not sure how to correct the initial issue so the question remains.

0 Answers
Related