I do this in
JSF. JPA didn't exist back when I worked with Struts. The same concepts apply, however.
What I do is actually define 2 persistence tiers: The business persistence tier (services) and the per-table persistence tier (DAOs). Although classes in both tiers are defined transactional, the business persistence tier is the one normally entered from the business logic (and hence from the Struts Action), so when business persistence invokes DAOs, they're part of the business persistence transaction.
Just in case it isn't clear - a lot of operations require a graph of several different tables in order to do their thing, My DAOs are intended for per-table CRUD operations (although I sometimes include parent-child table constructs). The Service methods work with the total graph, and invoke the DAOs for their sub-components.
Once the service has returned to its caller, not only is the transaction completed (committed or rolled back), but also, if it returns a graph, that graph consists of detached objects. I don't believe in keeping "live" ORM model objects at the higher levels or passing live objects to the rendering phase. It's extra overhead and somewhat dangerous.
I also cheat. I use the Spring Framework to manage the transactions and inject the EntityManagers into the DAOs. The service methods do not persist directly (they invoke DAOs), so even though they are transactional, EntityManagers are not injected into them.