Best way to close an entityManager - java

I have the following code:
public Category findCategoryById(Long id) {
EntityManager em = emf.createEntityManager();
try {
em.getTransaction().begin();
Category category = categoryDAO.findCategoryById(em, id);
em.getTransaction().commit();
return category;
} catch (Exception e) {
throw e;
} finally {
em.close();
}
}
I'm handling the exceptions in my controller, but I want to make sure that entity manager is closed. I don't like that I am catching and re-throwing the error. I'm hoping to find better suggestions.
thanks

The best way is to not have to care about it. If your Entity Manager is container managed (for example if you are using ejb or spring and you haven't forced a specific bean/application managed behaviour) you should let the container handle the opening/close of the transaction and in general to worry about your persistence context. It's easier, safer and, with the exclusion of very specific cases, better. The manual close of the Entity Manager should be directly handled by you only in case of application managed context, to avoid connection pool exhaustion or other problems.

Related

JPA2.0 commits transaction on flush immediatly

I'm using EJB3 and JPA2 in a project containing several modules.
Lately i have noticed that the DB-records won't rollback on exception. After doing some research i found that entity manager commits the transaction on flush immediatly even before the method ends, so that it can't rollback on exception.
I inject entity manager using
#PersistenceContext
private EntityManager entityManager;
To create a new record is persist and flush beeing called in the same class
entityManager.persist(entity);
entityManager.flush();
Even if i call throw new RuntimException("") right after flush, it wont rollback. On debug after flush is invoked i can select the DB-record with a database tool, before the method ends.
I already checked the persistence.xml and found nothing unusual. I dont use any other specifig configuration.
I'm out of ideas what might cause this behavior. I appriciate any clue.
You need to specify transaction boundaries, otherwise a new transaction will be opened and commited after each data manipulation query (INSERT, UPDATE, DELETE). As em.flush() will trigger such SQL query to be executed, it will open an implicit transaction and commit it if the SQL is successful, rollback in case of error.
In order to set transaction boundaries and make a RuntimeException trigger a rollback, the best option is to call entityManager methods from an EJB object. You must use a JTA datasource, not RESOURCE_LOCAL. If you don't use JTA datasource, you need to manage transactions by yourself, ie. by using entityManager.getTransaction() object.
Outside of an EJB, or with non-JTA datasource, you do not have any transaction open, unless you start it yourself by calling entityManager.getTransaction().begin(). However, in this way, your transaction will not be rolled back when Exception is thrown. Instead, you must roll back in catch block. This is mostly outside of Java EE container, in a Java SE application. In Java EE, I strongly suggest to use JTA datasource. Example:
public class NotAnEJB {
public persistEntity(EntityManager em, MyEntity entity) {
em.getTransaction().begin();
try {
em.persist(entity);
em.flush();
if (shouldFail()) {
throw new RuntimeException();
}
em.commit();
} catch (Exception e) {
em.rollback();
}
}
}

JPA persist not writing to database

I'm just trying to get to know JSF and JPA but whenever I try to persist an object into the database it seems to not write away.
Here's the code I'm using:
#Named
#ManagedBean
#SessionScoped
public class BestemmingController implements Serializable{
#PersistenceUnit(unitName="RealDolmenTravelShopPU")
#PersistenceContext(unitName="RealDolmenTravelShopPU")
EntityManagerFactory emf = null;
public void submit(){
try{
emf = Persistence.createEntityManagerFactory("RealDolmenTravelShopPU");
EntityManager em = emf.createEntityManager();
//EntityTransaction et = em.getTransaction();
//et.begin();
Bestemming nieuweBestemming = new Bestemming();
Land gezochtLand = em.find(Land.class, selectedLand);
nieuweBestemming.setLand(gezochtLand);
nieuweBestemming.setNaam(bestemmingNaam);
em.persist(nieuweBestemming);
//et.commit();
//em.flush();
em.close();
}catch (Exception e){
e.printStackTrace();
}finally{
emf.close();
}
}
I tried using the EntityTransaction but it just stopped my application, without any errors or anything. So I left it out, but still it didn't write away.
So then I tried calling flush seperately, but that didn't do anything either.
I'm really stumped as to why this isn't working. It's probably some newbie mistake, but I would love it if someone here could help me out.
Thanks in advance!
First, are you able to write to the logs? Starting a transaction when specifying the persistence unit uses JTA will throw an exception, so it is likely you have just been missing exceptions in your container log files.
Second, this is a JTA PU, so it needs a JTA transaction started that the EM gets associated to, and you will want to inject the em rather than create a factory yourself. Check out the JPA application server examples here first to see how they are set up:
http://wiki.eclipse.org/EclipseLink/Examples/JPA
Hey I found out why it was that the transaction wasn't running: the implementation I used didn't use JTA, it used a RESOURCE_LOCAL persistence unit. That was something I just looked over when I set up my project.
Good thing my buddy told me to check the server logs.

Transaction Management

In my code I am updating two table, one after the other.
update(table1_details);
update(table2_details);
So if the update fails in table1 , table2 should not be updated or should be rolled back.
How to handle this situation. I know I have to use transaction. Can some one help with code !!!
I am using Java with spring and hibernate .
The question is a bit broad and there are several ways to implement this but I would:
Use Spring to inject Hibernate SessionFactory into DAOs objects.
Use Spring to inject DAOs in a service object and call them inside a business method.
Use Spring declarative transaction management at the business method level (either with Spring AOP or #Transactional).
Something like this:
#Transactional
public void doSomething() {
dao1.foo();
dao2.bar();
}
For more details on the configuration, check the Chapter 9. Transaction management of the Spring documentation.
I can't recall the correct api, but something like this:
Transaction tx = em.getTransaction();
tx.begin();
try {
update1(); update2();
}
catch(Exception e) {
failed = true
}
finally {
if( !failed ) tx.commit();
else tx.rollbacl();
}

EJB3 Getting at original JDBC Errors

I am using EJB3 on Glassfish using the default TopLink persistance manager. Within a Session Bean, when the persistence manager catches a DB exception, it marks the transaction to be rolled back, and throws an EJBException, in turn wrapping a RollbackException. Now I was expecting to be able to get the original jdbc exception out of the caused by exception of one of these exceptions, but it is not.
It is important that I do retrieve the original exception, as I need to report back to the users what the problem is, and to do this I need to analyse the SQL error codes.
Does anyone know if it is possible to get this information from Toplink? Or whether Hibernate makes it possible?
Thanks,
I had the same issue. I ended up using the AroundInvoke interceptor method , that way you can catch any exception on the server side , and extract whatever info you want to and wrap it to throw your own exception , and set the EjbContext to rollback the transaction.
I can provide you with an example if you don't come right.
Good question, Ant
I know you want to throw a database exception but when it occurs the application, in most of the time, is not able to restore its initial state or it does not know how to recover from it. So it should be handled as a runtime exception. Some problems in database exceptions includes
database connection failure
query is wrong
table or column does not exist
Above you see the application is not be able to restore its initial state. If you think it is possible restore its initial state so you should use a application exception. Client will get the same application exception thrown by your business method. If you want to be able to get the exact exception thrown by your business method you have two choices:
Use a business delegate pattern to access your EJB
As you know, runtime exception is wrapped by a EJBException, so you shold use something like
Let's suppose you have this Stateless session bean
#Stateless
public class BeanImpl implements Bean {
public void doSomething() {
try {
// some code
} catch(SomeException e) {
throw new EJBException(e);
}
}
}
So you wrap your session bean through a business delegate
public class BeamBusinessDelegate implements Bean {
// your stateless session bean goes here
private Bean bean;
public BeamImpl() {
InitialContext i = new InitialContext();
bean = (Bean) i.lookup(<GLOBAL_JNDI_ADDRESS_OR_RELATIVE_ENVIRONMENT_NAMING_CONTEXT_ADDRESS>);
}
public void doSomething() {
try {
bean.doSomething()
} catch(EJBException e) {
throw e.getCause();
}
}
}
Or you can extends EJBException according to your needs
public class DatabaseException extends EJBException {
}
So in your business method
#Stateless
public class BeanImpl implements Bean {
public void doSomething() {
try {
// some code
} catch(SomeException e) {
throw new DatabaseException();
}
}
}
regards,
The only way I've found to do what I want, is to force the manager to write to the db using manager.flush(), and then catch the PersistenceException that that throws. I can then log the database error as I want, and throw an EJBException to force rollback. Leaving the container to do the flush seems to irretrievably lose any useful messages with TopLink.
I have the same question : how to get the SQL error message generated from JPA?
I haven't found the solution either but, I added this line in my persistence.xml
<properties>
<property name="toplink.logging.level" value="FINE" />
</properties>
and now, I can see the sql commands issued.
Reference :
http://www.jairrillo.com/blog/2008/09/04/introduction-to-jpa-part-1-getting-started/

Entitymanager causing memory leak?

I have a slow memory leak in my Java application. I was wondering if this could be caused by not always closing the Entitymanager when used. However using myeclipse to generate DB code, I'm getting methods like this:
public Meit update(Meit entity) {
logger.info("updating Meit instance");
try {
Meit result = getEntityManager().merge(entity);
logger.info("update successful");
return result;
} catch (RuntimeException re) {
logger.error("update failed");
throw re;
}
}
Which never close the EntityManager. Considering this is generated code, I'm wondering who's right, me or the IDE.
As #Ruggs said if you are managing the EntityManager lifecycle yourself (as opposed to having CMP Container Managed Persistence done by a J2EE) then you need to close the EntityManager yourself or at least call EntityManager.clear() to detach entities.
EntityManager are lightweight object so there is no need for just having one, you can create one for each transaction and close it after the transaction is committed.
All the entities that load/persist through an EntityManager stay in memory until you explicitly detach the entities from it (via EntityManager.detach() or EntityManager.clear() or EntityManager.close()). So it's better to have short-lived EntityManagers. If you persist 1000000 entities via the same EntityManager without detaching them after you will get a OOME (doesn't matter if you persist each entity in it's own EntityTransaction).
It's all explained in this post http://javanotepad.blogspot.com/2007/06/how-to-close-jpa-entitymanger-in-web.html.
As an example (taken from the earlier post) if you want to avoid "memory leaks" you should do something like this (if you are not using CMP):
EntityManager em = emf.createEntityManager();
try {
EntityTransaction t = em.getTransaction();
try {
t.begin();
// business logic to update the customer
em.merge(cust);
t.commit();
} finally {
if (t.isActive()) t.rollback();
}
} finally {
em.close();
}
Entity managers should generally have the same lifecycle as the application and not be created or destroyed on a per-request basis.
Your "memory leak" may be nothing more than the caching JPA is doing. You don't say which JPA provider you use but I know from experience that EclipseLink by default does extensive caching (which is part of the alleged benefits of JPA and ORM in general).
How do you know you have a memory leak?
Check whether it's really a leak
if so get the Eclipse Memory Analyzer and analyze it.
The blog posts here might also be useful.
It sounds like you are using an application managed EntityManager. You will need to call close the EntityManager yourself, it's part of the spec. You will also need to close the EntityManagerFactory when you shutdown your webapp.
I'd recommend using something like OpenEJB or Springframework to manage the EntityManager/EntityMangerFactory for you.

Categories