0

This is my connection detail in JBoss standalone.xml

<connection-url>
    jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=xx.1xx.119.1xx)(PORT=1521))(LOAD_BALANCE=on)(FAILOVER=on))(CONNECT_DATA=(SERVICE_NAME=XE)))
</connection-url>

I want to handle a corner case of failover where post getting EntityManager object during a call of persist(), the connection is lost. Failover option is not switching to next database in the same transaction, it switches to active connection in the next transaction. I attempted something like this: (Catch Exception and get updated bean object)

public EntityManager getEntityManager() {
    try {
        entityManager = getEntityManagerDao(Constant.JNDI_NFVD_ASSURANCE_ENTITY_MANAGER);

    } catch (NamingException e) {
        LOGGER.severe("Data could not be persisted.");
        throw new PersistenceException();
    }
    return entityManager.getEntityManager();
}

/**
 * Inserts record in database. In case multiple connections/databases exist, one more attempt will be made to
 * insert record.
 *
 * @param entry
 */
public void persist(Object entry) {
    try {
        getEntityManager().persist(entry);
    } catch (PersistenceException pe) {
        LOGGER.info("Could not persist data. Trying new DB connection.");
        getEntityManager().persist(entry);
    }
}

private static Object getJNDIObject(String path) throws NamingException {
    Object jndiObject = null;
    InitialContext initialContext = new InitialContext();
    jndiObject = initialContext.lookup(path);
    return jndiObject;
}

private static AssuranceEntityManager getEntityManagerDao(String path) throws NamingException {
    return (AssuranceEntityManager) getJNDIObject(path);
}

But this one also is not helping. After catching the exception, getting a new bean with JNDI lookup does not contain an updated new connection and an exception is thrown. This results in loss of data of that transaction.

Please suggest how to handle this corner case of "Connection lost post getting EntityManager and before persisting."

TT.
  • 15,774
  • 6
  • 47
  • 88

1 Answers1

0

I think it's quite impossible what you want to achieve. The thing is that if internal DB transction is aborted then the JTA transaction is in abort state and you can't continue with it.

I expect it's kind of similar to this case

 @Stateless
 public class TableCreator {
    @Resource
    DataSource datasource;

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void create() {
        try(Connection connection = datasource.getConnection()) {
            Statement st = connection.createStatement();
            st.execute("CREATE TABLE user (id INTEGER NOT NULL, name VARCHAR(255))");
        } catch (SQLException sqle) {
           // ignore this as table already exists
        }
    }
 }

 @Stateless
 public class Inserter {
   @EJB
   private TableCreator creator;

    public void call() {
        creator.create();

        UserEntity entity = new UserEntity(1, "EAP QE");
        em.persist(entity);
    }
 }

In case that table user exists and you would use annotation @TransactionAttribute(TransactionAttributeType.REQUIRED) then the create call will be part of the same jta global transaction as call of persist. As in such case the transaction was aborted the persist call would fail with exception like (postgresql case)

Caused by: org.postgresql.util.PSQLException: ERROR: current transaction is aborted, commands ignored until end of transaction block

I mean if Oracle jdbc driver is not able to to handle connection fail transparently to JBoss app server and throws the exception upwards then I think that the only possible solution is to repeat the whole update action.

chalda
  • 702
  • 4
  • 18