public String updateKeyValueDatabase(String key, String value) { EntityManager entityManager = entityManagerFactory.createEntityManager(); try { userTransaction.begin(); /* * Since the Entity Manager (EM) is not managed by the container the developer must explicitly tell the EM * to join the transaction. Compare this with ManagedComponent where the container automatically * enlists the EM with the transaction. The persistence context managed by the EM will then be scoped * to the JTA transaction which means that all entities will be detached when the transaction commits. */ entityManager.joinTransaction(); // make some transactional changes String result = updateKeyValueDatabase(entityManager, key, value); /* * Note that the default scope of entities managed by the EM is transaction. Thus once the transaction * commits the entity will be detached from the EM. See also the comment in the finally block below. */ userTransaction.commit(); return result; } catch (RollbackException e) { // We tried to commit the transaction but it has already been rolled back (adding duplicate // keys would // generate this condition although the example does check for duplicates). Throwable t = e.getCause(); return t != null ? t.getMessage() : e.getMessage(); } catch (Exception e) { /* * An application cannot handle any of the other exceptions raised by begin and commit so we just * catch the generic exception. The meaning of the other exceptions is: * * NotSupportedException - the thread is already associated with a transaction * HeuristicRollbackException - should not happen since the example is interacting with a single database * HeuristicMixedException - should not happen since the example is interacting with a single database * SystemException - the TM raised an unexpected error. There is no standard way of handling this error * (another reason why CMT are preferable to managing them ourselves) */ return e.getMessage(); } finally { /* * Since the EM is transaction scoped it will not detach its objects even when calling close on it * until the transaction completes. Therefore we must roll back any active transaction before returning. */ try { if (userTransaction.getStatus() == Status.STATUS_ACTIVE) userTransaction.rollback(); } catch (Throwable e) { // ignore } entityManager.close(); } }