Как исправить org.hibernate.LazyInitializationException - не удалось инициализировать прокси - нет сеанса

Я получаю следующее исключение:

Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:167)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:215)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
    at sei.persistence.wf.entities.Element_$$_jvstc68_47.getNote(Element_$$_jvstc68_47.java)
    at JSON_to_XML.createBpmnRepresantation(JSON_to_XML.java:139)
    at JSON_to_XML.main(JSON_to_XML.java:84)

когда я пытаюсь позвонить с основной линии следующим образом:

Model subProcessModel = getModelByModelGroup(1112);
System.out.println(subProcessModel.getElement().getNote());

getModelByModelGroup(int modelgroupid) я реализовал метод getModelByModelGroup(int modelgroupid) следующим образом:

public static Model getModelByModelGroup(int modelGroupId, boolean openTransaction) {

    Session session = SessionFactoryHelper.getSessionFactory().getCurrentSession();     
    Transaction tx = null;

    if (openTransaction) {
        tx = session.getTransaction();
    }

    String responseMessage = "";

    try {
        if (openTransaction) {
            tx.begin();
        }
        Query query = session.createQuery("from Model where modelGroup.id = :modelGroupId");
        query.setParameter("modelGroupId", modelGroupId);

        List<Model> modelList = (List<Model>)query.list(); 
        Model model = null;

        for (Model m : modelList) {
            if (m.getModelType().getId() == 3) {
                model = m;
                break;
            }
        }

        if (model == null) {
            Object[] arrModels = modelList.toArray();
            if (arrModels.length == 0) {
                throw new Exception("Non esiste ");
            }

            model = (Model)arrModels[0];
        }

        if (openTransaction) {
            tx.commit();
        }

        return model;

   } catch(Exception ex) {
       if (openTransaction) {
           tx.rollback();
       }
       ex.printStackTrace();
       if (responseMessage.compareTo("") == 0) {
           responseMessage = "Error" + ex.getMessage();
       }
       return null;
    }
}

и получил исключение. Тогда друг предложил мне всегда тестировать сеанс и получать текущий сеанс, чтобы избежать этой ошибки. Итак, я сделал это:

public static Model getModelByModelGroup(int modelGroupId) {
    Session session = null;
    boolean openSession = session == null;
    Transaction tx = null;
    if (openSession) {
        session = SessionFactoryHelper.getSessionFactory().getCurrentSession(); 
        tx = session.getTransaction();
    }
    String responseMessage = "";

    try {
        if (openSession) {
            tx.begin();
        }
        Query query = session.createQuery("from Model where modelGroup.id = :modelGroupId");
        query.setParameter("modelGroupId", modelGroupId);

        List<Model> modelList = (List<Model>)query.list(); 
        Model model = null;

        for (Model m : modelList) {
            if (m.getModelType().getId() == 3) {
                model = m;
                break;
            }
        }

        if (model == null) {
            Object[] arrModels = modelList.toArray();
            if (arrModels.length == 0) {
                throw new RuntimeException("Non esiste");
            }

            model = (Model)arrModels[0];

            if (openSession) {
                tx.commit();
            }
            return model;
        } catch(RuntimeException ex) {
            if (openSession) {
                tx.rollback();
            }
            ex.printStackTrace();
            if (responseMessage.compareTo("") == 0) {
                responseMessage = "Error" + ex.getMessage();
            }
            return null;        
        }
    }
}

но все равно получаю такую же ошибку. Я много читал об этой ошибке и нашел несколько возможных решений. Одним из них было установить для lazyLoad значение false, но мне не разрешено делать это, поэтому мне предложили контролировать сеанс

Ответ 1

Здесь неправильно то, что ваша конфигурация управления сеансом настроена на закрытие сеанса при фиксации транзакции. Проверьте, есть ли у вас что-то вроде:

<property name="current_session_context_class">thread</property>

в вашей конфигурации.

Чтобы преодолеть эту проблему, вы можете изменить конфигурацию фабрики сеансов или открыть другой сеанс и только потом запрашивать эти лениво загруженные объекты. Но то, что я хотел бы предложить здесь, это инициализировать эту ленивую коллекцию в самой getModelByModelGroup и вызвать:

Hibernate.initialize(subProcessModel.getElement());

когда вы все еще находитесь в активном сеансе.

И последнее. Дружеский совет. У вас есть что-то вроде этого в вашем методе:

for (Model m : modelList) {
    if (m.getModelType().getId() == 3) {
        model = m;
        break;
    }
}

Пожалуйста, вставьте этот код, просто отфильтруйте те модели с идентификатором типа, равным 3, в запросе, всего несколькими строками выше.

Еще немного чтения:

заводская конфигурация сеанса

проблема с закрытой сессией

Ответ 2

Если вы используете Spring, пометьте класс как @Transactional, то Spring будет обрабатывать управление сессиями.

@Transactional
public class MyClass {
    ...
}

Используя @Transactional, многие важные аспекты, такие как распространение транзакций, обрабатываются автоматически. В этом случае, если вызван другой транзакционный метод, у метода будет возможность присоединиться к текущей транзакции, избегая исключения "без сеанса".

Ответ 3

Вы можете попробовать установить

<property name="hibernate.enable_lazy_load_no_trans">true</property>

в файле hibernate.cfg.xml или persistence.xml

Проблема, связанная с этим свойством, хорошо объясняется здесь

Ответ 4

Лучший способ обработать LazyInitializationException - использовать директиву JOIN FETCH:

Query query = session.createQuery(
    "from Model m " +
    "join fetch m.modelType " +
    "where modelGroup.id = :modelGroupId"
);

В любом случае, НЕ используйте следующие анти-паттерны, как это предлагается в некоторых ответах:

Иногда проекция DTO является лучшим выбором, чем выборка объектов, и таким образом вы не получите никакого LazyInitializationException.

Ответ 5

Я получал ту же ошибку для одного-многих отношений для ниже аннотации.

@OneToMany(mappedBy="department", cascade = CascadeType.ALL)

Изменен как ниже после добавления fetch = FetchType.EAGER, он работал у меня.

@OneToMany(mappedBy="department", cascade = CascadeType.ALL, fetch=FetchType.EAGER)

Ответ 6

Это исключение из-за того, что вы вызываете session.getEntityById(), сеанс будет закрыт. Поэтому вам необходимо повторно привязать объект к сеансу. Или простое решение просто настроит default-lazy="false" на ваш entity.hbm.xml, или если вы используете аннотации, просто добавьте @Proxy(lazy=false) в класс сущности.

Ответ 7

Если вы используете Spring данных JPA, Spring Boot вы можете добавить эту строку в application.properties

spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true

Ответ 8

Я столкнулся с той же проблемой. Я думаю, что еще один способ исправить это - вы можете изменить запрос, чтобы присоединиться к извлечению вашего элемента из модели следующим образом:

Query query = session.createQuery("from Model m join fetch m.element where modelGroup.id = :modelGroupId")

Ответ 9

Здесь есть несколько хороших ответов, которые обрабатывают эту ошибку в широком диапазоне. Я столкнулся с конкретной ситуацией с Spring Security, у которой было быстрое, хотя, вероятно, и не оптимальное, исправление.

Во время авторизации пользователя (сразу после входа в систему и прохождения аутентификации) я тестировал пользовательский объект для определенного органа в пользовательском классе, который расширяет SimpleUrlAuthenticationSuccessHandler.

Мой пользовательский объект реализует UserDetails и имеет набор ленивых загруженных ролей, которые бросают исключение "org.hibernate.LazyInitializationException", не могут инициализировать исключение прокси - без сеанса. Изменение этого набора из "fetch = FetchType.LAZY" на "fetch = FetchType.EAGER" исправило это для меня.

Ответ 11

Это означает, что объект, к которому вы пытаетесь получить доступ, не загружен, поэтому напишите запрос, который делает выборку соединения для объекта, к которому вы пытаетесь получить доступ.

Например:

Если вы пытаетесь получить ObjectB из ObjectA, где ObjectB является внешним ключом в ObjectA.

Запрос:

SELECT objA FROM ObjectA obj JOIN FETCH obj.objectB objB

Ответ 12

Если вы используете Grail's Framework, просто разрешить ленивое исключение инициализации, используя ключевое слово Lazy в определенном поле в классе домена.

Для примера:

class Book {
    static belongsTo = [author: Author]
    static mapping = {
        author lazy: false
    }
}

Найти дополнительную информацию здесь

Ответ 13

Это означает, что вы используете JPA или hibernate в своем коде и выполняете операцию изменения в БД без выполнения транзакции бизнес-логики. Итак, простое решение для этого - пометить ваш кусок кода @Transactional

Благодарю.

Ответ 14

В моем случае эта проблема была session.clear() неуместной session.clear().

Ответ 15

В моем случае попытка Hibernate.initialize поля неинициализированного (вида java, а не вида hibernate) объекта приводила к проблемам. После нескольких дней копания замена 'private Person person' на 'private Person person=null' решила много головных болей. Трассировка стека выглядела так:

Caused by: org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:167)

"нет сеанса" действительно отбросил меня, потому что несколько строк назад инициализировали DID успешно.

Ответ 16

Столкнулся с тем же исключением в другом случае использования.

enter image description here

Вариант использования: Попробуйте прочитать данные из БД с помощью DTO-проекции.

Решение: используйте метод get вместо load.

Общая операция

public class HibernateTemplate {
public static Object loadObject(Class<?> cls, Serializable s) {
    Object o = null;
    Transaction tx = null;
    try {
        Session session = HibernateUtil.getSessionFactory().openSession();
        tx = session.beginTransaction();
        o = session.load(cls, s); /*change load to get*/
        tx.commit();
        session.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return o;
}

}

Постоянство Класс

public class Customer {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "Id")
private int customerId;

@Column(name = "Name")
private String customerName;

@Column(name = "City")
private String city;

//constructors , setters and getters

}

Интерфейс CustomerDAO

public interface CustomerDAO 
     {
   public CustomerTO getCustomerById(int cid);
     }

Класс объекта Entity Transfer

public class CustomerTO {

private int customerId;

private String customerName;

private String city;

//constructors , setters and getters

}

Фабричный класс

public class DAOFactory {

static CustomerDAO customerDAO;
static {
    customerDAO = new HibernateCustomerDAO();
}

public static CustomerDAO getCustomerDAO() {
    return customerDAO;
}

}

DAO для конкретного объекта

public class HibernateCustomerDAO implements CustomerDAO {

@Override
public CustomerTO getCustomerById(int cid) {
    Customer cust = (Customer) HibernateTemplate.loadObject(Customer.class, cid);
    CustomerTO cto = new CustomerTO(cust.getCustomerId(), cust.getCustomerName(), cust.getCity());
    return cto;
}

}

Получение данных: тестовый класс

CustomerDAO cdao = DAOFactory.getCustomerDAO();
CustomerTO c1 = cdao.getCustomerById(2);
System.out.println("CustomerName -> " + c1.getCustomerName() + " ,CustomerCity -> " + c1.getCity());

Представить данные

enter image description here

Запрос и вывод, сгенерированные системой Hibernate

Спящий режим: выберите customer0_.Id как Id1_0_0_, customer0_.City как City2_0_0_, customer0_.Name как Name3_0_0_ из CustomerLab31 customer0_, где customer0_.Id =?

CustomerName → Cody, CustomerCity → LA

Ответ 17

использует session.get(*. class, id); но не загружать функцию

Ответ 18

вы также можете решить эту проблему, добавив lazy = false в свой файл *.hbm.xml или вы можете запустить свой объект в Hibernate.init(Object), когда вы получите объект из db

Ответ 19

Сделайте следующие изменения в servlet-context.xml

    <beans:property name="hibernateProperties">
        <beans:props>

            <beans:prop key="hibernate.enable_lazy_load_no_trans">true</beans:prop>

        </beans:props>
    </beans:property>