When actually performing the execution of the "batched" statement (whether from BatchingBatch or NonBatchingBatch) any exception should cause the rest of the batch to be aborted.
I was going to log something similar to HHH-7688 - Bug in NonBatchingBatch makes session ununsable after failed transaction Complete but it's a bit different as that change only covers the NonBatchingBatch where in my case it was the BatchingBatch impl causing me the grief.
The full details got lost in my notes and it also involved using a SavePoint extension so I wasn't sure if I was inducing some of my own pain at the time but I think there's something there.
The complete details are a bit fuzzy but this is what I had recorded...
The abortBatch() in the JdbcCoordinatorImpl is only called when it encounters a SQLException. However, when executing the batch Hibernate catches the original SQLException and rethrows a different exception which causes the abortBatch() not to be called.
In the event that Hibernate got to the executeBatch() stage the worst that happens is that any registered batch listeners are not removed. Under a previous patch I ensured that the clearStatements() included a call to clear the batch.
However, if it gets to the point where the execute hasn't actually been called yet, i.e. a validation exception occurs then the batch isn't actually cleared until the session controlling the transaction is closed. This isn't usually an issue since the exception is typically bubbled up the stack and everything is rolled back. However, in our case, we have some SavePoint functionality that required a workaround. I believe Spring would also encounter the same sort of issue.
The statements like this from addToBatch() in BatchingBatch are what cause the abortBatch to get bypassed.
Then in places that are wrapping the addToBatchCall, i.e. the insert method of AbstractEntityPersister you end up with...
However, by this point it seems like the Exception has been rewrapped to a GenericJDBCException which doesn't extend from SQLException and blows out.
In my case I ended up catching the exception in my extension and manually calling it but I think the Spring guys use the same concept (I think it's how their nested transaction functionality works)