Исключение закрытия сеанса гибернации, когда 10 или более пользователей обращаются к странице

#java #hibernate #spring-mvc

#java #гибернация #spring-mvc

Вопрос:

У меня есть приложение spring MVC с гибернацией.Я продолжаю получать сообщение об ошибке закрытия сеанса, когда 10 или более пользователей заходили на одну и ту же страницу для чтения данных или после быстрых последующих запросов. Пожалуйста, помогите, мне нужно было срочно что-то исправить. Это влияет на клиента.

Я использую приведенный ниже код

 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;
 

Для обновления

  @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;
    }
 

Исключение

  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)
 

Комментарии:

1. Является ли session локальной переменной в методе?

2. да, я объявляю это в методе.

3. какое исключение вы получаете при получении ошибки закрытия сеанса? Можете ли вы вставить трассировку стека исключений в свой ответ?

4. Я обновил ошибку. Это отображается точно в строке List<?> comLst = query.list();

5. Не используйте openSession use getCurrentSession и позвольте spring управлять ресурсами. При использовании openSession вы открываете новый сеанс за пределами spring, и если вы сами не управляете ресурсами должным образом, у вас будет утечка сеансов и соединений thys.

Ответ №1:

Весной это может выглядеть так:

 @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);
}
 

ДЛЯ ОБНОВЛЕНИЯ

 // 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);
}
 

Ссылка

Комментарии:

1. Я использовал ваш код, но все равно получаю ошибку при закрытии сеанса.

2. Вы проверили настройки своей базы данных? Возможно, вы ограничиваете максимальное количество подключений к своей базе данных.

3. вы имеете в виду уровень конфигурации гибернации или саму базу данных

4. Вы должны проверить их оба. В файле конфигурации гибернации может быть что-то вроде этого: «hibernate.connection.pool_size», что является максимальным количеством объединенных подключений. Вот ссылка на него: docs.jboss.org/hibernate/core/3.3/reference/en-US/html /…

5. Я не установил размер пула. я ищу в Интернете, должен ли я использовать SessionFactory.getCurrentSession() вместо SessionFactory.OpenSession

Ответ №2:

Как вы извлекаете свои сеансы SessionFactory.openSession() или SessionFactory.getCurentSession() ? Имейте в виду, что сеансы гибернации не являются потокобезопасными, поэтому вам требуется один сеанс на цикл ответа на запрос.

Комментарии:

1. я использую SessionFactory.OpenSession(), но все равно получаю ошибку для параллельного запроса.

Ответ №3:

Вы должны использовать SessionFactory.getCurrentSession() вместо OpenSession() . Это позволит автоматически открывать и закрывать сеансы. Также вы должны использовать транзакцию Spring с использованием метода @Transactional with you. Управление транзакциями Spring более эффективно, чем getCurrentTransaction() в режиме гибернации

Комментарии:

1. Я использую метод try-catch in, кроме getCurrentTransaction. этот метод поможет мне избежать закрытия сеанса.

2. getCurrentTransaction не нужно закрывать сеанс, поскольку он будет повторно использовать тот же сеанс. И, таким образом, может решить вашу проблему.

3. Спасибо за ответ, но в сеансе гибернации такого метода не существует, только что проверено.