Exception handling in @Transactional class

Within my Spring-installed ( @Transactional

and @Service

annotations) I have the following method:

@Transactional
@Service
public class Foo {

    @Autowired
    private MyService service; // MyService has @Service and @Transactional annotations


      public void save(...) { 
          try { 
              service.save(...); // gets a Hibernate Session & calls `merge(...)`
          } catch(DataIntegrityViolationException e) {
             logMessage("save failed with exception: " + e);
          }
      }

      

In my respective table (which Foo#save

does the job of saving), I have unique constraint

.

When the above code Foo#save

is executed in such a way that the unique constraint is violated, I can see in my log what is selected DataIntegrityViolationException

, but it does not fall into my block Foo#save

catch

.

   org.springframework.orm.jpa.JpaTransactionManager 891 doRollbackOnCommitException - 
     Initiating transaction rollback after commit exception 
   org.springframework.dao.DataIntegrityViolationException: Could not execute 
       JDBC batch update; SQL [insert into MY_TABLE ...; constraint 
         [MY_CONSTRAINT]; nested exception is 
       org.hibernate.exception.ConstraintViolationException: Could not execute 
    JDBC batch update

      

Vaguely DataIntegrityViolationException

not caught, I added another catch for everyone RuntimeException

:

      public save(...) { 
          try { 
              service.save(...); // `service` is marked with 
                                 //  @Service and @Transactional
          } catch(DataIntegrityViolationException e) {
             logMessage("save failed with exception: " + e);
          } catch(RuntimeException e) {
             logMesssage("runtime exception e: " + e);
          }
      }

      

But, again, when I ran the same code that would violate a unique constraint violation, I didn't see the log message from the block catch(RuntimeException e)

.

My incomplete understanding is that since I am using the @Transactional

proxy Foo

(created by Spring) will make the method call save

.

But, is it possible for me to catch the DataIntegrityViolationException

called service.save(...)

?

+3


source to share


1 answer


The method session.merge(...)

does not execute a direct SQL insert / update query, but enqueues this action. The SQL query will be executed when the session flushes. In your case, the session will be cleared in the transactional advice after your method is executed and an exception will be thrown there.

So to throw an exception in your method add session.flush()

after session.merge(...)

like this:



  public class MyService {

      public void save(Object o) {
         Session session = //get session somehow
         session.merge(o);
         session.flush();  // In case of data integrity violation Exception will be thrown here
      }
  }

      

+1


source







All Articles