During a transaction, the logic for a given persistent object is always executed in the same order. In many cases, it can be helpful to understand this order:
- Early actions get executed first. They can modify the object as needed, but (by definition) they don't have access to the result of the rest of the logic, since they're the first to be executed.
- Parent copies are next
- Then formulas.
- Then constraints
- Then actions
- Any changes that may affect child objects are then processed. If any child object is modified because it depends on the original object, we enter a new level of recursion.
- We then adjust any parent aggregates. In this case too, any parent object that is modified because it depends on the original object will trigger a new level of recursion.
- Commit actions are executed last, just before the actual commit.
- And finally the transaction is committed.
If an exception is thrown at any point during this process, the transaction will not be committed, but it will not be rolled back either: that is up to the code that invoked the original commit. If you are using a framework like Spring, the framework will often handle the rollback automatically.
This order has some obvious implications. For instance, constraints are executed before actions, which means that actions will not get executed if a constraint fails.