JPA No transaction Active - java

I am using the JPA Framework to achieve Database Persistence of information.
This is how I used I created a class like this:
public class ManageConnection {
private static EntityManagerFactory emf = null;
private static EntityManager em = null;
private static String persitenceName="locationtracker";
public static EntityManager getEntityManager(){
if(emf==null || !emf.isOpen())
emf = Persistence.createEntityManagerFactory(persitenceName);
if(em==null || !em.isOpen())
em=emf.createEntityManager();
return em;
}
public static void closeEntityManager(){
if(em!=null && em.isOpen())
em.close()
}
}
Then in my servlet I am using like this:
public void doPost(blablah){
.
.
.
.
.
.
.
.
.
.
.
for(blah blah){
Manageconnection.getEntityManager().getTransaction().begin();
<PersistenceObject> objName = new <PersistenceObject>();
//properties of the objName to persist
ManageConnection.getEntityManager().persist(<objName>);
Manageconnection.getEntityManager().getTransaction().commit();
}
Manageconnection.closeEntityManager();
}
Now my problem is I get Transaction is already active Exception whenever I passes the values to my Servlet also the same code works perfect when there is no Servlet thing, I mean using main method in a Test class it is running like charm, but it throws exception when runs in Servlet.
Please help me..............
;(
Thanks in advance,
Ankur

All of your EntityManagerFactory and EntityManagerFactory is used static. It is the class level and for all instance of ManageConnection. At first, if an instance of ManageConnection is created, it will be share other instance of ManageConnection. My suggestion is just try without using static.

I assume you don't want to use EJBs, but instead want to use POJOs.
(Note there's a simple solution where Session Beans carry out JPA operations and Servlets call EJBs - less code, less ugly, does what you want.)
Each servlet session should have its own entity manager instance. Remove every case of "static" from the class ManageConnection. Then in your servlet, when you create the HttpSession, additionally create an instance of ManageConnection and store it as an attribute in the session.
public class MyServlet extends HttpServlet {
private ManageConnections getManageConnections(HttpSession sess) {
ManageConnection manageConnection =
(ManageConnection)sess.getAttribute("userManageConnection");
if (manageConnection == null) {
ManageConnection manageConnection = new ManageConnection();
sess.setAttribute("userManageConnection", manageConnection);
}
}
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.processRequest(req, resp);
}
public void processRequest(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
HttpSession sess = req.getSession(true);
ManageConnections manageConnections = this.getManageConnections(sess);
// remaining JPA operations
}
}
Get the EntityManager:
// inside processRequest() above
EntityManager em = manageConnection.getEntityManager();
Start Tx, do entity operations, End Tx
// inside processRequest() above
em.getTransaction().begin();
<PersistenceObject> objName = new <PersistenceObject>();
//properties of the objName to persist
em.persist(<objName>);
em.getTransaction().commit();
Close the EntityManager before the user finishes their session. This is important, because without it some implementations will need to be restarted very often - especially during development when you're rebuilding and redeploying often (I'm looking at you, EclipseLink on Glassfish, deployed using netbeans modules).
make servlet: extends HttpSessionListener
// add the following methods, so we get a callback to sessionDestroyed when the
// session is closed via user logout (terminateSession) or session timeout:
public void init(ServletConfig config) throws ServletException {
config.getServletContext().addListenter(this.class.getName());
}
public void sessionCreated(HttpSessionEvent se) {
}
public void sessionDestroyed(HttpSessionEvent se) {
ManageConnections manageConnections = this.getManageConnections();
manageConnections.getEntityManager().close();
manageConnections.getEntityManagerFactor().close();
}
As I said - a bit ugly, because we are using a very stateful Application Managed Entity Manager in a stateless Servlet. Much cleaner to use a Transaction Scoped Entity Manager in a Stateless Session Bean or Extended Scope (or Application Managed) Entity Manager in a Stateful Session Bean... quite a JPA mouthful, but easier than it sounds.
:-)

I created two classes like this:
//This class has the EntityManagerFactory instance that is going to be shared between the classes
public class ManageConnection {
protected static EntityManagerFactory emf = null;
private static String persitenceName="locationtracker";
//Anonymous Block that is going to be called (beofre) on every call for constructor of this class
//whether through inheritance or normal instantiation
{
if(emf==null || !emf.isOpen())
emf = Persistence.createEntityManagerFactory(persitenceName);
}
public static EntityManagerFactory getEntityManagerFactory(){
return ManageConnection.emf;
}
}
//This class actually handles the trasactional management
public class ManageTransaction extends ManageConnection{
/**
*
*/
public ManageTransaction() {
super();
this.entityManager = emf.createEntityManager();
this.transaction = this.entityManager.getTransaction();
}
/**
* #param entityManager
* #param transaction
*/
public ManageTransaction(EntityManager entityManager,EntityTransaction transaction) {
super();
this.entityManager = entityManager;
this.transaction = transaction;
}
private EntityManager entityManager;
private EntityTransaction transaction;
/**
* #return the entityManager
*/
public EntityManager getEntityManager() {
return entityManager;
}
/**
* #param entityManager the entityManager to set
*/
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
/**
* #return the transaction
*/
public EntityTransaction getTransaction() {
return transaction;
}
/**
* #param transaction the transaction to set
*/
public void setTransaction(EntityTransaction transaction) {
this.transaction = transaction;
}
public void closeEntityManager(){
if(entityManager!=null && entityManager.isOpen()){
entityManager.close();
}
}
public void close(){
this.closeEntityManager();
}
public void flush(){
entityManager.flush();
}
public void begin(){
this.transaction.begin();
}
public void commit(){
this.flush();
this.transaction.commit();
}
public void persist(Object objToPersist){
this.entityManager.persist(objToPersist);
}
}//end of ManageTransaction class
Now if I want to use this, I use like this:
.
.
.
.
.
.
ManageTransaction mt = new ManageTransaction();
Scenario 1
mt.getEntityManager().find(blah,blah);//works perfectly
Scenario 2
mt.begin();
<PersistenceObject> objName = new <PersistenceObject>();
mt.persist(objName);
mt.close();
Scenario 3
String jpaquery = "blah blah";
TypedQuery<ClassType> tq = mt.getEntityManager().createQuery(jpaquery,<Class>.class);
List<ClassType> all = tq.getResultList();
In this way every time creating new Transaction is not required I just create a single transaction and use that transaction every where in my class and at the end closes it.
That way my problem of sharing EntityManager is solved and thus never throws the Exception at any case.
:)

Related

Hibernate - Rollback list of entities if one entity fails

im just working on a project to create, change user in my mysql database. Therefore i have UserService (REST) which creates a user and a GenericDAO class where i can persist users. In my DAO for each user i begin, persist and commit a transaction. Creating single users or find users works perfect.
Now i am facing with the problem to persist or update a list of users. Especially if one user can not be persisted (e.g. duplicates) the hole transaction should be rolled back. It doesnt work in my current setup.
My first idea is to outsource the commit in a separate method. With an loop over all users i only persist them. At the end of the loop i would call my method to commit everything. If a single or more users fails i can catch them with the rollback. Is that a good approach?
AbstractDAO (current)
public abstract class GenericDAO<T> implements IGenericDAO<T>{
#PersistenceContext
protected EntityManager em = null;
private CriteriaBuilder cb = null;
private Class<T> clazz;
public GenericDAO(Class<T> class1) {
this.clazz = class1;
this.em = EntityManagerUtil.getEntityManager();
this.em.getCriteriaBuilder();
}
public final void setClazz(Class<T> clazzToSet) {
this.clazz = clazzToSet;
}
public T create(T entity) {
try {
em.getTransaction().begin();
em.persist(entity);
em.getTransaction().commit();
return entity;
} catch (PersistenceException e) {
em.getTransaction().rollback();
return null;
}
}
public T find(int id) {
return em.find(this.clazz, id);
}
public List<T> findAll() {
return em.createQuery("from "+this.clazz.getName()).getResultList();
}
/** Save changes made to a persistent object. */
public void update(T entity) {
em.getTransaction().begin();
em.merge(entity);
em.getTransaction().commit();
}
/** Remove an object from persistent storage in the database */
public void delete(T entity) {
em.getTransaction().begin();
em.remove(entity);
em.getTransaction().commit();
}
Wouldn't the most convenient solution be to simply add methods like createAll()/updateAll()?
Adding separate public methods for starting and persisting the transaction like start() and commit() creates a whole bunch of problems because it means you suddenly introduce a stateful conversation between the Dao and its clients.
The Dao methods now need to be called in a certain order and, worse still, the state of the EntityManager transaction is retained. If you forget to commit() at the end of one service call using your Dao, a subsequent call is going to mistakenly assume a transaction was not yet started, and that call is going to fail 'for no apparent reason' (not to mention that the original call will appear completed when in reality the transaction was left hanging). This creates bugs that are hard to debug, and tricky to recover from.
EDIT As I already pointed out in the comment below this answer, getting programmatic transaction management right is tricky in a multi-layer application structure, and so, I would recommend to have a look at declarative transaction management.
However, if you insist on managing transactions yourself, I would probably introduce sth like a TransactionTemplate:
public class TransactionTemplate {
private EntityManager em; //populated in a constructor, for instance
public void executeInTransaction(Runnable action) {
try {
em.getTransaction().begin();
action.run();
em.getTransaction().commit();
} catch (Exception e) {
em.getTransaction().rollback();
} finally {
em.clear(); // since you're using extended persistence context, you might want this line
}
}
}
and use it in a service like so:
public class UserService {
private TransactionTemplate template;
private RoleDao roleDao;
private UserDao userDao; //make sure TransactionTemplate and all Daos use the same EntityManager - for a single transaction, at least
public void saveUsers(Collection<User> users, String roleName) {
template.executeInTransaction(() -> {
Role role = roleDao.findByName(roleName);
users.forEach(user -> {
user.addRole(role);
userDao.create(user);
});
// some other operations
});
}
}
(of course, using the above approach means only one layer - the service layer in this case - is aware of transactions, and so DAOs must always be called from inside a service)

Singleton DAO instance keeps old closed session between HTTP transactions

I'm trying to implement the "One-session-per-http-request" pattern with Hibernate, and it works for the 1st request : The servlet's doGet() method opens the session, gets some stuff, and closes the session.
But when I refresh the browser, My DAO Singleton instance (whose constructor gets the session from the SessionFactory) gets called a second time, but still uses the old session object (the singleton constructor is NOT called again). I then obtain a "Session is closed" error.
I guess that the singleton instance must be kept in cache between HTTP requests, so : How can I get the DAO singleton constructor called again ? (or another elegant solution to have the fresh SessionFactory session object ?)
Thank you very much
The servlet :
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
// Gets the session, eventually creates one
Session s = HibernateUtil.currentSession();
// Gets data from singleton DAO instance
MySingletonDAO o = MySingletonDAO.getInstance();
List<Stuff> stuff = o.getAllTheStuff();
// send it to the view
request.setAttribute("foo",stuff);
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(vue);
dispatcher.forward(request, response);
}
/* error handling blah blah */
finally {
// closing the session
HibernateUtil.closeSession();
}
MySingletonDAO.java :
public class MySingletonDAO {
// Usual singleton syntax
private static MySingletonDAO INSTANCE = new MySingletonDAO();
public static MySingletonDAO getInstance() { return INSTANCE;}
private Session session;
private MySingletonDAO() {
session = HibernateUtil.currentSession();
System.out.println("This constructor is called only on the first HTTP transaction");
}
public List<Stuff> getAllTheStuff() {
try {
session.beginTransaction();
Query q = session.createQuery("FROM StuffDBTable");
session.getTransaction().commit();
return (List<Stuff>) q.list();
}
}
}
A classical thread-safe HibernateUtil.java :
public class HibernateUtil {
private static final SessionFactory sessionFactory;
public static final ThreadLocal session = new ThreadLocal();
static {
try {
// Creates the SessionFactory
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (HibernateException he) {
throw new RuntimeException("Conf problem : "+ he.getMessage(), he);
}
}
public static Session currentSession() throws HibernateException {
Session s = (Session) session.get();
// Opens a new Session, if this Thread has none
if (s == null || !s.isOpen() ) {
s = sessionFactory.openSession();
session.set(s);
}
return s;
}
public static void closeSession() throws HibernateException {
Session s = (Session) session.get();
session.set(null);
if (s != null)
s.close();
}
}
What you're asking for doesn't make sense: if the constructor of the singleton was called at each request, it wouldn't be a singleton anymore. The session is indeed closed at the end of the request, but the DAO keeps a reference to the session, instead of getting it from your util class every time it's called.
Your DAO code should be
public class MySingletonDAO {
private static MySingletonDAO INSTANCE = new MySingletonDAO();
public static MySingletonDAO getInstance() { return INSTANCE;}
private MySingletonDAO() {
}
public List<Stuff> getAllTheStuff() {
Session session = HibernateUtil.currentSession();
try {
session.beginTransaction();
Query q = session.createQuery("FROM StuffDBTable");
session.getTransaction().commit();
return (List<Stuff>) q.list();
}
}
}
That said, transactions should be handled declaratively, and should be handled at the service layer rather than the DAO layer: a transaction typically uses deveral DAOs, the entities returned by the DAO should stay managed, and all the accesses and modifications made to these entities should be made inside the transaction.
I strongly recommend using a Java EE container, or Spring, to handle the transactions and the session handling for you. You should also use the standard JPA API rather than the proprietary Hibernate API.

Log Exception into DB

I got a method call from a stateless ejb which looks like the following
#Stateless
#Local(MyCrudService.class)
#TransactionAttribute(TransactionAttributeType.MANDATORY)
public class MyCrudServiceBean implements MyCrudService {
#EJB
private CrudService crudService;
#Override
public void writeLogEntry(StatementLog statementLog) {
try {
crudService.execute(statement.getSql());
} catch (Exception e) {
crudService.writeLogEntry(statementLog);
throw new MyApplicationException(e.getLocalizedMessage());
}
}
// ...
}
CrudSerivce:
#Stateless
#Local(CrudService.class)
#TransactionAttribute(TransactionAttributeType.MANDATORY)
#Interceptors(GenericFrepDataBaseUserInterceptor.class)
public class CrudServiceBean implements CrudService {
public static final String PERSISTENCE_UNIT_NAME = "name";
private EntityManager entityManager;
#PersistenceContext(unitName = PERSISTENCE_UNIT_NAME)
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
#Override
public void execute(String sqlString) {
Query query = entityManager.createNativeQuery(sqlString);
query.executeUpdate();
}
#Override
public void writeLogEntry(StatementLog statementLog) {
entityManager.persist(entity);
}
// ....
}
Statement is an entity which got an sql which is invalid (like 'invalid sql'). On execution I get the following error
javax.ejb.EJBTransactionRolledbackException: JBAS011469
If I debug this, I can see that this happens in the line with the logging.
I think the problem is, that because I am getting an exception the transaction gets rolled back. Because of that it is not possible to write into the db, because there is no open session anymore. Is this the case? What's best practice then? To manually open a session by myself seems quite ugly to me.
Your method log.writeErrorInDb needs to start its own transaction, so that it can still operate when the main transaction is rolled back. Yes, if your Hibernate session is already closed, then your log class would need to be able to open its own session. However it would probably be better to have a transaction boundary covering this entire block of code, and bind the Hibernate session to that, then set your log method to require a new transaction, to ensure it can operate once the first transaction is marked for rollback. i.e. two transactions, but one session
Based on your code, you should be able to annotate your log method:
#Override
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void writeLogEntry(StatementLog statementLog) {
entityManager.persist(entity);
}

What is the scope of a Transaction used in shared EntityManager contexts?

In JPA:
consider the following example, which uses a Container managed transaction scoped Entity manager.
public class ItemDAOImpl implements ItemDAO {
#PersistenceContext(unitName="ItemService")
EntityManager em;
LoggingService ls;
public void createItem(Item item) {
em.persist(item);
ls.log(item.getId(), "created item");
}
// ...
}
public class LoggingService implements AuditService {
#PersistenceContext(unitName="ItemService")
EntityManager em;
public void log(int itemId, String action) {
// verify item id is valid
if (em.find(Item.class, itemId) == null) {
throw new IllegalArgumentException("Unknown item id");
}
LogRecord lr = new LogRecord(itemId, action);
em.persist(lr);
}
}
Am I right in supposing that ls.log() method
will use the transaction of the calling method.
I'm pretty confused about these things right now, can you help?
If you are in EJBs, then very probably those methods will use the same transaction, because of the default transaction propagation method. Just check how they are configured, as it seems they are configured in an XML file.

implementing a dao class properly to manage transactions

I am working on a java web application that calls database backend through hibernate.I use servlets,jsp and tomcat for test/deployment.Most books on java-ee suggested using Dao classes for database calls.As per examples given in books(Hibernate Recipes by Gary Mak),I created a generic base class and a specific subclass as below.
class BaseDao{
private Class persistentClass;
public BaseDao(Class persistentClass) {
super();
this.persistentClass = persistentClass;
}
public Object findById(Long id) {
SessionFactory factory = HibernateUtil.getSessionFactory();
Session session = factory.openSession();
Object object = null;
try {
object = (Object) session.get(persistentClass, id);
return object;
}
finally {
session.close();
}
}
#Override
public void saveOrUpdate(Object obj) {
SessionFactory factory = HibernateUtil.getSessionFactory();
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
session.saveOrUpdate(obj);
tx.commit();
}catch(HibernateException e){
if (tx != null) {
tx.rollback();
}
throw e;
}finally {
session.close();
}
}
}
class SaleOrderDao extends BaseDao{
public SaleOrderDao() {
super(SaleOrder.class);
}
#Override
public SaleOrder findSaleOrderById(Long saleOrderId){
SaleOrder so = (SaleOrder)findById(saleOrderId);
return so;
}
#Override
public void saveOrUpdateSaleOrder(SaleOrder so){
saveOrUpdate( so);
}
}
While going through the posts in this forum ,I came across Ryan Stewart's advice that beginning and ending transactions in a dao method is not recommended..Sadly, my project does not use any web framework that supports transaction management..and I am limited to using jsp,servlets and a servlet container..
Is there some way I can rewrite my dao implementations sothat transactions can be managed properly..I couldn't find anything in this regard from those books I read..
Hope somebody helps me with suggestions
sincerely,
Jim
Normally transactions should not be handled in the DAO. They should be handled by the service layer. One service method may include multiple DAO calls that are all in the same transaction.
Spring (as well as other DI frameworks) allows you to do that by simply annotating your service methods with #Transactional. Without spring you can still do that manually in the service layer

Categories

Resources