A typical stack of technologies used in small scale Java web development shops is the following:
- JPA
- Spring
- Some MVC web framework like Struts, Spring MVC or Wicket.
The problem though, is the way Spring documentation is worded, it pushes the wrong approach for many web application engineers. I am looking at you LocalContainerEntityManagerFactoryBean! According to the Spring docs, this is the "most powerful" way to configure an Entity Manager. My reaction: O Rly?
The issue is that such an Entity Manager necessitates the use of application level transactions. Most people read the Spring documentation and say: "Hmmm, do I need transactions in my code? Eh, sure why not." That's is the wrong assumption. Very few of the service layer calls in typical, small-scale web applications actually need application level transaction support, because they mostly are atomic operations (insert, update, delete, select).
This is actually one of the chief reasons the J2EE platform has not been as successfull in small scale agile environments: their obsessive focus on transaction support, and specifically, distributed transaction support. This focus resulted in the notoriously slow EJB standard. Spring solves much of the complexity of J2EE. As part of their attack strategy, they market their product as a non-invasive alternative, but engineer it to be a full replacement. An engineer reading "most powerful" in the docs will use that Bean instead of the much better suited for small apps LocalEntityManagerFactoryBean. Unfortunately, that bean type cannot be configured with different data sources, prompting even more people to use the Local Container Entity Manager Bean.
The point is, you do not lose database transaction support if you go with the LocalEntityManagerFactoryBean. Why? Because they are not provided by Spring, they are provided by your database server. You can still .begin() and .commit() as well as .rollback() transactions through your JPA Entity Manager's getTransaction() method. This means you can add transaction support for a small subset of your service layer database calls, and everyone's a winner!