How to stop rollback in MDB?
I have a onMessage method where I'm reciving an ObjectMessage from the Queue and using that information to populate and persist a JPA entity object. But when something goes wrong while persisting the entity object it is re-executing the onMessage(). My guess is it is pushing the ObjectMessage back the queue and hence the onmessage is getting executed again. This way I'm entering an infinite loop. How can stop onMessage() to get execute again or control the no of times it gets executed. Here is the code I have. Error is happening at saveAuditData(auditInfo).
public void onMessage(Message inMessage) {
log.debug("Entering onMessage() Method.");
AuditInfo auditInfo = null;
try {
ObjectMessage om = (ObjectMessage) inMessage;
auditInfo = (AuditInfo) om.getObject();
log.debug("Message received : " + auditInfo.getApiUsed());
log.debug("Calling saveAuditData().");
saveAuditData(auditInfo);
log.debug("Leaving onMessage() Method.");
}
catch (Exception e) {
e.printStackTrace();
log.debug("Error persisting Audit Info.",e);
log.debug("Printing Audit Info:");
log.debug(auditInfo.toString());
}
}
private void saveAuditData(AuditInfo auditInfo) {
log.debug("Entering saveAuditData() Method.");
log.debug("Populating Audit Object.");
IdmAudit idmAudit = new IdmAudit();
idmAudit.setApiUsed("API");
idmAudit.setAppClientIpAddress("localhost");
idmAudit.setAuditActivity("activity1");
idmA开发者_如何学JAVAudit.setAuditData(auditInfo.getAuditData());
idmAudit.setAuditGroup(AUDIT_GROUP);
idmAudit.setAuditType("Type");
idmAudit.setIdmAuditCreationDate(new Date());
idmAudit.setLocationCd("Location");
idmAudit.setPurgeDate(null);
idmAudit.setSubscriberId(new BigDecimal(0));
idmAudit.setSuccessInd("Y");
idmAudit.setUserId(new BigDecimal(0));
idmAudit.setAuditSource("Source");
idmAudit.setVersionNumber(new BigDecimal(0));
log.debug("Saving Audit.");
entityManager.persist(idmAudit);
entityManager.flush();
log.debug("Leaving saveAuditData() Method.");
}
When a container-managed transaction is started by the container to process a JMS message, any failure in JDBC connections or exception thrown in the thread will result into a rollback of the global XA transaction. So the message goes back to the queue and will be retry later according to the queue configuration: period between retries, maximum number of retry before moving the message to a dead-letter queue.
So you have the following options:
Choose "Bean managed" transaction mode in your MDB deployment descriptor and use UserTransaction from lookup to
java:comp/UserTransaction
to callbegin
,commit
orrollback
manually, so care your exception handling.Keep "Container managed" transaction but query the redelivery count property on the JMS message to decide what to do next: either try again something that can fail or either skip this step and save your data in database. You can get redelivery info on your message from
Message.getJMSRedelivered()
orMessage.getLongProperty("JMSXDeliveryCount")
if your JMS provider delivers it.Or else, move your
saveAuditData
method to a EJB StatelessBean with transaction supportRequiresNew
in deployment descriptor so that a new transaction is created and your data is saved whatever happens to your MDB transaction. This option can be combined with the previous one.
You can simply mark the onMessage method with the TransactionType annotation:
@TransactionAttribute(value=TransactionAttributeType.REQUIRES_NEW)
public void onMessage(Message message) {
.....
}
精彩评论