Issue
I am pretty new to Kotlin and Spring and had a very basic doubt. Consider a function like this:
@transaction
fun accept() {
try {
write to table A
throw Exception()
} catch(){
write to table B
}
}
Question: I understand that Table B write will be successful, but will the table A write succeed? and why? Any pointers to
Solution
Spring has a bit of a bizarre take on what exceptions 'mean'. It acts as follows. A transaction method doesn't commit anything until it exits. i.e. this:
@transaction
fun accept() {
write to table A
while (true) {} // loop forever
}
trivially never actually commits anything, that's probably obvious. Otherwise, the method exits, and it can exit in one of three ways:
- The method 'returns'. As in, no exception is thrown out of the method - exceptions might be thrown, but they are caught. Then upon exiting the method, the transaction is committed. Note that this describes your snippet - which does not throw an exception out of the method. Hence, the write to table A and B will both happen and be visible from outside parties!
- The method finishes by throwing an UNCHECKED exception. Spring's opinion is that this is 'unexpected', and indicates the result of executing the method is failure - the entire transaction is aborted. the write to table A will not be visible to other transactions, ever, nor would the write to table B (let's imagine that after the catch block, you have
throw new RuntimeException()
, which is unchecked). - The method ends by throwing a CHECKED exception out. Spring's opinion is that this must mean that it is 'intentional', and indicates that the code succeeded; it simply chose to "return" an exception instead of finishing up normally. The transaction is committed - the write to table A will be visible to others. The write to table B will also be visible to others (this is assuming that you add
throw new IOException()
to the end of your accept method, and of course that your method is allowed to do that. Which in java means it has to be declared asvoid accept() throws IOException {}
, of course.
The notion of checked and unchecked does not exist in kotlin - in kotlin, all exceptions are 'unchecked', effectively. However, spring doesn't go: "OOoooohhhh, kotlin user, I'll just treat everything as if it was unchecked, i.e. any exceptions thrown result in a aborted transaction". Nope, so, you must learn what checked exceptions are even if you write only kotlin.
Unchecked exceptions are all throwables that have in their type hierarchy either java.lang.Error
(such as java.lang.InternalError
, which extends j.l.Error
), or java.lang.RuntimeException
, such as NullPointerException
.
All other throwables are 'checked'. Such as IOException
, which extends Exception. which extends Throwable. Exception
itself is checked.
NB: You can add interceptors and the like to change this behaviour; "checked exception means we need to commit, checked means we need to abort" is merely the default behaviour.
Answered By - rzwitserloot
Answer Checked By - Pedro (JavaFixing Volunteer)