I am having some trouble understanding the proper usage of entity manager when querying for objects and or deleting/creating. Right now for any database transactions I have several service methods that open and close new entity managers like so:
public static Long getCountApplicants(String active){
EntityManager entityManager = factory.createEntityManager();
long value = (Long) entityManager.createQuery("select count(distinct a) from Applicant a where a.active = " +active).getSingleResult();
System.out.println("get count app query");
entityManager.close();
return value;
}
Since I have a Java EE app with a persistence.xml file that defines my unit, why can't I declare only one from my factory and use it throughout the life of my app? Is there any performance or memory leak issues with using just one of these objects?
Update:
I am using the following stack, Spring Framework/JPA Eclipselink
Long story short: Since you're using Spring, you're better off defining the Entity Manager as an attribute of your DAO like so:
#PersistenceContext
EntityManager em;
Your code then becomes:
public static Long getCountApplicants(String active){
long value = (Long) em.createQuery("select count(distinct a) from Applicant a where a.active = " +active).getSingleResult();
System.out.println("get count app query");
return value;
}
This will work only with Non Extended Persistence Contexts.
The EntityManager injected by Spring will be threadsafe.
Whether you need to configure an LocalEntityManagerFactorBean application-managed or LocalContainerEntityManagerFactoryBean container-managed Entity Manager is just a matter of configuration in the Spring configuration files.
EntityManager is generally not threadsafe when application managed.
http://docs.oracle.com/javaee/6/tutorial/doc/bnbqw.html
However, if you're using a container managed version, it should be. You would inject it:
#PersistenceContext
EntityManager entityManager;
Spring is one such container that can do this. The link above is a helpful resource.
Related
I'm using JPA, but I need to unwrap my EntityManagerFactory, so I can add an interceptor to the Session. Afterward I want to wrap the Session back to a EntityManager.
"Why not just use Session instead of EntityManager?" We still want to reduce the impact of a possible technology migration
For what do I want to use Interceptor:
I can resume the problem in the following way: The project works running queries on a alarms database. Each place has one database with a Alarm Table, but the client wants to have a single database, where we will have to create multiple "Alarm Table", one for each place (ex: Table_Alarm-Place1, Table_Alarm-Place2). That means we would have multiple tables for the same entity, the interceptor has the goal of changing the Table name generate by hibernate in the final SQL
How I pretend to use the interceptor:
public class SqlInterceptor extends EmptyInterceptor {
private String tableSufix;
private static final Logger LOGGER = LoggerFactory.getLogger(SqlInterceptor.class);
public SqlInterceptor(String tableSufix) {...}
#Override
public String onPrepareStatement(String sql) {
String finalSql;
//Manipulated SQL (parsed by Hibernate)
return finalSql;
}
}
The project uses JPA 2.1 and Hibernate 4.3.11.Final
A super easy way to override Hibernate's EmptyInterceptor is to just this in properties file
spring.jpa.properties.hibernate.session_factory.interceptor=<fully-qualified-interceptor-class-name>
Cheers :)
You can supply the Interceptor when building the EntityManagerFactory:
String persistenceUnitName = ...;
PersistenceUnitInfo persistenceUnitInfo = persistenceUnitInfo(persistenceUnitName);
Map<String, Object> configuration = new HashMap<>();
configuration.put(AvailableSettings.INTERCEPTOR, new SqlInterceptor());
EntityManagerFactoryBuilderImpl entityManagerFactoryBuilder = new EntityManagerFactoryBuilderImpl(
new PersistenceUnitInfoDescriptor(persistenceUnitInfo), configuration
);
EntityManagerFactory emf = entityManagerFactoryBuilder.build();
It looks like you want to have a multi-tenant database. I had a similar issue before and implemented an interceptor using aspectj to set the filter properly. Even if you do not go for the filter option, you can grab te session everytime it is created using aspectj, as below.
public privileged aspect MultitenantAspect {
after() returning (javax.persistence.EntityManager em): execution (javax.persistence.EntityManager javax.persistence.EntityManagerFactory.createEntityManager(..)) {
Session session = (Session) em.getDelegate();
Filter filter = session.enableFilter("tenantFilter");
filter.setParameter("ownerId", ownerId);
}
}
In the sample below, I just set the filter that needs to be configured on the entity you need to filter:
#Entity
#FilterDef(name = "tenantFilter", parameters = #ParamDef(name = "ownerId", type = "long"))
#Filters({
#Filter(name = "tenantFilter", condition = "(owner=:ownerId or owner is null)")
})
public class Party {
}
Of course, to use the filter instead of the table name, you will have to add a column to differentiate the tables - which I believe to be better than having multiple table names.
You can store all the necessary information in a static ThreadLocal instance and read it afterwards.
This way you avoid the complications with session scoped interceptors and you can use other mechanisms to achieve the same goal (for example with a session factory scoped interceptor which is a bit easier to configure).
Why not simply do the following:
EntityManagerFactory entityManagerFactory = // created from somewhere.
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
// do whatever you need with the session factory here.
// Later in your code, initially use EntityManager and unwrap to Session.
EntityManager entityManager = entityManagerFactory.createEntityManager();
Session session = entityManager.unwrap(Session.class);
Basically, rather than trying to get a Session and then wrapping it back into an EntityManager, simply pass a JPA EntityManager around and unwrap it to Session on an as-needed basis.
The following code is from JPA specs. I could not understand why em.joinTransaction() is required in createLineItem(int quantity).
Can anyone provide an apt explanation?
#Stateful
public class ShoppingCartImpl implements ShoppingCart {
#PersistenceUnit
private EntityManagerFactory emf;
private EntityManager em;
private Order order;
private Product product;
#PostConstruct
public void init() {
em = emf.createEntityManager();
}
public void initOrder(Long id) {
order = em.find(Order.class, id);
}
public void initProduct(String name) {
product = (Product) em
.createQuery("select p from Product p where p.name = :name")
.setParameter("name", name).getSingleResult();
}
public LineItem createLineItem(int quantity) {
em.joinTransaction();
LineItem li = new LineItem(order, product, quantity);
order.getLineItems().add(li);
em.persist(li);
return li;
}
#Remove
public void destroy() {
em.close();
}
}
First, a few words of theory...
An application-managed entity manager participates in a JTA transaction in one of two ways.
If the persistence context is created inside the transaction, the persistence provider will automatically synchronize the persistence context with the transaction.
If the persistence context was created earlier (outside of a transaction or in a transaction that has since ended), the persistence context can be manually synchronized with the transaction by calling joinTransaction() on the EntityManager interface. Once synchronized, the persistence context will automatically be flushed when the transaction commits.
After reading the above definition a few questions may arise:
how do we know that ShoppingCartImpl participates in JTA transaction ?Because the class has been annotated with #Stateful (or #Stateless) annotation so the intention is to execute the class within Java EE environment which by default uses JTA transactions. A class doesn't need such annotation, if it will be executed in Java SE environment.
how do we know application-managed entity manager is used in this particular case?Because we are using #PersistenceUnit annotation to inject EntityManagerFactory and then manually creating and destroying EntityManager. By doing this we are telling Java EE container that we don't want our transaction to be automatically managed (like in case of transaction-scoped entity manager or extended entity manager types).
why em.joinTransaction() is required in createLineItem method?By calling em.joinTransaction() we notify the application-managed persistence context that it should synchronize itself with the current JTA transaction. Without such call the changes to Order would not be flushed to the underlying database when the transaction commits (at the end of createLineItem method). NOTE: since EntityManagerFactory instances are thread-safe and EntityManager instances are not, an application must not call em.joinTransaction() on the same entity manager in multiple concurrent transactions.
I'm trying to move out my project from Seam 3.
Now I'm stuck on JTA transactions after switching off Seam Faces module. There was integrated transaction management. Transactions were begun and commit automatically - without manual commit.
Now when I try to execute EntityManager.persist() or EntityManager.merge(Object entity), I've got error:
JBAS011469: Transaction is required to perform this operation (either use a transaction or extended persistence context)
Is there any way to force JTA to start transaction and commit it transparently?
Ps. Funny thing - some time ago I was looking for solution how to force manual commit/rollback in Seam3.
OK, if I put bean into #Stateless state - then it behaves as I expected.
But...
Isn't it - that if I put application managed EntityManager - then I should manage transaction on my own (method testApplicationJTA() in example below), but if I use container managed EntityManager - then it should work without transaction managing (method testContainterJTA() ) ?
My example:
#Named
#SessionScoped
public class Test implements Serializable {
private static final long serialVersionUID = 1L;
#PersistenceContext
private EntityManager em;
#PersistenceUnit
private EntityManagerFactory emf;
#Resource
private UserTransaction utx;
public void testContainerJTA() {
TestEntity entity = em.find(TestEntity.class, 1L);
entity.setName("dddddd");
em.merge(entity);
}
public void testApplicationJTA() {
EntityManager mgr = emf.createEntityManager();
TestEntity entity = em.find(TestEntity.class, 1L);
entity.setName("fffff");
try {
utx.begin();
mgr.joinTransaction();
mgr.merge(dict);
utx.commit();
} catch (Exception e) {
utx.rollback();
}
mgr.close();
}
}
In my example above method testContainerJTA() doesn't work. Why?
If I'll remove #SessionScoped and put #Stateless then method testApplicationJTA() doesn't work, but testContainerJTA() works. Why?
Should't they work both always - as application managed and container managed?
OK, so it is possible to make CDI bean tansactional - with interceptors :-)
Finally I managed to solve my problem reading this article:
http://smokeandice.blogspot.com/2009/12/cdi-and-declarative-transactions.html
Edit:
From JEE7 there is new #Transactional annotation which takes all JPA actions in CDI bean or method into transaction.
I have 2 ejb-module in my project, ejb-module1 and ejb-module2. ejb-module1 contain entity clases and persistence unit, there is a ejb with a Entity Manager like this:
#Stateful
public class ErpTools implements ErpToolsLocal {
#PersistenceContext(unitName = "erp-ejbPU")
private EntityManager em;
public EntityManager getEm() {
return em;
}
public void setEm(EntityManager em) {
this.em = em;
}
in ejb-module2 i have other ejb that need use entity manager from ejb-module1,
i try with this,
String ejbql = "SELECT e from CtEmpresaCliente e ORDER BY e.idCliente ASC";
Query query = this.erpTools.getEm().createQuery(ejbql);
empresaClientes = query.getResultList();
but send this exception:
"Unable to retrieve EntityManagerFactory for unitName erp-ejbPU"
debuging in this point Query query = this.erpTools.getEm().createQuery(ejbql);
this.erpTools.getEm() is not null.
note: Using Netbeans, JPA, JEE6, EJB 3.1
Calls to EJBs that are in different modules are similar to remote invocations in the sense that they use pass by value semantics and undergo serialization / de-serialization. In this case the network is not used, but all other aspects of the remote invocations are still happening.
What this means for you is that even though you get a non null EntityManager from another EJB module, it is serialized / de-serialized and by the time it makes it to the other EJB module it no longer refers to a valid persistence context (since it does not exist in the calling EJB module).
I am developing a JavaEE6 based web application using JBoss7.
In my application I am injecting the EntityManager in my EJBs as:
class ForumServiceEJB
{
#PersistenceContext(type=EXTENDED)
private EntityManager em;
}
class TopicServiceEJB
{
#PersistenceContext(type=EXTENDED)
private EntityManager em;
}
The problem when I update some data using ForumServiceEJB's EntityManager then the changes are made into DB but TopicServiceEJB's EntityManager is not able to see those changes and the results are always fetched from Cache.
I am using ExtendedPerssisteenceContext as My Entities contain child Entity Collections of Lazy Loading type.
How can I use/Inject EntityManager of type ExtendedPersistenceContext and make different EntityManager in one EJB can still see the changes done by other different EJB EntityManagers?
Somewhere I read EntityManagers should be RequestScoped objects.
public class MyEntityManagerProducers {
#Produces #RequestScoped
public EntityManager createDbEm() {
return Persistence.createEntityManagerFactory("forumDb").
createEntityManager();
}
public void disposeUdEm(#Disposes EntityManager em) {
em.close();
}
Is it the way to go?
I am using ExtendedPerssisteenceContext as My Entities contain child
Entity Collections of Lazy Loading type.
This is not a good reason to use EXTENDED. I would suggest you to make it default, which is TRANSACTION. And it's good to make your EntityManager request-scoped, or method-scoped, in non-enterprise environment or when using application-managed persistence, as this is not a very heavy object to create. Moreover, neither using application-scoped EntityManager is a good idea, as it is not threadsafe.
Having said that, as you are using JBoss, you should let the container handle the lifecycle of EntityManager, in case you are using JTA. Hence, just inject that with everything default
Note:
Only stateful session beans can have a container-managed, extended entity manager.
Links:
http://javanotepad.blogspot.com/2007/08/managing-jpa-entitymanager-lifecycle.html
https://blogs.oracle.com/enterprisetechtips/entry/extended_persistence_context_in_stateful
Suggestions:
Your business method should know whether to load the children or not. But that's the ideal case. A number of times we can't say that and completely depends on the user input -- we can't predict that well. Therefore, there are two solutions available,
make a separate AJAX call to load children
Use the filter called open-session-in-view. I would prefer the former.
Links:
https://community.jboss.org/wiki/OpenSessionInView
http://static.springsource.org/spring/docs/1.2.9/api/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.html
Why is Hibernate Open Session in View considered a bad practice?