问题
I get the following exception:
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)
when I try to call from main the following lines:
Model subProcessModel = getModelByModelGroup(1112);
System.out.println(subProcessModel.getElement().getNote());
I implemented the getModelByModelGroup(int modelgroupid) method firstly like this :
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;
}
}
and got the exception. Then a friend suggested me to always test the session and get the current session to avoid this error. So I did this:
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;
}
}
}
but still, get the same error. I have been reading a lot for this error and found some possible solutions. One of them was to set lazyLoad to false but I am not allowed to do this that\'s why I was suggested to control the session
回答1:
What is wrong here is that your session management configuration is set to close session when you commit transaction. Check if you have something like:
<property name="current_session_context_class">thread</property>
in your configuration.
In order to overcome this problem you could change the configuration of session factory or open another session and only than ask for those lazy loaded objects. But what I would suggest here is to initialize this lazy collection in getModelByModelGroup itself and call:
Hibernate.initialize(subProcessModel.getElement());
when you are still in active session.
And one last thing. A friendly advice. You have something like this in your method:
for (Model m : modelList) {
if (m.getModelType().getId() == 3) {
model = m;
break;
}
}
Please insted of this code just filter those models with type id equal to 3 in the query statement just couple of lines above.
Some more reading:
session factory configuration
problem with closed session
回答2:
If you using Spring mark the class as @Transactional, then Spring will handle session management.
@Transactional
public class MyClass {
...
}
By using @Transactional, many important aspects such as transaction propagation are handled automatically. In this case if another transactional method is called the method will have the option of joining the ongoing transaction avoiding the "no session" exception.
回答3:
You can try to set
<property name="hibernate.enable_lazy_load_no_trans">true</property>
in hibernate.cfg.xml or persistence.xml
The problem to keep in mind with this property are well explained here
回答4:
The best way to handle the LazyInitializationException is to use the JOIN FETCH directive:
Query query = session.createQuery(
"from Model m " +
"join fetch m.modelType " +
"where modelGroup.id = :modelGroupId"
);
Anyway, DO NOT use the following Anti-Patterns as suggested by some of the answers:
- Open Session in View
- hibernate.enable_lazy_load_no_trans
Sometimes, a DTO projection is a better choice than fetching entities, and this way, you won't get any LazyInitializationException.
回答5:
I was getting the same error for a one to many relationships for below annotation.
@OneToMany(mappedBy="department", cascade = CascadeType.ALL)
Changed as below after adding fetch=FetchType.EAGER, it worked for me.
@OneToMany(mappedBy="department", cascade = CascadeType.ALL, fetch=FetchType.EAGER)
回答6:
This exception because of when you call session.getEntityById(), the session will be closed. So you need to re-attach the entity to the session. Or Easy solution is just configure default-lazy="false" to your entity.hbm.xml or if you are using annotations just add @Proxy(lazy=false) to your entity class.
回答7:
if you use spring data jpa , spring boot you can add this line in application.properties
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
回答8:
I encountered the same issue. I think another way to fix this is that you can change the query to join fetch your Element from Model as follows:
Query query = session.createQuery("from Model m join fetch m.element where modelGroup.id = :modelGroupId")
回答9:
There are several good answers here that handle this error in a broad scope. I ran into a specific situation with Spring Security which had a quick, although probably not optimal, fix.
During user authorization (immediately after logging in and passing authentication) I was testing a user entity for a specific authority in a custom class that extends SimpleUrlAuthenticationSuccessHandler.
My user entity implements UserDetails and has a Set of lazy loaded Roles which threw the "org.hibernate.LazyInitializationException - could not initialize proxy - no Session" exception. Changing that Set from "fetch=FetchType.LAZY" to "fetch=FetchType.EAGER" fixed this for me.
回答10:
This means that the object which you are trying to access is not loaded, so write a query that makes a join fetch of the object which you are trying to access.
Eg:
If you are trying to get ObjectB from ObjectA where ObjectB is a foreign key in ObjectA.
Query :
SELECT objA FROM ObjectA obj JOIN FETCH obj.objectB objB
回答11:
If you are using JPQL, use JOIN FETCH is the easiest way: http://www.objectdb.com/java/jpa/query/jpql/from#LEFT_OUTER_INNER_JOIN_FETCH_
回答12:
If you are using Grail's Framework, it's simple to resolve lazy initialization exception by using Lazy keyword on specific field in Domain Class.
For-example:
class Book {
static belongsTo = [author: Author]
static mapping = {
author lazy: false
}
}
Find further information here
回答13:
This means you are using JPA or hibernate in your code and performing modifying operation on DB without making the business logic transaction. So simple solution for this is mark your piece of code @Transactional
Thanks.
回答14:
In my case a misplaced session.clear() was causing this problem.
回答15:
Faced the same Exception in different use case.
Use Case : Try to read data from DB with DTO projection.
Solution: Use get method instead of load.
Generic Operation
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;
}
}
Persistence Class
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 interface
public interface CustomerDAO
{
public CustomerTO getCustomerById(int cid);
}
Entity Transfer Object Class
public class CustomerTO {
private int customerId;
private String customerName;
private String city;
//constructors , setters and getters
}
Factory Class
public class DAOFactory {
static CustomerDAO customerDAO;
static {
customerDAO = new HibernateCustomerDAO();
}
public static CustomerDAO getCustomerDAO() {
return customerDAO;
}
}
Entity specific 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;
}
}
Retrieving data: Test Class
CustomerDAO cdao = DAOFactory.getCustomerDAO();
CustomerTO c1 = cdao.getCustomerById(2);
System.out.println("CustomerName -> " + c1.getCustomerName() + " ,CustomerCity -> " + c1.getCity());
Present Data
Query and output generated by Hibernate System
Hibernate: select customer0_.Id as Id1_0_0_, customer0_.City as City2_0_0_, customer0_.Name as Name3_0_0_ from CustomerLab31 customer0_ where customer0_.Id=?
CustomerName -> Cody ,CustomerCity -> LA
回答16:
uses session.get(*.class, id); but do not load function
回答17:
you could also solved it by adding lazy=false into into your *.hbm.xml file or you can init your object in Hibernate.init(Object) when you get object from db
回答18:
Do the following changes in 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>
来源:https://stackoverflow.com/questions/21574236/how-to-fix-org-hibernate-lazyinitializationexception-could-not-initialize-prox