1


I have a spring MVC application with hibernate.I keep on getting the session closed error, when 10 or more users accessed the same page for reading the data or after fast subsequent requests. Please help, I needed a crucial fix. It is affecting the customer.

I use the below code

try{
    session = sessionFactory.openSession();
    tx = session.getTransaction();
    session.beginTransaction();
    Map<Organization, List<Users>> comToUserLst 
                           = new HashMap<Organization,List<Users>>();

    String queryString = "FROM Users as usr Inner Join usr.organization 
                          as org     where org.id = :id";

    Query query = session.createQuery(queryString);
    query.setInteger("id", Integer.valueOf(id));

    List<?> comLst = query.list();
    Iterator<?> ite = comLst.iterator();
    while (ite.hasNext()) {
        Object[] objects = (Object[]) ite.next();

        Users user = (Users) objects[0];

        Organization Organization = (Organization) objects[1];
        if (comToUserLst.containsKey(Organization)) {
            List<Users> usrLst = new ArrayList<Users>();
            usrLst.addAll(comToUserLst.get(Organization));
            usrLst.add(user);
            comToUserLst.put(Organization, usrLst);
        } else {
            List<Users> userLst = new ArrayList<Users>();
            userLst.add(user);
            comToUserLst.put(Organization, userLst);
        }
    }

 } catch (HibernateException e) {
    tx.rollback();
    e.printStackTrace();
 } finally {
    tx.commit();
    session.close();
 }
 return comToUserLst;

For update

 @Transactional
    public Account updateAccount(Account account, UserDetail userInfo) {

        session = sessionFactory.getCurrentSession();


        Account acct = null;

        String queryString = "FROM Account where id = :acctId";
        Query query = session.createQuery(queryString);
        query.setLong("acctId", account.getId());

        acct = (Account) query.uniqueResult();

        acct.setName(account.getName());
        acct.setPhone(account.getPhone());
        acct.setRating(account.getRating());
        acct.setFax(account.getFax());
        acct.setAccountNumber(account.getAccountNumber());
        if (!ValidateUtil.isNullOrEmptyCheckStr(account.getParentAccount()
                .getName())) {
            acct.setParentAccount(account.getParentAccount());
        }
        acct.setWebsite(account.getWebsite());
        acct.setType(account.getType());
        acct.setIndustry(account.getIndustry());
        acct.setNumberOfEmployees(account.getNumberOfEmployees());
        acct.setDescription(account.getDescription());
        acct.setAnnualRevenue(account.getAnnualRevenue());
        acct.setEmail(account.getEmail());

        acct.setBillingAddress(account.getBillingAddress());
        acct.setShippingAddress(account.getShippingAddress());

        Users user = new Users();
        user.setId(userInfo.getUserId());
        // modified details
        acct.setModifiedBy(user);
        acct.setModifiedDate(new Date());
        //update use merge
        session.merge(acct);
        session.flush();

        System.out.println("update Account" + acct.getId());

        return acct;
    }

Exception

 org.hibernate.SessionException: Session is closed!
        at org.hibernate.internal.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:133)
        at org.hibernate.internal.SessionImpl.getTransactionCoordinator(SessionImpl.java:2069)
        at org.hibernate.loader.Loader.doQuery(Loader.java:923)
        at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:354)
        at org.hibernate.loader.Loader.doList(Loader.java:2553)
        at org.hibernate.loader.Loader.doList(Loader.java:2539)
        at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2369)
        at org.hibernate.loader.Loader.list(Loader.java:2364)
        at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:496)
        at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:387)
        at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:231)
        at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1264)
        at org.hibernate.internal.QueryImpl.list(QueryImpl.java:103)
        at com.oi.service.setup.OrganizationService.getOrgToUserLst(OrganizationService.java:311)
        at com.oi.service.setup.OrganizationService$$FastClassBySpringCGLIB$$84e99831.invoke(<generated>)
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)

3 Answers3

0

You should use sessionFactory.getCurrentSession() in place of openSession(). This will maintain the opening and closing sessions automatically. Also you should use Spring's Transaction using @Transactional with you method. Spring's Transaction management is more efficient than the Hibernate's getCurrentTransaction()

KayV
  • 12,987
  • 11
  • 98
  • 148
0

In Spring it might need to look like this:

@Autowired
private SessionFactory sessionFactory;

public void setSessionFactory(SessionFactory sessionFactory) {
    this.sessionFactory = sessionFactory;
}

@Transactional
public Map getOrgToUserLst() {
    Map<Organization, List<Users>> comToUserLst = new HashMap<Organization,List<Users>>();
    String queryString = "FROM Users as usr Inner Join usr.organization as org where org.id = :id";

    List<?> comLst = this.sessionFactory.getCurrentSession()
            .createQuery(queryString)
            .setParameter(0, Integer.valueOf(id))
            .list();
    Iterator<?> ite = comLst.iterator();

    while (ite.hasNext()) {
        Object[] objects = (Object[]) ite.next();

        Users user = (Users) objects[0];

        Organization Organization = (Organization) objects[1];
        if (comToUserLst.containsKey(Organization)) {
            List<Users> usrLst = new ArrayList<Users>();
            usrLst.addAll(comToUserLst.get(Organization));
            usrLst.add(user);
            comToUserLst.put(Organization, usrLst);
        } else {
            List<Users> userLst = new ArrayList<Users>();
            userLst.add(user);
            comToUserLst.put(Organization, userLst);
        }
    }

    return comToUserLst;
}

@Transactional
public void saveOrganization(Organization org) {
    this.sessionFactory.getCurrentSession().persist(org);
}

@Transactional
public void updateOrganization(Organization org) {
    this.sessionFactory.getCurrentSession().merge(org);
}

@Transactional
public void deleteOrganization(Organization org) {
    getCurrentSession().delete(org);
}

@Transactional
public void deleteOrganizationById(long id) {
    final Organization org = this.getCurrentSession().get(Organization, id);
    this.getCurrentSession().delete(org);
}

FOR UPDATE

// Get an account object by ID
public Account getAccount(long id) {
    session = sessionFactory.getCurrentSession();
    String queryString = "FROM Account where id = :acctId";
    Query query = session.createQuery(queryString);
    query.setLong("acctId", id);
    return (Account) query.uniqueResult();
}

// Set account object's attributes
public Account updateAccount(Account acct, UserDetail userInfo) {
    acct.setName(account.getName());
    acct.setPhone(account.getPhone());
    acct.setRating(account.getRating());
    acct.setFax(account.getFax());
    acct.setAccountNumber(account.getAccountNumber());
    if (!ValidateUtil.isNullOrEmptyCheckStr(account.getParentAccount()
            .getName())) {
        acct.setParentAccount(account.getParentAccount());
    }
    acct.setWebsite(account.getWebsite());
    acct.setType(account.getType());
    acct.setIndustry(account.getIndustry());
    acct.setNumberOfEmployees(account.getNumberOfEmployees());
    acct.setDescription(account.getDescription());
    acct.setAnnualRevenue(account.getAnnualRevenue());
    acct.setEmail(account.getEmail());

    acct.setBillingAddress(account.getBillingAddress());
    acct.setShippingAddress(account.getShippingAddress());

    Users user = new Users();
    user.setId(userInfo.getUserId());
    // modified details
    account.setModifiedBy(user);
    account.setModifiedDate(new Date());
    updateAccount(acct);
}

// Update the account object in the database. Here transaction is necessary
@Transactional
private Account updateAccount(Account acct) {
    session = sessionFactory.getCurrentSession();
    //update use merge
    System.out.println("update Account" + acct.getId());
    return session.merge(acct);
}

// This is for testing
public void testUpdate(long id, UserDetail userInfo) {
    Account acc = getAccount(id);
    updateAccount(acct, userInfo);
}

Reference

  • I used your code , but still getting error as session closed. – Rajasekar Ramalingam Oct 17 '16 at 08:05
  • Have you checked your database settings? Maybe you're limiting the maximum number of connections to your database. – Mihály Lestyán Oct 17 '16 at 08:13
  • you mean hibernate config level or database itself – Rajasekar Ramalingam Oct 17 '16 at 08:17
  • You should check both of them. In the hibernate configuration file there might be something like this: "hibernate.connection.pool_size", which is the maximum number of pooled connections. Here is the reference for it: https://docs.jboss.org/hibernate/core/3.3/reference/en-US/html/session-configuration.html#configuration-hibernatejdbc – Mihály Lestyán Oct 17 '16 at 08:22
  • I didnot set any pool size.i am searching in web do i have to use sessionFactory.getCurrentSession() instead of sessionFactory.openSession – Rajasekar Ramalingam Oct 17 '16 at 08:25
  • You shouldn't use sessionFactory.getCurrentSession because if you call the close method on the session object, next time you try to get the current session, it will be closed already. You should use sessionFactory.openSession instead, and close the session each time you finished the work as in the provided example (see hibernate documentation). – Mihály Lestyán Oct 17 '16 at 08:29
  • This guy faced the same problem, but used getCurrent session. Please look into it. http://stackoverflow.com/questions/8036947/hibernate-session-closed-exception-after-fast-subsequent-requests – Rajasekar Ramalingam Oct 17 '16 at 08:41
  • It seems to be an issue with your session object. You might be re-using it while you shouldn't. Can you provide the whole class source code for us? – Mihály Lestyán Oct 17 '16 at 08:55
  • I have updated the error .It is show exactly in the line of List> comLst = query.list(); – Rajasekar Ramalingam Oct 17 '16 at 09:03
  • error showing could not obtain transaction-synchronized Session for current thread – Rajasekar Ramalingam Oct 17 '16 at 10:05
  • In this case, check out this issue: http://stackoverflow.com/questions/26203446/spring-hibernate-could-not-obtain-transaction-synchronized-session-for-current Also you can check out this article about `@EnableTransactionManagement` annotation: http://www.concretepage.com/spring/example_enabletransactionmanagement_spring – Mihály Lestyán Oct 17 '16 at 10:17
  • No bean named 'transactionManager' is defined error – Rajasekar Ramalingam Oct 17 '16 at 10:23
  • I really worked dude...Thanks a lot. Please also advise how to update a record using @transactional – Rajasekar Ramalingam Oct 17 '16 at 10:40
  • I'm glad I could help! I've updated the answer accordingly. As far as I know you can use the save(), update() and saveOrUpdate() methods for this purpose. – Mihály Lestyán Oct 17 '16 at 11:43
  • I was wrong in the last comment. Spring's API documentation says that there's `persist`, `merge`, `delete` methods for insert, update, delete operations. http://docs.jboss.org/jbossas/javadoc/7.1.2.Final/org/hibernate/Session.html – Mihály Lestyán Oct 17 '16 at 12:06
  • great !!! everything is so perfect. except when try to save two different records. i have this error, please help.. "Illegal attempt to associate a collection with two open sessions; nested exception is org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions" – Rajasekar Ramalingam Oct 17 '16 at 12:31
  • You may need to specify the propagation types in the @Transactional annotation: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/transaction/annotation/Propagation.html Also you can try to using `merge()` instead of `persist()`. You can also check the entity associations, they should be `CascadeType.MERGE` or `CascadeType.ALL`. See this reference: https://access.redhat.com/solutions/1354713 – Mihály Lestyán Oct 17 '16 at 13:00
  • In update, don't we need pull the record and update only the update value in object. as shown below: – Rajasekar Ramalingam Oct 17 '16 at 13:28
  • I have added the code for update that i m using .please help – Rajasekar Ramalingam Oct 17 '16 at 13:30
  • Why i am retrieving previous value is because if i update new value that value only gets save .So i pull the previous value and added the new updated value. – Rajasekar Ramalingam Oct 17 '16 at 13:32
  • For the updateAccount method try the updated code I provided. I hope that helps. – Mihály Lestyán Oct 17 '16 at 13:56
  • Thanks a lot for your help dude, but the old error came session closed. – Rajasekar Ramalingam Oct 17 '16 at 14:53
  • Account retAcct=accountService.getAccount(String.valueOf(acct.getId()));Account clonedAcct= accountService.cloneAccount(retAcct,acct, userInfo); acct1=accountService.updateAccount(clonedAcct); – Rajasekar Ramalingam Oct 17 '16 at 14:54
  • this error came ignore previous Found two representations of same collection: – Rajasekar Ramalingam Oct 17 '16 at 14:58
  • Hi Lesty, While i adding i having, please help – Rajasekar Ramalingam Oct 18 '16 at 11:39
0

How are you fetching your sessions SessionFactory.openSession() or SessionFactory.getCurentSession()? Keep in mind that hibernate sessions are not thread safe, hence you require one session per request response cycle.

BHARAT Bhasin
  • 45
  • 1
  • 6