adam bien's blog

Glassfish v2ur2: Potential Data Corruption in Mixed JPA / DAO Usage - and The Solution 📎

During Glassfish v2ur2 EJB 3 tests together with JPA persistence I enountered the following problem: Direct changes to the database (SQL updates) performed using an injected DataSource in the same Bean-method, and so transaction, were not visible for the operations performed on the EntityManager (subsequent find). Only the old (cached)  entity was visible, without the changes performed in the DB.

Both EntityManager and DataSource were injected, whereas the EntityManager was configured in persistence.xml to use the same DataSource.

@Stateless
@Remote(VehicleManager.class)
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class VehicleManagerBean implements VehicleManager {

    @PersistenceContext
    private EntityManager entityManager;
    @Resource(mappedName="jdbc/db")
    private DataSource dataSource;
 }

Both resources; the EntityManager and DataSource participate in a transaction, so direct changes to the database should be visible to the EntityManager as well.

Nevertheless in the method below, the last find-method didn't reflected the changes made in the DB:

public Vehicle findChangeDBClearFind(int id, String newColor) {
        Vehicle vehicle = this.find(id);
        try {
         //changes the color of the vehicle directly in the DB
            this.changeVehiclesColor(id, newColor);
        } catch (Exception e) {
            throw new EJBException("Problem executing statement" + e, e);
        }
        this.entityManager.clear();

                    return this.find(id);
    }

 private void changeVehiclesColor(int id, String color) throws Exception {
        Connection connection = this.dataSource.getConnection();
        Statement statement = connection.createStatement();
        String sqlStatement = "update vehicle set color=\'" + color + "\' where id=" + id;
        int updatedRecords = statement.executeUpdate(sqlStatement);
        if (updatedRecords != 1) {
            throw new IllegalStateException("Vehicle with id: " + id + " cannot be updated!");
        }
        connection.close();
        statement.close();
    }

I assumed first, that the problem was the DataSource configuration. It turned out, however, that in the default configuration, TopLink essentials will not join the existing transaction. This can be achieved with the following setting in the persistence.xml:

        <property name="toplink.transaction.join-existing" value="true"/>

The property above is only available for TopLink Essentials 2.1 and so only for Glassfish v2.1+,v3 and not for Glassfish v2ur2. However I replaced the installed toplink-essentials.jar and toplink-essentials-agent.jar in the [GLASSFISH_HOME]\lib (existing Glassfish v2ur2 installation), and it worked as well. It is actually an already known bug. Btw. I tested Glassfish v2ur2 during the last weeks intensively, and this was the one and only  major issue. Beyond that I enountered only problems merging entities with @Version fields with the "big" types like Long, Integer etc. which is uncommon in real life project. I filed this bug as well. Thanks to Gordon Yorke for providing the property and the hints.