1
votes

My Spring application is layered as Bean, Service and DAO. All the @Transactional annotations are in service layer.

This is the pseudo code in one particular scenario.

UserBean.java

saveUser() {
    userService.manageUser();
}

UserServiceImpl.java

@Transactional
public void manageUser() {
    userDAO.createUser();
    userDAO.updateParentUser();
}

UserDAOImpl.java

createUser() {
    //insert user record in database
}

updateParentUser() {
    //update parent user's database record
}

In my save user test case, the update parent user operation can fail in some cases due to primary key violation which is kind of expected.

As the @Transactional annotation is implemented in service class, this violation exception will be notified in bean class only.

What is the option to get this PK violation notification in my service class? [Then I can handle it from there in a different business process.]

If I add a new method in service class and call manageUser() from there the @Transactional annotation will not work properly. This is due to the limitation/property of AOP. Spring expects external call to @Transactional methods.

3
What do you mean when you say "this violation exception will be notified in the bean class only". Surely if the exception is being thrown in the service class, then you can also catch it in the service class and deal with it properly?ConMan
@ConMan this exception happens when the @ Transactional method is 'exited'. So with the current code I will not be able to catch it in service class.Sam

3 Answers

2
votes
  1. Use programmatic transaction management and handle exceptions in try catch block
  2. Introduce a delegate class and do manageUser in a transaction there:

    @Transactional(REQUIRED)
    public void manageUser() {
        try{
           delegate.manageUser();
        } catch (Exception ex ) {
        //handle
        }
    }
    

    And in delegate class

    @Transactional(REQUIRES_NEW)
    public void manageUser() {
    }
    
2
votes

The create/update won't be committed until you return from the @Transactional method. If the create/update is flushed to the database before that then you may get the exception within the method, but in your case it's not being flushed until the commit.

You can force the create/update to be flushed before the commit. You don't say whether you're using Hibernate or JPA, but session.flush() or entityManager.flush() should do the trick.

0
votes

Instead of Spring proxy based AOP I moved to AspectJ approach. This gives me the flexibility to make my manageUser() method call from another method of same service class and I can handle the exception there.