I need to remember this, so I’ll post it.
Spring transaction (annotations or proxies) will join the current session, which is associated with the current thread of execution, if there is one or create a new session if there isn’t one. This is the default behavior. However, if you specify REQUIRES_NEW it creates a new Session for that particular method invocation, which also brings along a new transaction. This is expected, but I never really believe it until I sout the hell out of an application just to make certain.
Exceptions that get thrown will always rollback the transaction regardless of where it was started. This invalidates the session as well. The trick is to ensure that methods that could fail always start new transactions. The reason being that for the most part each request to a web application can reuse the same transaction for almost all operations. The only operations that fail are usually insert, update and delete operations, which should probably be wrapped in separate transactions to ensure that the outer transaction stays intact and usable during the entire request.