How to catch OptimisticLockException in JPA - java

I've read out a couple of questions here regarding the OptimisticLockException with JPA, used in an stateless session bean. It is thrown, but not where I expect it obviously.
Here is the code where I expect to get the exception:
try
{
productFacade.edit(product);
}
catch(Exception {
return "lock";
}
The productFacade is generated with NetBeans and it is an EJB with a local interface, an it implements an AbstractFacade abstract class. As far as I read, this has something to do with transactions in JPA. Because the exception is thrown after the method this code snippet is in is left, not after edit() is called. Where should I than handle the exception?
Also, I will be needing the transaction mechanism for later, because I will need to update multiple products (or none if some is locked). I've found some code examples, but this leaves me wondering how should I work with transactions?

The lock error will not be thrown until the transaction commits. So you would need to handle it outside of your SessionBean or use a container managed transaction.
Or, you could just call flush() on your JPA EntityManager, then the error will be thrown.

use save and flash and catch with Exception
try {
log.info("save data versions: " + employee.getVersion());
someRepository.saveAndFlush(employee);
} catch (Exception ex) {
log.info("catch Exception");
throw new OptimisticLockException("retry data Exception");
}
if want to use retry can add anotation #Retryable with some flagging

Related

Logger clean up Using Spring AOP

We're trying to introduce generic logger in our application using Spring AOP for log statements which are under catch block.
Before AOP
try
{
\\Business Logic
}
catch(Exception e){
\\some recovery mechanism that won't be generic across different layers
log.error();//These statements needs to be moved to generic logger
}
After going through Spring Docs,I have found this can be done using AfterThrowing advice.
After throwing advice is Advice to be executed if a method exits by throwing an exception.
In order to do this We'll to change our existing exception handling code by re throwing Exception inside catch block something like this for AfterThrowing Advice to work.
After AOP:
try
{
\\Business Logic
}
catch(Exception e){
\\some recovery mechanism that won't be generic across different layers
throw e;
}
AOP code:
#Aspect
#Sl4j
#Component
public class LoggingAdvice {
#AfterThrowing(pointcut = "execution (* * com..*(..)", throwing = "e")
public void myAfterThrowing(JoinPoint joinPoint, Exception e) {
log.error("Exception occured",e);
}
}
Do you think is there any better solution than this rather than rethrowing Exception in catch block and propagating it upwards as per call hierarchy?
Note any raised or unchecked exceptions would be catched anyway by AfterThrowing Advice..All i want to do is perform logger clean up by removing log.error inside catch block and have it generic using AOP.
As was discussed here, #AfterThrowing is nice for logging exceptions which are actually thrown.
Your case is quite special as you want to log exceptions which are being caught/handled. If you use full AspectJ instead of Spring AOP for this use case you can use a handler(*) pointcut as described with sample code in this answer. It would enable you to factor out your log statements from your catch blocks without the need to escalate (re-throw) exceptions which have already been properly handled, thus changing your logic and making it necessary to catch them somewhere else later.
The better approach is to remove the catch blocks as you are going to use #AfterThrowing anyway. And implement whatever you want to implement on top that aspect execution.

Force Hibernate To Save A Specific POJO

I have some code calling a webservice and it returns an ID. I am saving this ID in the database using hibernate. I have a filter that opens the session and commits it, rolling back when any exception occurs within the contained code. Since there is no way to get back the ID returned by the webservice I would like to save this in the database EVEN if there is an exception that occurred later on in the code. Is there anyway to do this using the same session?
It depends on who throws the exception. If it is thrown by the hibernate session object you cannot reuse the session anymore as stated in hibernate Session documentation:
If the Session throws an exception, the transaction must be rolled back and the session discarded. The internal state of the Session might not be consistent with the database after the exception occurs.
If the exception is thrown by some other code, then yes, you can do something like this:
Long yourIdFromWebservice = ...
try {
// do some processing that might result in an exception
}
catch(//the interesting exception, but not HibernateException) {
//maybe log it, rethrow it
}
finally {
session.save() //save what needed to be saved
}
or depending on your use case:
try {
// do some processing that might result in an exception
session.save() //save all stuff if no exception
}
catch(//the interesting exception, but not HibernateException) {
session.save() //save only the id from the webservice
}
The right way to do that is to use two transactions: one to save the ID, and one to save the rest of your work.
If you're using EJB, you could do the save of the ID in a bean of its own, and annotate it with a TransactionAttribute of REQUIRES_NEW.
Otherwise, you can look at what control over transactions your environment gives you, and figure out a way to have two of them.

MyBatis mapper injected directly into service class. What about exceptions?

I'm currently working with MyBatis-Spring integration framework and that's what I read from docs:
Rather than code data access objects (DAOs) manually using SqlSessionDaoSupport or SqlSessionTemplate,
Mybatis-Spring provides a proxy factory: MapperFactoryBean. This class lets you inject data mapper interfaces
directly into your service beans. When using mappers you simply call them as you have always called your
DAOs, but you won't need to code any DAO implementation because MyBatis-Spring will create a proxy for
you.
That's a very nice feature... but what about exception handling? Where should I translate SQL errors? In my service layer? But wouldn't it violate service-DAO patterns?
Example:
public final class AccountServiceImpl implements AccountService {
(...)
private AccountMapper accountMapper;
(...)
#Override
public void addAccount(Account account) throws AccountServiceException {
//Validating, processing, setting timestamps etc.
(...)
//Persistence:
int rowsAffected;
try {
rowsAffected = accountMapper.insertAccount(account);
} catch (Exception e) {
String msg = e.getMessage();
if (msg.contains("accounts_pkey"))
throw new AccountServiceException("Username already exists!");
if (msg.contains("accounts_email_key"))
throw new AccountServiceException("E-mail already exists!");
throw new AccountServiceException(APP_ERROR);
}
LOG.debug("Rows affected: '{}'", rowsAffected);
if (rowsAffected != 1)
throw new AccountServiceException(APP_ERROR);
}
Is it OK to translate exceptions in service layer?
How should it be done?
Thanks in advance for you advice.
Having recently used mybatis-spring for a project I came across the same stumbling block. I also didn't want to litter my service class with DAO exception handling, particularly since some methods in my service layer required read-only access to a lot of different tables.
The solution I arrived at was to catch the exceptions in the service layer but create your own exception type that takes the caught exception as a parameter. This can then filter out what kind of error message should be contained when the exception is actually constructed and remove the need for string matching (in the service layer at least).
You are close to that there, except the AccountServiceException would have a constructor that took the Exception e as a parameter. I also chose to try and do all my data access as early as possible and wrap it all in a single try/catch. Since the MapperFactoryBean always translates thrown exceptions in to Spring DataAccessExceptions you don't have to worry about catching other kinds of exceptions when doing data access.
I hesitate to consider this an answer as such - more of a sharing of experience given I came across that and hesitated as well.
Translating low level DataAccessExceptions thrown by MyBatis to application-defined ones in service layer is a standard practice.
It's usually connected to transaction handling as you can't handle the transaction spanning multiple DAOs in DA layer.
So yes it's OK and even recommended.
Normally I log the exceptions thrown by DAO in error log and rethrow something defined by application.

Which is the best way to handle exception in java MDB?

I got this use case:
Here the class diagram
Here the sequence diagram
This diagram represents an enterprise model. Java EE technology on Weblogic 10.3 with the leverage of spring framework for IoC and AOP, JPA for persistence with spring jpatemplate, spring integration for the interaction frame.
As you can see there is no coupling between the Service and the Gateway since spring integration add all the magic sugar needed.
Now I have to deal with the exception handling. All the chain has no checked exceptions: also the data access has no checked exception since jpatemplate wraps all the sql exception in runtime exceptions.
So the only checked exception that I handle is on the MDB
#Override
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void onMessage(Message message) {
try {
TextMessage textMessage = (TextMessage) message;
String stringMessage = textMessage.getText();
OnlineEventMessage<? extends Serializable> event = eventMessageParser.parse(stringMessage);
legacyEventMessageService.handle(event);
} catch (JMSException e) {
logger.error("si e' verificato un errore JMS nel processamento dell'evento {}", message, e);
}
}
I noticed that if I get a NPE for example on some component of the chain the message is rolled back on the JMS queue and the process is looped back.
Which is the best way to handle exceptions in this scenario?
Catch all the runtimeExceptions in the MDB?
Kind regards
Massimo
Which is the best way to handle exceptions in this scenario? Catch all the runtimeExceptions in the MDB?
It depends on what you want to achieve. If feel from your description that you want to prevent the message being rolled back. Is that right?
In that case catching all run time exceptions gets you only so far. The system could also throw errors, which you won't catch then. So you have to catch Throwable instead. But, then the transaction could still time out, resulting in a roll-back.
In short, do you want your MDB to be transactional at all?
Also note that the transaction context from the sender does not propagate to the MDB.
Slightly off topic, but are you really sure you need jpatemplate? It seems pretty much everybody has agreed that the JPA API is fine by itself and doesn't need any 'enhancements' from Spring, including SpringSource themselves.

EJB3 - handling RollBackExceptions

I have an EJB3 application which consists of some EJB's for accessing a DB, and exposed via a Session Bean as a web service.
Now there are two things I need to find out:
1) Is there any way I can stop SQL exceptions from causing the web service from throwing a SOAP Fault? The transactions are handled by the container, and currently sql exceptions cause a RollBackException to be thrown, and consequently the transaction to be rolled back (desired behaviour) and the web service to throw a fault (not desired).
2) I wish to extend the webservice to be able to take in a list of entities, and the session bean to persist each. However, I want each entity to be executed in its own transaction, so that if one fails the others are not affected (and again the web service should not fault).
For (1) I have tried to catch the RollBackException, but I assume this is thrown somewhere on another thread, as the catch block is never reached. I assume for (2) I will need to look into User Transactions, but firstly would prefer the container to manage this, and secondly do not know how to force the use of user transactions.
Thanks.
no, you can do all this with container managed transactions (and this is definitely preferable, as managing transactions is a pain).
the gist of the solution is to create a second EJB with a local interface only and the transaction semantics you desire. then your "public" ejb, which the web-service is calling directly, calls into this second ejb via its local interface to do the actual work.
something along the lines of:
public class MyPublicEjb {
#EJB
private MyPrivateImpl impl;
public void doSomething() {
try {
impl.doSomething();
} catch(TXRolledBack) {
// handle rollback ...
}
}
}
I know this looks sort of ugly, but trust me, this is far preferable to directly manipulating transactions.
For (1): Debug your code to find out where the exception is being thrown and what is causing it. Then handle the exception there.
For (2): Wrap each instance with beginTransaction() and commit().
for(each Entity){
try{
//begin transaction
//save entity
//commit
} catch(Exception e) {
//handle Exception, but continue on
}
}

Categories