Как исправить 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" исправило это для меня.
Ответ 10
Если вы используете JPQL, используйте JOIN FETCH - это самый простой способ:
http://www.objectdb.com/java/jpa/query/jpql/from#LEFT_OUTER_INNER_JOIN_FETCH_
Ответ 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>