Reputation: 65
Hi I am trying to log exception into the DB
public void a(){
try{
String c = b();
}catch (Throwable ex){
com.log.Logger.log(ex);
throw new UserDefinedException(ex);
}
}
public String b(){
throw new NullPointerException("Transaction Logger")
}
I have a LoggerImpl class which logs the details of the exception into DB. Only the UserDefinedException is getting logged where as the Null Pointer Exception is not. Could any one Plz help me.
LogEntry.java
private long id;
private String desc;
// getters and setters
Logger.java
public long log(Throwble ex){
LogEntry entry = new LogEntry();
entry.setDesc(ex.getMessage());
LoggerImpl log = new LoggerImpl();
log.insertLog(entry);
return entry.getId();
}
LoggerImpl.java
@Transactional(propogation = PROPOGATION.REQUIRES_NEW)
public void insertLog(LogEntry log){
insert.update(//fields);
}
Id is generated using a Sequence Incrementer
I am using JTA Transaction Manager.
Upvotes: 1
Views: 3601
Reputation: 6073
You got such results because in your case LoggerImplementation class isn't managed by Spring container and container doesn't start new transaction for insertLog(..) method (as it supposed to be). To make this class managed you should inject it in your bean. I propose you to make such refactoring. This will work.
Instead of having Logger and LoggerImpl classes create Logger interface and LoggerImpl class that implements this interface.
public interface Logger {
long log(Throwable ex);
}
@Transactional
@Component
public final class LoggerImpl implements Logger {
@PersistenceContext
private EntityManager entityManager;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public long log(Throwable ex) {
LogEntry entry = new LogEntry();
entry.setDescription(ex.getMessage());
entityManager.persist(entry);
return entry.getId();
}
}
And then simply inject your exceptions Logger into necessary service class. For example:
@Transactional(rollbackFor=Exception.class)
@Service
public class TestService {
@Autowired
private Logger logger;
public void a() throws UserDefinedException {
try {
b();
} catch (Throwable ex) {
logger.log(ex);
throw new UserDefinedException(ex);
}
}
public String b() {
throw new NullPointerException("Transaction Logger");
}
}
Now outer transaction will be rolled back but inner new transaction will write data to DB.
Note rollbackFor attribute in @Transactional annotation for TestService class. This is necessary because by default Spring will not rollback transaction for chacked exceptions. This described behaviour that you got. In your case outer transaction was rollbacked only for runtime exceptions. That's why when you try to log NullPointerException the whole transaction is rolled back and your log record isn't added to the DB. But when you try to log UserDefinedException transaction is successfully commited despite the fact that error have been thrown and your log record is written to the DB.
Upvotes: 2