This is all considerably more abstraction than I have wanted or needed when writing Java. When handling transactions, I’ve passed around the same connection before committing.
The point of the transaction in this context is that both the database(s) and the business logic/state stay in sync. I don’t think that naive attempts will be logically correct.
As I mentioned, you will have to roll back not only the database, but the relevant application state as well. This is really error-prone if repeated enough times, or the flow of control is through many different methods, etc.
By application state, do you mean something like an in memory cache? I would prefer having no such state in the first place, and have all meaningful state in the DB to be pulled out or mutated as needed.
I recognize that what you’re advocating for makes of sense in some applications, I just wanted to point out that I haven’t felt the need for it in my eight years of software development.