I am using JPA with Spring. If I were to let Spring handle the transactions, then this is what my Service layer would look like assuming the EntityManager has been properly injected into the DAOs:
MyService {
#Transactional
public void myMethod() {
myDaoA.doSomething();
myDaoB.doSomething();
}
}
However, if I were to do transactions manually, I have to make sure to pass that instance of EntityManager into each of the DAOs within a transaction. Any idea how can this be better refactored? I fee ugly doing new MyDaoA(em) or passing em into each DAO method like doSomething(em).
MyService {
private EntityManagerFactory emf;
public void myMethod() {
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
MyDaoA myDaoA = new MyDaoA(em);
MyDaoB myDaoB = new MyDaoB(em);
try {
tx.begin();
myDaoA.doSomething();
myDaoB.doSomething();
tx.commit();
} catch(Exception e) {
tx.rollback();
}
}
}
However, if I were to do transactions
manually, I have to make sure to pass
that instance of EntityManager into
each of the DAOs within a transaction.
This is where you are wrong. From the Spring Reference, JPA section:
The main problem with such a DAO is
that it always creates a new
EntityManager through the factory. You
can avoid this by requesting a
transactional EntityManager (also
called "shared EntityManager" because
it is a shared, thread-safe proxy for
the actual transactional
EntityManager) to be injected instead
of the factory:
public class ProductDaoImpl implements ProductDao {
#PersistenceContext
private EntityManager em;
public Collection loadProductsByCategory(String category) {
Query query = em.createQuery(
"from Product as p where p.category = :category");
query.setParameter("category", category);
return query.getResultList();
}
}
The #PersistenceContext annotation has
an optional attribute type, which
defaults to
PersistenceContextType.TRANSACTION.
This default is what you need to
receive a shared EntityManager proxy.
add this to your spring config
<bean p:entityManagerFactory-ref="emf" class='org.springframework.orm.jpa.support.SharedEntityManagerBean' />
now you can #Autowired EntityManager inside your dao
for the transaction management, since you already using spring, and #Transactional annotation, i assume you already have one transaction manager declared in your spring.xml
so using spring's transaction management
as
transactionStatus = platformTransactionManager.getTransaction(new DefaultTransactionDefinition());
// do your work here
platformTransactionManager.commit(transactionStatus );
Shot in the dark a bit I guess, but do you know you can do:
TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
That usually eliminates the majority of cases where you would want/need to use programmatic transactions in a system that otherwise has declarative transactions.
Related
I would like to know which way is the best to define entity manager. I am using spring boot
case 1) creating in spring service class like follows
#Service
#Transactional
public class DemoService {
private static final Logger log = LoggerFactory.getLogger(DemoService.class);
private EntityManagerFactory emf;
public void getEntity(){
final EntityManager em = emf.createEntityManager();
}
#PersistenceUnit
public void setEntityManagerFactory(final EntityManagerFactory emf) {
this.emf = emf;
}
}
Case 2.) Define a global entity manager and share it across all services.
Note : Each service only reflects one single Entity definition.
Injecting the EntityManager is the simplest and the most effective way to do it:
#PersistenceContext(unitName = "persistenceUnit")
private EntityManager entityManager;
You don't need to set the EntityManagerFactory, since you need a transaction-bound EntityManager.
You don't need to hold the EntityManager in a global component, since that would be yet another indirection layer and you can simply mock the EntityManager anyway.
I have an application built on Spring. I let the Spring do the all #Transactional magic and everything works fine as long as I operate on my entities that are mapped to Java objects.
However, when I want to do some custom job on a table that is not mapped to any of my Java entities, I'm stuck. Some time ago, I found a solution to execute a custom query like this:
// em is instance of EntityManager
em.getTransaction().begin();
Statement st = em.unwrap(Connection.class).createStatement();
ResultSet rs = st.executeQuery("SELECT custom FROM my_data");
em.getTransaction().commit();
When I try this with the entity manager injected from Spring with the #PersistenceContext annotation, I receive almost obvious exception:
java.lang.IllegalStateException:
Not allowed to create transaction on shared EntityManager -
use Spring transactions or EJB CMT instead
I finally managed to extract non-shared Entity Manager like this:
#Inject
public void myCustomSqlExecutor(EntityManagerFactory emf){
EntityManager em = emf.createEntityManager();
// the em.unwrap(...) stuff from above works fine here
}
Nevertheless, I find this solution neither comfortable nor elegant. I just wonder if there is any other way to run custom SQL queries in this Spring-transactional-driven environment?
For those who are curious - this problem appeared when I tried to create user accounts in my application and in the related forum at once - I did not want the forum's users table to be mapped to any of my Java entities.
You can use createNativeQuery to execute any arbitrary SQL on your database.
EntityManager em = emf.createEntityManager();
List<Object> results = em.createNativeQuery("SELECT custom FROM my_data").getResultList();
The above answer still holds true but I would like to edit in some additional information that may also be relevant to people looking at this question.
While it is true that you can use the createNativeQuery method to execute native queries through an EntityManager; there is an alternative (arguably better) way of doing it if you are using the Spring Framework.
The alternative method for executing queries with Spring (that will behave with the configured transactions) is to use the JDBCTemplate. It is possible to use both the JDBCTemplate and a JPA EntityManager within the same application. The configuration would look something like this:
InfrastructureConfig.class:
#Configuration
#Import(AppConfig.class)
public class InfrastructureConfig {
#Bean //Creates an in-memory database.
public DataSource dataSource(){
return new EmbeddedDatabaseBuilder().build();
}
#Bean //Creates our EntityManagerFactory
public AbstractEntityManagerFactoryBean entityManagerFactory(DataSource dataSource){
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource);
emf.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
return emf;
}
#Bean //Creates our PlatformTransactionManager. Registering both the EntityManagerFactory and the DataSource to be shared by the EMF and JDBCTemplate
public PlatformTransactionManager transactionManager(EntityManagerFactory emf, DataSource dataSource){
JpaTransactionManager tm = new JpaTransactionManager(emf);
tm.setDataSource(dataSource);
return tm;
}
}
AppConfig.class:
#Configuration
#EnableTransactionManagement
public class AppConfig {
#Bean
public MyService myTransactionalService(DomainRepository domainRepository) {
return new MyServiceImpl(domainRepository);
}
#Bean
public DomainRepository domainRepository(JdbcTemplate template){
return new JpaAndJdbcDomainRepository(template);
}
#Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource){
JdbcTemplate template = new JdbcTemplate(dataSource);
return template;
}
}
And an example repository that would use both JPA and JDBC:
public class JpaAndJdbcDomainRepository implements DomainRepository{
private JdbcTemplate template;
private EntityManager entityManager;
//Inject the JdbcTemplate (or the DataSource and construct a new JdbcTemplate)
public DomainRepository(JdbcTemplate template){
this.template = template;
}
//Inject the EntityManager
#PersistenceContext
void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
//Execute a JPA query
public DomainObject getDomainObject(Long id){
return entityManager.find(id);
}
//Execute a native SQL Query
public List<Map<String,Object>> getData(){
return template.queryForList("select custom from my_data");
}
}
You can use EntityManager.createNativeQuery(String sql) to use direct sql code or use EntityManager.createNamedQuery(String name) to execute precompiled query.
You still use spring-managed Entity manager, but working on non managed objects
In a project of mine I'm trying to switch management of my persistence from application to container. I'm following these instructions: http://docs.oracle.com/javaee/6/tutorial/doc/gkhrg.html
I've read about EntityManager not being thread safe and just want to make sure that my setup is correct. My concern: http://weblogs.java.net/blog/2005/12/19/dont-use-persistencecontext-web-app.
I have a class that produces a persistence context.
#Singleton
public class JpaResourceProducer {
//The "pu" unit is defined with transaction-type="JTA"
#Produces
#PersistenceUnit(unitName = "pu")
#Database
EntityManagerFactory databasePersistenceUnit;
#Produces
#PersistenceContext(unitName = "pu")
#Database
EntityManager databaseEntityManager;
/* Alternative
#PersistenceContext(unitName = "pu")
private EntityManager em;
#Produces
#UserDatabase
public EntityManager create() {
return em;
}
public void close(#Disposes #Database EntityManager em) {
em.close();
}
*/
}
Then I have a jax-rs resource that injects a DAO.
#RequestScoped
#Path("/endpoint")
public class MyResource {
#Inject private Dao dao;
#GET
#Produces({MediaType.APPLICATION_JSON})
public Converter get() {
MyEntity entity = dao.find(1);
Converter converter = new Converter(entity);
return converter;
}
}
And finally a DAO where I inject the EntityManager.
#Singleton
public class JpaDao<T, K extends Serializable> implements Dao<T, K> {
protected Class<T> entityClass;
#Inject
#Database
EntityManager em;
public JpaDao() {
ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
this.entityClass = (Class<T>) genericSuperclass.getActualTypeArguments()[0];
}
public T find(K id) {
return em.find(entityClass, id);
}
....
}
1. Is this a good setup in terms of thread safety and overall performance?
Bonus questions:
In the JpaResourceProducer I have an alternative setup for the EntityManager where I manually close the manager on dispose.
2. Is the container handling close of my EntityManager automatically?
The example from Oracle includes an EntityManagerFactory.
3. Do I really need an EntityManagerFactory when I'm using CMP?
What's your container? From annotations used I presume it is at least Java EE 6 Web Profile compatible, and in that case you're overcomplicating this.
The tutorial presents producting of multiple persistence units. Is this the case in your application? If not, plain injection into EJBs would be more relieable and less magical - I am also unsure about transactional behaviour of a singleton-produced persistence context.
Singleton JpaDAO means, there can be only one database operation at a time in your application, so this is serious performance bottleneck. It should be Stateless instead (and having its persistence context injected by traditional means).
In general, implement your DAOs and Business logic, even your JAX-RS endpoints as session EJBs, and let container handle concurrency and transactions properly.
Also use other sources of examples, e. g. Adam Bien's JavaEE Patterns.
I am currently trying to figure out the best way to get a entity manager and a usertransaction in my application.
In JBoss 5.1 I was able to inject it directly into the JSP file, but this is not permitted anymore:
<%!#PersistenceContext(unitName = "unitname")
public EntityManager em;
#Resource
UserTransaction utx;
%>
I have to access em and utx from different locations in my application such as Servlets and Controller classes. So it would be great to have it in one place and to access it globally, but I did not figure out yet how to do it. Any hint would be appreciated.
I found out how to get the EntityManager and the UserTransaction in Servlets, Controller Classes and JSP files.
Let's start with SessionBeans. I redefined all my controller classes as Stateless SessionBeans. Session Beans allow ressource injection. This is how I did it:
#Stateless
public class UserHandling {
#PersistenceContext(unitName = "SSIS2")
private static EntityManager em;
#Resource
private UserTransaction utx;
public User getUser(int userId) {
User userObject = em.find(User.class, userId);
return userObject;
}
}
If another Session Bean is needed in a Session Bean Class, it can be injected with the #EJB annotation:
#Stateless
public class UserHandling {
#PersistenceContext(unitName = "SSIS2")
private static EntityManager em;
#Resource
private UserTransaction utx;
#EJB
UserHandling uh; RoleHandling rh;
public User getUser(int userId) {
User userObject = em.find(User.class, userId);
return userObject;
}
}
In JSP files, you can get the Session Bean Controller classes by lookup the InitialContext:
<%
InitialContext ic = new InitialContext();
UserHandling uh = (UserHandling) ic.lookup("java:app/" + application.getContextPath() + "/UserHandling");
%>
The Issue being Solved
Servlets and JSPs must be stateless because they are shared across multiple threads. An EntityManager does keep state, and so a single instance cannot be shared by concurrent threads.
We'd like a smooth/seamless mechanism for obtaining an EntityManager, preferably managed by the Servlet container.
Servlet-Container Managed Persistence Context
Let's introduce a ContainerManagedPersistenceContext into the Servlet/JSP runtime.
We'll define it in a moment. Let's first look at how it can be used to inject an EntityManager into JSP:
<%! #Inject
#ContainerManagedPersistenceContext.Qualifier
public EntityManager em;
%>
or, better yet into a controller (because we do want to separate data recovery/business logic from our JSP, right?):
#Named
#SessionScoped
public class SessionController implements Serializable
{
...
#Inject
#ContainerManagedPersistenceContext.Qualifier
private EntityManager em;
}
But I don't (yet) have CDI available
If you don't have CDI, but you do have JSF, then the context can be injected as an old-style standard JSF #ManagedProperty:
#Named
#SessionScoped
public class SessionController implements Serializable
{
...
#ManagedProperty(value = "#{containerManagedPersistenceContext}")
ContainerManagedPersistenceContext cmpContext;
...
public void myMethod() {
EntityManager em = cmpContext.getEntityManager();
try {
...
} finally {
em.close();
}
}
}
Remember that - for all the same reasons that we have to go to this effort in the first place - the EntityManager must never be cached/preserved anywhere.
Transactions
Use the EntityTransaction provided by the EntityManager for begin/commit/rollback:
EntityTransaction transaction = em.getTransaction();
ContainerManagedPersistenceContext
This is defined as an application scoped controller and a PersistenceContext:
#PersistenceContext(name = ContainerManagedPersistenceContext.NAME,
unitName = ContainerManagedPersistenceContext.UNIT_NAME)
#ApplicationScoped
public class ContainerManagedPersistenceContext implements Serializable
{
private static final long serialVersionUID = 1L;
// UNITNAME must match persistence.xml: <persistence-unit name="myUnitName">
public static final String UNITNAME = "myUnitName";
public static final String NAME = "persistence/" + UNIT_NAME;
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.FIELD,
ElementType.PARAMETER, ElementType.TYPE})
public static #interface Qualifier { }
// Servlets must be stateless (shared across multiple threads).
// EntityManager is not stateless (cannot be shared across threads).
// Obtain Container Managed EntityManager - and do NOT cache.
#Produces #Qualifier
public static EntityManager getEntityManager() throws NamingException
{
EntityManager lookup = InitialContext.doLookup("java:comp/env/" + NAME);
return lookup;
}
}
Limitations
As written, this defines a specifically named PersistenceContext for the Servlet container. Since the unitName isn't parameterized, it doesn't provide the level of flexibility as:
#PersistenceContext(unitName = "unitname")
public EntityManager em;
Alternatives
Define a PersistenceContext on your Servlet, and use JNDI name lookup.
Well i think you should see the problem from a different point of view?
Why do you need to call an EJB from JSP page?
JSP page shouldn't contain codes and it is used only for presentation.
I suggest to you to add a Servlet or a JSF framework and let the Servlet or the ManagedBean to call EJB and then pass the parameters to the JSP.
Hope it helps you
You can use the following snippet to retrieve EntityManager and/or UserTransaction via JNDI lookup:
try {
Context ic = (Context) new InitialContext();
EntityManager em = (EntityManager) ic.lookup("java:comp/env/*<persistence-context-name>*");
UserTransaction ut = (UserTransaction) ic.lookup("java:comp/env/UserTransaction");
} catch (NamingException ne) {...}
In my Spring+JPA/Hibernate+Wicket app, I have a QueryBuilder bean that I want to use in one of my DAOs which generates a typed query with the help of Criteria API:
#Service(value="inboxQueryBuilder")
public class InboxQueryBuilder {
#PersistenceContext
EntityManager em;
CriteriaBuilder cb;
public InboxQueryBuilder() {
cb = em.getCriteriaBuilder();
}
public TypedQuery<App> getQueryForApps(AppSearchObject aso) {
...
}
...
}
However, when I run the app, I get a null pointer exception for line:
cb = em.getCriteriaBuilder();
i.e. the EntityManager doesn't get injected. Do you know why?
Also, is this use correct and thread-safe or should I instantiate my InboxQueryBuilder for each query? In that case, should I also inject the EntityManager or should I just pass it as a constructor parameter (the InboxQueryBuilder would get instantiated for each query in the DAO which has an injected instance of EntityManager)?
You can't access the EntityManager within the constructor. Take a look at the #PostConstruct-Annotation
#Service(value="inboxQueryBuilder")
public class InboxQueryBuilder {
#PersistenceContext
EntityManager em;
CriteriaBuilder cb;
public InboxQueryBuilder() {
// em= null
}
#PostConstruct
public void toSomething(){
// em set by Container
cb = em.getCriteriaBuilder();
}
public TypedQuery<App> getQueryForApps(AppSearchObject aso) {
...
}
...
}
EDIT:
After reading your post again, I start to became unsure, if I'm right. I know the Java EE-Dependency-Injection within a JBoss works as I described, but I'm not sure about spring-IOC.
Do you have this bean somewhere in your application context?
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="myPersistenceUnit"/>
</bean>
Spring uses the Java Beans mechanism, so I am pretty sure this is insufficient:
#PersistenceContext
EntityManager em;
Here's the standard way:
private EntityManager entityManager;
#PersistenceContext
public void setEntityManager(final EntityManager entityManager){
this.entityManager = entityManager;
}