Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java EE (J2EE) и Spring > hibernate createCriteria


Автор: Samotnik 17.5.2011, 18:37
привет.
Столкнулся с неприятной проблемой. Не понимаю с чего и откуда взялось, но частенько вываливается такого рода ошибка:
Цитата

com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed.
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
        .....
Caused by: java.lang.OutOfMemoryError: Java heap space

И появляется именно на createCriteria. Данные не большие и в БД их мало. Вот пример:
Код

public List<Device> getByTenant(long tenantId) throws SQLException {
        Session session = null;
        try {
            session = HibernateUtil.openSession();
            Tenant tenant = (Tenant) session.createCriteria(Tenant.class).add(Restrictions.idEq(tenantId)).uniqueResult();
            //Tenant tenant = (Tenant) session.get(Tenant.class, tenantId); //если брать так, то нету ошибки
            if (tenant == null) {
                throw new NotFoundInnerException("Tenant id " + tenantId + " not found");
            }
            return session.createCriteria(Device.class) // но зато есть здесь :)
                                         .add(Restrictions.eq("tenant.id", tenantId))
                                         .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();
        } finally {
            HibernateUtil.closeSession(session);
        }
    }

Возможно проблема заключается в том, что примерно 5 таких запросов выполняются друг за другом (в данном случае выбираются девайсы по тенанту, но есть также и 4 других сущности из которых выбираются данные таким же образом) ?

Где искать причину ? smile 
Было бы в БД записей около 100.000 другое дело, а то там всего то 40 записей ...

Автор: Samotnik 17.5.2011, 19:52
новые подробности. Оказывается 
Код

Criteria criteria = session.createCriteria(App.class)
                                         .add(Restrictions.eq("tenant.id", tenantId))
                                         .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

отрабатывает, а вот когда делаю
Код

criteria.list();

выстреливает java.lang.OutOfMemoryError: Java heap space

Автор: Stolzen 17.5.2011, 20:25
Код

    public void smth(E el) {
        Session session = null;
 
        try {
            session = HibernateUtil.getSessionFactory().getCurrentSession();
            Transaction transaction = session.beginTransaction();
            
            ....

            transaction.commit();
        } finally {
            if (session != null && session.isOpen()) {
                session.close();
            }
        }
    } 


Если делать так, то ошибки "No operations allowed after connection closed." не должно возникнуть.

И, похоже, слишком рано return делаете.

С критерием - вот так можно:

Код

    public List<E> getAllElements() {
        Session session = null;
        List<E> els = new ArrayList<E>();
        
        try {
            session = HibernateUtil.getSessionFactory().getCurrentSession();
            session.beginTransaction();
            els = session.createCriteria(elementClass).list();
        } finally {
            if (session != null && session.isOpen()) {
                session.close();
            }
        }
        
        return els;
    }


Добавлено через 4 минуты и 14 секунд
Цитата(Samotnik @  17.5.2011,  20:52 Найти цитируемый пост)
отрабатывает, а вот когда делаю
Выделить всёкод Java
1:
    
criteria.list();

выстреливает java.lang.OutOfMemoryError: Java heap space


Скорее всего, потому что createCriteria - это по сути Builder, который строит запрос, а когда вызывается list() происходит извлечение самих данных.

Автор: Samotnik 17.5.2011, 21:29
Stolzen, да, но эта конструкция работала полгода и всё было хорошо, а сейчас посыпались ошибки.

Добавлено через 1 минуту и 41 секунду
Цитата(Stolzen @  17.5.2011,  20:25 Найти цитируемый пост)
И, похоже, слишком рано return делаете.

что значит "рано" ? Нормально я делаю smile

Автор: MisterCleric 17.5.2011, 23:17
Цитата

.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);


Вот это баг архитектуры программиста, т.е. тебя Samotnik, 
А связан он с тем, что ты пытаешься вытащить все дерево сущностей отталкиваясь от App да еще и списком их хочешь.
Давай избавляйся от Fetch.EAGER на вложенных коллекциях и убирай этот DISTINCT.
А вот теперь действительно представь, что у тебя будет, если записей станет 100 000?..

Автор: Samotnik 18.5.2011, 01:26
MisterCleric,  LAZY использовать ?

Автор: sergioK1 18.5.2011, 08:52
У меня давно возник этот вопрос ,не знаю сюда ее лучше вклеить или нет , 
 

С DB работаю много лет,и не только на Java, работаю напрямую через Pperare Statement (иногда cacheRowSet) , проблем которые тут (не только в этой ветке)описываються не возникало, пробовал  несколько вариатов Persistent Layer, говорят что так лучше ,

1) Что это дает? ведь все равно select(insert,update,delete) нужно писать руками , ведь если что-то меняеться в DB нужно мапить
заново. Все равно если поле написать ошибочно , скажем, From imageName вместо Image_name ошибка будет в обоих случаях,
ключи , связи все равно нужно в DB прописывать , 
 ??
2) как увидеть реальную Query, которую потом отлаживать на DB ? и наоборот Я сначала строю SQL на базе и как мне потом
   его переводить в тот же Hibernate(JPA или Eclipse link) ? не терая при этом оптимизацию, потом если выбор полей поменялся,
  то нужно менять класс, а тут у меня перекачка  ResultSet в мой объект , и какая разница? 
  Работаю примитивно никаких ArrayList , только массив (так быстрее и прыгать в нем легко) , 

Желательно конкретные примеры, типа слева один  способ  , справа другой,  , а не общии рассуждения 




 
 

Автор: MisterCleric 18.5.2011, 11:50
Цитата

LAZY использовать ? 


Да, ставь LAZY. Это будет более правильно, но тогда тебе нужно переделывать архитектуру своего приложения, как я понял по примерам кода.
можно еще так:
Код

@Entity
public class Bank implements Countable, Serializable {
    @Id
    private Long id;

    @ManyToOne
    @JoinColumn(name = "JURIDICALBANKID")
    @OptimisticLock(excluded = true)
    private Bank parent;

    @OneToMany(mappedBy = "parent", cascade = {CascadeType.REMOVE, CascadeType.MERGE}, fetch = FetchType.EAGER)
    @Fetch(FetchMode.SELECT) //HERE
    private List<Bank> branches = new ArrayList<Bank>();
}


Тогда все твои вложенные коллекции будут селектиться из БД в отдельном запросе. И снова тебе не нужен будет 
Код

.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)

Автор: Samotnik 18.5.2011, 12:14
MisterCleric, спасибо, оставил eager, но добавил - FetchMode.SELECT
Код

@OneToMany(mappedBy = "tenant", fetch = FetchType.EAGER)
@Fetch(FetchMode.SELECT)
private Set<Category> categories;

ошибки пропали smile  smile  
Надеюсь навсегда  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)