I'm trying to understand, how does injecting of EntityManger in Spring bean work.
I have bean
#Service
#RequiredArgsConstructor(onConstructor_ = #Autowired)
public class TestUpdateService {
#PersistenceContext
private EntityManager entityManager;
private final OrderRepository orderRepository;
#Transactional
public void doWork(Long id) {
Order order = orderRepository.findById(id).get();
entityManager.detach(order);
orderRepository.save(order);
}
}
And have a couple of questions:
Am I right that for every call of my transactional method doWork new instance of EntityManager will be created? I read (or mb misunderstood) on stackoverflow that entity manager annotated with #PersistanceContext creates own EntityManager for each transaction.
If it is so, does #Autowired work the same way?
If it isn't so, then how do these both annotations work?
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.
Currently, I'm using PersistenceContext to inject an EntityManager. The EM is injected perfectly.
#Stateless
public StatelessSessionBean implements StatelessSessionBeanLocal {
#PersistenceContext(unitName = "MyPersistenceUnit")
private EntityManager em;
#Override
public Collection<MyObject> getAllObjects(){
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriqQuery<MyObject> query = cb.createQuery(MyObject.class);
query.from(MyObject);
return em.createQuery(query).getResultList();
}
}
Now I try to decorate the bean, and suddenly the em doesn't get injected. I get a NullPointerException.
#Decorator
public StatelessSessionBeanDecorator implements StatelessSessionBeanLocal {
#Inject
#Delegate
#Any
StatelessSessionBeanLocal sb
#Override
public Collection<MyObject> getAllObjects(){
System.out.println("Decorated method!");
return sb.getAllObjects();
}
}
I know EJB and CDI are 2 completely different managers, so the one doesn't know about the other. I'm expecting that #PersistenceContext is an EJB injection point, while #Inject is a CDI one. What should I do to solve this and get the EntityManager to be injected like it should?
The best practice for persistence context and CDI is to make them CDI bean to avoid these kind of issue.
public class MyProducers {
#Produces
#PersistenceContext(unitName = "MyPersistenceUnit")
private EntityManager em;
}
After that you'll be able to inject the EntityManager in CDI way. Taking your EJB it'll be :
#Stateless
public StatelessSessionBean implements StatelessSessionBeanLocal {
#Inject
private EntityManager em;
#Override
public Collection<MyObject> getAllObjects(){
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriqQuery<MyObject> query = cb.createQuery(MyObject.class);
query.from(MyObject);
return em.createQuery(query).getResultList();
}
}
This way, you'll be able to decorate your CDI bean with no issue.
If you have multiple EntityManagers you can use CDI qualifiers to distinguish them
#PersistenceContext is an EJB injection point, while #Inject is a CDI one
Actually, no. #PersistenceContext annotation can be used in CDI and is not connected with EJB. You can do something like this:
#Named
public class EntityDAO {
#PersistenceContext
private EntityManager manager;
...
}
EJB uses #EJB annotation to inject other EJB, but it can inject any CDI bean or persistence context with same annotations.
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'm using Spring 3.1.2 with Hibernate 4.
I have a DAO implementation class MyDaoImpl annotated with #Repository so that exception translation is enabled. I have a service class MyService annotated with #Transactional as follows:
public class MyService implements IMyService {
private MyDao myDao;
#Autowired
public void setMyDao(MyDao dao) {
this.myDao = dao;
}
#Override
#Transactional
public void createA(String name)
{
A newA = new A(name);
this.myDao.saveA(newA);
}
}
I've wrote a unit tests class MyServiceTest as follows:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:beans.xml" })
#Transactional
#TransactionConfiguration(defaultRollback = true)
public class MyServiceTest implements IMyServiceTest {
private IMyService myService;
private SessionFactory sessionFactory;
#Autowired
public void setMyService(IMyService myService)
{
this.myService = myService;
}
#Autowired
public void setSessionFactory(SessionFactory sessionFactory)
{
this.sessionFactory = sessionFactory;
}
#Test
#Override
public void testCreateA()
{
//Assume that there is already a row of table A with the name "A1"
//so I expect to get a Spring DataAccessException (or subtypes)
//when the session is flushed
this.myService.createA("A1");
this.sessionFactory.getCurrentSession().flush();
//asserts
}
}
When I run the test, I get a Hibernate specific exception ConstraintViolationException. I've found on the forum that this is because the translation system takes place outside the transaction, so in this case after testCreateA() returns. I don't know if this is the real cause, but if it is, it means that I can't test that the translation works for my DAOs. One solution would be to remove the #Transactional annotations from my unit tests, but I would no benefit from the rollback feature.
What are your recommendations?
EDIT: I've added the SessionFactory declared in my context to the test class, so that I can access the current session for flushing.
Some additional explanations: In this case, I get the exception when the session is flushed (which is inside the transaction). I flush the session in order to avoid false positives as it is explained in the docs. Also, since the default propagation is REQUIRED, the testCreateA() transaction is also used for the call to createA(), so the changes are not flushed (generally) until testCreateA() returns.
Have you added PersistenceExceptionTranslationPostProcessor bean defination? Like
<!--
Post-processor to perform exception translation on #Repository classes
(from native exceptions such as JPA PersistenceExceptions to
Spring's DataAccessException hierarchy).
-->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
From Spring doc.
Bean post-processor that automatically applies persistence exception
translation to any bean that carries the #Repository annotation, adding
a corresponding PersistenceExceptionTranslationAdvisor to the exposed
proxy (either an existing AOP proxy or a newly generated proxy that
implements all of the target's interfaces).
Translates native resource exceptions to Spring's DataAccessException
hierarchy. Autodetects beans that implement the
PersistenceExceptionTranslator interface, which are subsequently asked
to translate candidate exceptions
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) {...}