JTA/XA is a kind of system insurance against data corruption (and the resulting business losses). The most common use cases are:
Processing JMS messages from a queue and inserting the results in a database: you don't want a crash to lose messages whose results are not yet stored in the database.
Updating two or more legacy back-end systems in the same transaction
In general, whenever you access more than one back-end system in the same transaction the use of JTA/XA is highly recommended. Otherwise, the risk of data loss or corruption is too high (and not necessarily visible!).
Many programmers try to avoid the "overhead" of JTA/XA by programming application-specific recovery code (such as trying to handle duplicate requests, storing extra state in the database, etc). However, all these approaches are brittle (not reusable, application-specific, and hard to test). In the end, the perceived overhead of JTA/XA is often replaced by equivalent but buggy overhead at the application level.
A sample