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(...)
?
source to share
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
}
}
source to share