I am using JPA 2.1. Entity Managers are application managed here.
Sample Class:
public class TestDao {
private static EntityManagerFactory emf;
private static EntityManager em;
public static EntityManager initialize() {
if (emf == null) {
emf = Persistence.createEntityManagerFactory("persistence_unit");
}
return emf.createEntityManager();
}
public static void insert(Object obj){
em.persist(obj);
}
When user first time uses TestDao.initialize(), it generates emf and em instances.
What will happen with this emf instance?
Does it always keep connection with the database?
Which is better way if I have both significant reads and writes:
create emf once (as I used above)
create new emf and em every time I interact with the database.
As per the Factory Pattern, it should be created/initialized only once. So EntityManagerFactory should be only one through out the application. You can create EntityManager from this factory as and when required.
References: Factory Pattern,
When should be factory instance be created?
Related
I'm working on a homework that using JPA but without spring.
It has service layer and repository layer.
I try to begin transaction in service and call save or update from repository and then commit in service.
But how to get Current EntityManager in repository?
My cod is like this:
Service:
public void save(Entity entity){
var em = factory.createEntityManager();
var t = em.getTransaction();
try {
t.begin();
repository1.save(entity);
// For saving one to many relation
repository2.save(entity.getChildEntity());
t.commit();
} catch (Exception e) {
t.rollback();
}
}
Repository:
// I don't want to pass EntityManager to method
public void save(T entity) {
var em = ? // How can I get EntityManager hear?
em.persist(entity);
}
In your first snippet of the service I see that you have a factory and there you create an EntityManager. So the factory exists...
Take your factory and make it accessible everywhere in your program. How?
Create a class specific only to creating the factory and the hibernate session. There you create public static getters for the fields that you need (such as the factory and EntityManager).
Example:
public class HibernateUtils
{
public static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory()
{
try
{
// Create the SessionFactory from hibernate.cfg.xml
return new Configuration().configure().buildSessionFactory();
}
catch (Throwable ex)
{
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void shutdown() {
// Close caches and connection pools
getSessionFactory().close();
}
}
In Spring, the use of Services and Repositories is a further abstraction of JPA.
If you want to use JPA without Spring, you can inject EntityManager using standard JavaEE/JakartaEE technologies, that is what Spring does under the hood.
Otherwise, if you want to do it by yourself, keep in mind that JPA is a standard for which there are a couple of implementations.
Let's take in consideration Hibernate, go to read the docs, stick with EntityManagerFactory and EntityManager instead of SessionManager (specific to Hibernate).
You can instantiate an EntityManager as:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("my_PU");
EntityManager em = emf.createEntityManager();
The "my_PU" is a persistenceUnit that you need to define.
More info here: https://docs.oracle.com/cd/E19798-01/821-1841/bnbrj/index.html#:~:text=A%20persistence%20unit%20defines%20a,the%20persistence.xml%20configuration%20file.
public class EntityManagerProvider {
private static final EntityManager entityManager;
public EntityManagerProvider() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("com.example.factory");
this.entityManager = emf.createEntityManager();
}
public static EntityManager getEntityManager() {
return entityManager;
}
}
Second Approach :
public class EntityManagerProvider {
private static final EntityManager entityManager;
private EntityManagerProvider() {}
public static synchronized EntityManager createOrGetEntityManager() {
if(entityManager == null) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("com.example.factory");
EntityManagerProvider.entityManager = emf.createEntityManager();
return EntityManagerProvider.entityManager;
}
return EntityManagerProvider.entityManager;
}
}
You need to create entityManager once and use it everywhere. I don't know where you create factory class but you can create entityManagerProvider class after creation of factory class.
You can simply call EntityManagerProvider.getEntityManager() to receive entityManager from class.
Please note that you don't need to initialize everywhere you can do it once and use it everywhere.
SecondApproach is better you can use it simply everywhere. EntityManagerProvider.createOrGetEntityManager method will give you entityManager.
After some time I found a safe way to get Current EntityManager in current thread.
I lust link so just sharing code that I want get your feedback and opinions.
I think in this way I can even user Aspectj too.
public class EntityManagerUtil {
//for holding EntityManager in current thread
private static final ThreadLocal<EntityManager> THREAD_LOCAL;
static {
THREAD_LOCAL = new ThreadLocal<>();
}
// singleton creating EntityManagerFactory
private static class LazyHolder {
private static final EntityManagerFactory ENTITY_MANAGER_FACTORY =
Persistence.createEntityManagerFactory("persistence-unit");
}
public static EntityManagerFactory getEntityManagerFactory() {
return LazyHolder.ENTITY_MANAGER_FACTORY;
}
public static EntityManager getCurrentEntityManager() {
EntityManager entityManager = THREAD_LOCAL.get();
if (entityManager == null) {
entityManager = getEntityManagerFactory().createEntityManager();
// set your flush mode here
THREAD_LOCAL.set(entityManager);
}
return entityManager;
}
public static void closeCurrentEntityManager() {
EntityManager em = THREAD_LOCAL.get();
if (em != null) {
em.close();
THREAD_LOCAL.remove();
}
}
}
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.
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) {...}
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.