org.hibernate.LazyInitializationException: failed to lazily initialize a collection [duplicate] - java

I have this problem:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: mvc3.model.Topic.comments, no session or session was closed
Here is the model:
#Entity
#Table(name = "T_TOPIC")
public class Topic {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
#ManyToOne
#JoinColumn(name="USER_ID")
private User author;
#Enumerated(EnumType.STRING)
private Tag topicTag;
private String name;
private String text;
#OneToMany(mappedBy = "topic", cascade = CascadeType.ALL)
private Collection<Comment> comments = new LinkedHashSet<Comment>();
...
public Collection<Comment> getComments() {
return comments;
}
}
The controller, which calls model looks like the following:
#Controller
#RequestMapping(value = "/topic")
public class TopicController {
#Autowired
private TopicService service;
private static final Logger logger = LoggerFactory.getLogger(TopicController.class);
#RequestMapping(value = "/details/{topicId}", method = RequestMethod.GET)
public ModelAndView details(#PathVariable(value="topicId") int id)
{
Topic topicById = service.findTopicByID(id);
Collection<Comment> commentList = topicById.getComments();
Hashtable modelData = new Hashtable();
modelData.put("topic", topicById);
modelData.put("commentList", commentList);
return new ModelAndView("/topic/details", modelData);
}
}
The jsp-page looks li the following:
<%#page import="com.epam.mvc3.helpers.Utils"%>
<%# page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%# page session="false" %>
<html>
<head>
<title>View Topic</title>
</head>
<body>
<ul>
<c:forEach items="${commentList}" var="item">
<jsp:useBean id="item" type="mvc3.model.Comment"/>
<li>${item.getText()}</li>
</c:forEach>
</ul>
</body>
</html>
Exception is rised, when viewing jsp. In the line with c:forEach loop

If you know that you'll want to see all Comments every time you retrieve a Topic then change your field mapping for comments to:
#OneToMany(fetch = FetchType.EAGER, mappedBy = "topic", cascade = CascadeType.ALL)
private Collection<Comment> comments = new LinkedHashSet<Comment>();
Collections are lazy-loaded by default, take a look at this if you want to know more.

From my experience, I have the following methods to solved the famous LazyInitializationException:
(1) Use Hibernate.initialize
Hibernate.initialize(topics.getComments());
(2) Use JOIN FETCH
You can use the JOIN FETCH syntax in your JPQL to explicitly fetch the child collection out. This is some how like EAGER fetching.
(3) Use OpenSessionInViewFilter
LazyInitializationException often occur in view layer. If you use Spring framework, you can use OpenSessionInViewFilter. However, I do not suggest you to do so. It may leads to performance issue if not use correctly.

I know it's an old question but I want to help.
You can put the transactional annotation on the service method you need, in this case findTopicByID(id) should have
#Transactional(propagation=Propagation.REQUIRED, readOnly=true, noRollbackFor=Exception.class)
more info about this annotation can be found here
About the other solutions:
fetch = FetchType.EAGER
is not a good practice, it should be used ONLY if necessary.
Hibernate.initialize(topics.getComments());
The hibernate initializer binds your classes to the hibernate technology. If you are aiming to be flexible is not a good way to go.
Hope it helps

The origin of your problem:
By default hibernate lazily loads the collections (relationships) which means whenver you use the collection in your code(here comments field
in Topic class)
the hibernate gets that from database, now the problem is that you are getting the collection in your controller (where the
JPA session is closed).This is the line of code that causes the exception
(where you are loading the comments collection):
Collection<Comment> commentList = topicById.getComments();
You are getting "comments" collection (topic.getComments()) in your controller(where JPA session has ended) and that causes the exception. Also if you had got
the comments collection in your jsp file like this(instead of getting it in your controller):
<c:forEach items="topic.comments" var="item">
//some code
</c:forEach>
You would still have the same exception for the same reason.
Solving the problem:
Because you just can have only two collections with the FetchType.Eager(eagerly fetched collection) in an Entity class and because lazy loading is more
efficient than eagerly loading, I think this way of solving your problem is better than just changing the FetchType to eager:
If you want to have collection lazy initialized, and also make this work,
it is better to add this snippet of code to your web.xml :
<filter>
<filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
What this code does is that it will increase the length of your JPA session or as the documentation says, it is used "to allow for lazy loading in web views despite the original transactions already being completed." so
this way the JPA session will be open a bit longer and because of that
you can lazily load collections in your jsp files and controller classes.

#Controller
#RequestMapping(value = "/topic")
#Transactional
i solve this problem by adding #Transactional,i think this can make session open

The best way to handle the LazyInitializationException is to join fetch upon query time, like this:
select t
from Topic t
left join fetch t.comments
You should ALWAYS avoid the following anti-patterns:
FetchType.EAGER
OSIV (Open Session in View)
hibernate.enable_lazy_load_no_trans Hibernate configuration property
Therefore, make sure that your FetchType.LAZY associations are initialized at query time or within the original #Transactional scope using Hibernate.initialize for secondary collections.

The problem is caused by accessing an attribute with the hibernate session closed. You have not a hibernate transaction in the controller.
Possible solutions:
Do all this logic, in the service layer, (with the #Transactional), not in the controller. There should be the right place to do this, it is part of the logic of the app, not in the controller (in this case, an interface to load the model). All the operations in the service layer should be transactional.
i.e.: Move this line to the TopicService.findTopicByID method:
Collection commentList = topicById.getComments();
Use 'eager' instead of 'lazy'. Now you are not using 'lazy' .. it is not a real solution, if you want to use lazy, works like a temporary (very temporary) workaround.
use #Transactional in the Controller. It should not be used here, you are mixing service layer with presentation, it is not a good design.
use OpenSessionInViewFilter, many disadvantages reported, possible instability.
In general, the best solution is the 1.

The reason is that when you use lazy load, the session is closed.
There are two solutions.
Don't use lazy load.
Set lazy=false in XML or Set #OneToMany(fetch = FetchType.EAGER) In annotation.
Use lazy load.
Set lazy=true in XML or Set #OneToMany(fetch = FetchType.LAZY) In annotation.
and add OpenSessionInViewFilter filter in your web.xml
Detail See my POST.

In order to lazy load a collection there must be an active session. In a web app there are two ways to do this. You can use the Open Session In View pattern, where you use an interceptor to open the session at the beginning of the request and close it at the end. The risk there is that you have to have solid exception handling or you could bind up all your sessions and your app could hang.
The other way to handle this is to collect all the data you need in your controller, close your session, and then stuff the data into your model. I personally prefer this approach, as it seems a little closer to the spirit of the MVC pattern. Also if you get an error from the database this way you can handle it a lot better than if it happens in your view renderer. Your friend in this scenario is Hibernate.initialize(myTopic.getComments()). You will also have to reattach the object to the session, since you're creating a new transaction with every request. Use session.lock(myTopic,LockMode.NONE) for that.

One of the best solutions is to add the following in your application.properties file:
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true

If you are trying to have a relation between a entity and a Collection or a List of java objects (for example Long type), it would like something like this:
#ElementCollection(fetch = FetchType.EAGER)
public List<Long> ids;

Two things you should have for fetch = FetchType.LAZY.
#Transactional
and
Hibernate.initialize(topicById.getComments());

There are multiple solution for this Lazy Initialisation issue -
1) Change the association Fetch type from LAZY to EAGER but this is not a good practice because this will degrade the performance.
2) Use FetchType.LAZY on associated Object and also use Transactional annotation in your service layer method so that session will remain open and when you will call topicById.getComments(), child object(comments) will get loaded.
3) Also, please try to use DTO object instead of entity in controller layer. In your case, session is closed at controller layer. SO better to convert entity to DTO in service layer.

I got this error after a second execution of a method to generate a JWT token.
The line user.getUsersRole().stream().forEachOrdered((ur) -> roles.add(ur.getRoleId())); generated the error.
// MyUserDetails.java
#Service
public class MyUserDetails implements UserDetailsService {
#Override
public UserDetails loadUserByUsername(String email) {
/* ERROR
/* org.hibernate.LazyInitializationException: failed to
/* lazily initialize a collection of role:
/* com.organizator.backend.model.User.usersRole,
/* could not initialize proxy - no Session */
user.getUsersRole().stream().forEachOrdered((ur) ->
roles.add(ur.getRoleId()));
In my case the #Transactional annotation solved it,
// MyUserDetails.java
import org.springframework.transaction.annotation.Transactional;
#Service
public class MyUserDetails implements UserDetailsService {
#Override
#Transactional // <-- added
public UserDetails loadUserByUsername(String email) {
/* No Error */
user.getUsersRole().stream().forEachOrdered((ur) ->
roles.add(ur.getRoleId()));

#Transactional annotation on controller is missing
#Controller
#RequestMapping("/")
#Transactional
public class UserController {
}

I found out that declaring #PersistenceContext as EXTENDED also solves this problem:
#PersistenceContext(type = PersistenceContextType.EXTENDED)

To solve the problem in my case it was just missing this line
<tx:annotation-driven transaction-manager="myTxManager" />
in the application-context file.
The #Transactional annotation over a method was not taken into account.
Hope the answer will help someone

your list is lazy loading, so the list wasn't loaded.
call to get on the list is not enough.
use in Hibernate.initialize in order to init the list.
If dosnt work run on the list element and call Hibernate.initialize for each .
this need to be before you return from the transaction scope.
look at this post.
search for -
Node n = // .. get the node
Hibernate.initialize(n); // initializes 'parent' similar to getParent.
Hibernate.initialize(n.getChildren()); // pass the lazy collection into the session

The problem is caused because the code is accessing a lazy JPA relation when the "connection" to the database is closed (persistence context is the correct name in terms of Hibernate/JPA).
A simple way of solving it in Spring Boot is by defining a service layer and using the #Transactional annotation. This annotation in a method creates a transaction that propagates into the repository layer and keeps open the persistence context until the method finish. If you access the collection inside the transactional method Hibernate/JPA will fetch the data from the database.
In your case, you just need to annotate with #Transactional the method findTopicByID(id) in your TopicService and force the fetch of the collection in that method (for instance, by asking its size):
#Transactional(readOnly = true)
public Topic findTopicById(Long id) {
Topic topic = TopicRepository.findById(id).orElse(null);
topic.getComments().size();
return topic;
}

it was the problem i recently faced which i solved with using
<f:attribute name="collectionType" value="java.util.ArrayList" />
more detailed decription here and this saved my day.

By using the hibernate #Transactional annotation, if you get an object from the database with lazy fetched attributes, you can simply get these by fetching these attributes like this :
#Transactional
public void checkTicketSalePresence(UUID ticketUuid, UUID saleUuid) {
Optional<Ticket> savedTicketOpt = ticketRepository.findById(ticketUuid);
savedTicketOpt.ifPresent(ticket -> {
Optional<Sale> saleOpt = ticket.getSales().stream().filter(sale -> sale.getUuid() == saleUuid).findFirst();
assertThat(saleOpt).isPresent();
});
}
Here, in an Hibernate proxy-managed transaction, the fact of calling ticket.getSales() do another query to fetch sales because you explicitly asked it.

This is an old question but the below information may help people looking for an answer to this.
#VladMihalcea 's answer is useful. You must not rely on FetchType.EAGER , instead you should load the comments into the Topic entity when required.
If you are not explicitly defining your queries so that you could specify a join fetch, then using #NamedEntityGraph and #EntityGraph you could override the FetchType.LAZY (#OneToMany associations use LAZY by default) at runtime and load the comments at the same time as the Topic only when required. Which means that you restrict loading the comments to only those methods (queries) which really require that. An entity graph as JPA defines it:
An entity graph can be used with the find method or as a query hint to
override or augment FetchType semantics.
You could use it based on the JPA example here. Alternatively, if you use Spring Data JPA, then you could use it based on the example provided by Spring.

To get rid of lazy initialization exception you should not call for lazy collection when you operate with detached object.
From my opinion, best approach is to use DTO, and not entity. In this case you can explicitly set fields which you want to use. As usual it's enough. No need to worry that something like jackson ObjectMapper, or hashCode generated by Lombok will call your methods implicitly.
For some specific cases you can use #EntityGrpaph annotation, which allow you to make eager load even if you have fetchType=lazy in your entity.

For those working with Criteria, I found that
criteria.setFetchMode("lazily_fetched_member", FetchMode.EAGER);
did everything I needed had done.
Initial fetch mode for collections is set to FetchMode.LAZY to provide performance, but when I need the data, I just add that line and enjoy the fully populated objects.

In my case following code was a problem:
entityManager.detach(topicById);
topicById.getComments() // exception thrown
Because it detached from the database and Hibernate no longer retrieved list from the field when it was needed. So I initialize it before detaching:
Hibernate.initialize(topicById.getComments());
entityManager.detach(topicById);
topicById.getComments() // works like a charm

In my case, I had the mapping b/w A and B like
A has
#OneToMany(mappedBy = "a", cascade = CascadeType.ALL)
Set<B> bs;
in the DAO layer, the method needs to be annotated with #Transactional if you haven't annotated the mapping with Fetch Type - Eager

Not the best solution, but for those who are facing LazyInitializationException especially on Serialization this will help. Here you will check lazily initialized properties and setting null to those. For that create the below class
public class RepositoryUtil {
public static final boolean isCollectionInitialized(Collection<?> collection) {
if (collection instanceof PersistentCollection)
return ((PersistentCollection) collection).wasInitialized();
else
return true;
}
}
Inside your Entity class which you are having lazily initialized properties add a method like shown below. Add all your lazily loading properties inside this method.
public void checkLazyIntialzation() {
if (!RepositoryUtil.isCollectionInitialized(yourlazyproperty)) {
yourlazyproperty= null;
}
Call this checkLazyIntialzation() method after on all the places where you are loading data.
YourEntity obj= entityManager.find(YourEntity.class,1L);
obj.checkLazyIntialzation();

The reason is you are trying to get the commentList on your controller after closing the session inside the service.
topicById.getComments();
Above will load the commentList only if your hibernate session is active, which I guess you closed in your service.
So, you have to get the commentList before closing the session.

The collection comments in your model class Topic is lazily loaded, which is the default behaviour if you don't annotate it with fetch = FetchType.EAGER specifically.
It is mostly likely that your findTopicByID service is using a stateless Hibernate session. A stateless session does not have the first level cache, i.e., no persistence context. Later on when you try to iterate comments, Hibernate will throw an exception.
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: mvc3.model.Topic.comments, no session or session was closed
The solution can be:
Annotate comments with fetch = FetchType.EAGER
#OneToMany(fetch = FetchType.EAGER, mappedBy = "topic", cascade = CascadeType.ALL)
private Collection<Comment> comments = new LinkedHashSet<Comment>();
If you still would like comments to be lazily loaded, use Hibernate's stateful sessions, so that you'll be able to fetch comments later on demand.

Hi All posting quite late hope it helps others,
Thanking in advance to #GMK for this post Hibernate.initialize(object)
when Lazy="true"
Set<myObject> set=null;
hibernateSession.open
set=hibernateSession.getMyObjects();
hibernateSession.close();
now if i access 'set' after closing session it throws exception.
My solution :
Set<myObject> set=new HashSet<myObject>();
hibernateSession.open
set.addAll(hibernateSession.getMyObjects());
hibernateSession.close();
now i can access 'set' even after closing Hibernate Session.

Related

JPA Lazy loading is not working in Spring boot

I googled a lot and It is really bizarre that Spring Boot (latest version) may not have the lazy loading is not working. Below are pieces of my code:
My resource:
public ResponseEntity<Page<AirWaybill>> searchAirWaybill(CriteraDto criteriaDto, #PageableDefault(size = 10) Pageable pageable{
airWaybillService.searchAirWaybill(criteriaDto, pageable);
return ResponseEntity.ok().body(result);
}
My service:
#Service
#Transactional
public class AirWaybillService {
//Methods
public Page<AirWaybill> searchAirWaybill(AirWaybillCriteriaDto searchCriteria, Pageable pageable){
//Construct the specification
return airWaybillRepository.findAll(spec, pageable);
}
}
My Entity:
#Entity
#Table(name = "TRACKING_AIR_WAYBILL")
#JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="#airWaybillId") //to fix Infinite recursion with LoadedAirWaybill class
public class AirWaybill{
//Some attributes
#NotNull
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "FK_TRACKING_CORPORATE_BRANCH_ID")
private CorporateBranch corporateBranch;
}
And when debugging, I still getting all lazy loaded attributed loaded. See image below.
One of my questions is could Jackson be involved in such behaviour?
Is there any way that I may have missed to activate the lazy loading?
EDIT
Another question, could the debugger be involved in ruining the lazy loading?
EDIT 2:
For specification build, I have :
public static Specification<AirWaybill> isBranchAirWayBill(long id){
return new Specification<AirWaybill>() {
#Override
public Predicate toPredicate(Root<AirWaybill> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.equal(root.join("corporateBranch",JoinType.LEFT).get("id"),id);
}
};
}
Hibernate Session exists within method with #Transactional.
Passing entity outside Service class is a bad practise because session is being closed after leaving your search method. On the other hand your entity contains lazy initialised collections, which cannot be pulled once session is closed.
The good practise is to map entity onto transport object and return those transport objects from service (not raw entities).
SpringBoot by default has enabled:
spring.jpa.open-in-view = true
That means transaction is always open. Try to disable it.
more information here
Most likely you are debugging while still being inside the service, thus while the transaction is still active and lazy loading can be triggered (any method called on a lazy element triggered the fetch from the database).
The problem is that lazy loading cannot occur while being outside of the transaction. And Jackson is parsing your entity definitely outside the boundaries of one.
You either should fetch all the required dependencies when building your specification or try with the #Transactional on the resource level (but try that as of last resort).
Just so that you know, LAZY fetching strategy is only a hint.. not a mandatory action. Eager is mandatory:
The LAZY strategy is a hint to the persistence provider runtime that
data should be fetched lazily when it is first accessed. The
implementation is permitted to eagerly fetch data for which the LAZY
strategy hint has been specified.
When using a debugger, you are trying to access the value of your variables. So, at the moment you click that little arrow on your screen, the value of the variable in question is (lazily) loaded.
I suppose you are using Hibernate as JPA.
From specification:
The EAGER strategy is a requirement on the persistence provider runtime that data must be eagerly fetched. The LAZY strategy is a hint to the persistence provider runtime that data should be fetched lazily when it is first accessed. The implementation is permitted to eagerly fetch data for which the LAZY strategy hint has been specified. https://docs.jboss.org/hibernate/jpa/2.2/api/javax/persistence/FetchType.html
Hibernate ignores fetch type specially in OneToOne and ManyToOne relationships from non owning side.
There are few options how to force Hibernate use fetch type LAZY if you really need it.
The simplest one is to fake one-to-many relationship. This will work because lazy loading of collection is much easier then lazy loading of single nullable property but generally this solution is very inconvenient if you use complex JPQL/HQL queries.
The other one is to use build time bytecode instrumentation. For more details please read Hibernate documentation: 19.1.7. Using lazy property fetching. Remember that in this case you have to add #LazyToOne(LazyToOneOption.NO_PROXY) annotation to one-to-one relationship to make it lazy. Setting fetch to LAZY is not enough.
The last solution is to use runtime bytecode instrumentation but it will work only for those who use Hibernate as JPA provider in full-blown JEE environment (in such case setting "hibernate.ejb.use_class_enhancer" to true should do the trick: Entity Manager Configuration) or use Hibernate with Spring configured to do runtime weaving (this might be hard to achieve on some older application servers). In this case #LazyToOne(LazyToOneOption.NO_PROXY) annotation is also required.
For more informations look at this:
http://justonjava.blogspot.com/2010/09/lazy-one-to-one-and-one-to-many.html
Just a guess: you are forcing a fetch while building your specification.
I expect something like
static Specification<AirWaybill> buildSpec() {
return (root, query, criteriaBuilder) -> {
Join<AirWaybill, CorporateBranch> br = (Join) root.fetch("corporateBranch");
return criteriaBuilder.equal(br.get("addressType"), 1);
};
}
If this is the case, try changing root.fetch to root.join
The retrieved data already lazy but you are using debug mode its return value when click to watch a data from a debugger.
You can solve this problem with wit 2 steps with jackson-datatype-hibernate:
kotlin example
Add In build.gradle.kts:
implementation("com.fasterxml.jackson.datatype:jackson-datatype-hibernate5:$jacksonHibernate")
Create #Bean
#Bean
fun hibernate5Module(): Module = Hibernate5Module()
Notice that Module is com.fasterxml.jackson.databind.Module, not java.util.Module
Another consideration is while using Lombok, #Data/#Getter annotation causes to load lazy items without need. So be careful when using Lombok.
This was my case.
I think I might have a solution. You can give this a try. This worked for me after 4 hours of hit and trial -
User Entity :
class User {
#Id
String id;
#JsonManagedReference
#OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private List<Address> addressDetailVOList = new ArrayList<Address>();
}
Address entity :
class Address {
#JsonBackReference
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "userId")
private User user;
}
Your parent class will use #JsonManagedReference, and child class will use #JsonBackReference. With this, you can avoid the infinite loop of entity objects as response and stack overflow error.
I also faced the same issue with Spring data JPA. I added the below annotation & able to get the customer records for a given ORDER ID
Customer to Order : one to Many
Order to customer is lazy load.
Order.java
#ManyToOne(cascade = CascadeType.ALL,targetEntity = CustomerEntity.class,fetch = FetchType.LAZY)
#Fetch(FetchMode. JOIN)
#JoinColumn(name = "CUSTOMER_ID",referencedColumnName = "CUSTOMER_ID",insertable = false,updatable = false)
#LazyToOne(LazyToOneOption.PROXY)
Private CustomerEntity customer
Customer.java
#Entity
#TabLe(name = "CUSTOMER" ,
uniqueConstraints = #UniqueConstraint(columnNames= {"mobile"}))
public class CustomerEntity {
#GeneratedVaLue(strategy = GenerationType.IDENTITY)
#CoLumn(name = "customer_id" )
private Integer customerld;
private String name;
private String address;
private String city;
private String state;
private Integer zipCode;
private Integer mobileNumber;
#OneToMany(mappedBy = " customer" )
#Fetch(FetchMode.JOIN)
#LazyToOne(LazyToOneOption.PROXY)
private List<OrderEntity> orders;
}

LazyInitializationException : Why can't Hibernate create a session on lazy loading?

My project use to have a lot of #Transactional method everywhere. Now because of business logic I do not want to rollback when I have an issue, but want to set my object to an error status (aka saved in the db, so definitly not rollback), so I removed a few #Transactional to start.
Now the issue is where there is a lazy loading there is no session, thus spawning a LazyInitializationException.
Now here are my following trouble-shooting and solution seeking so far :
We're using annotation configuration, so no xml configuration here.
For each action using the database, an EntityManager (defined as an attribute and #Autowired in the service) is created and then deleted (I can clearly see it in the logs when adding the configuration to see them), which apparently is normal according to the Spring documentation.
Using #PersistenceContext or #PersistenceUnit, either with a EntityManagerFactory or with EntityManager doesn't work.
I can load the lazy-loaded attribute I want to use with Hibernate.initialize(), and it then doesn't spawn a LazyInitializationException.
Now my question is : Why can't hibernate do it by itself ? It's seems trivial to me that if I'm using a lazy loading, I want Hibernate to create a session (which he seems perfectly able to do when doing Hibernate.initialize()) to load the date automatically.
Would there be a way to spawn a new entity manager to be use inside my method so Hibernate doesn't create and recreate one all the time ? I really feel like I'm missing something basic about Hibernate, lazy loading and sessions that makes this whole mess a lot less complicated.
Here is an example :
#Entity
#Table(name = "tata")
public class Tata {
#Id
#Column(name = "tata_id")
private Long id;
// getter / setter etc
}
#Entity
#Table(name = "toto")
public class Toto {
#Id
#Column(name = "toto_id")
private Long id;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "tata_id")
private Tata tata;
// getter / setter etc
}
#Service("totoManager")
public class TotoManager extends GenericManagerImpl {
#Autowired
private EntityManager entityManager;
#Autowired
private TotoRepository totoRepository;
public void doSomethingWithTotos() throws XDExceptionImpl {
List<Toto> totos = this.totoRepository.findAll();
for (toto toto : totos) {
// LazyInitializationException here
LOGGER.info("tata : " + toto.getTata().getId());
}
}
}
Hibernate can do it by itself. With setting property hibernate.enable_lazy_load_no_trans=true (for spring boot it should be spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true) you can load any lazy property when transaction is closed. This approach has huge drawback: each time you load lazy property, hibernate opens session and creates transaction in background.
I would recommed fetch lazy properties by entityGraphs. So you doesnt have to move persistent context do upper level or change fetch type in your entities.
Try to read something about Open session in view to understand why Lazy loading does not work out of session/transaction. If you want you can set property spring.jpa.open-in-view=true and it will load your lazy loaded data.

How to solve the “failed to lazily initialize a collection of role” Hibernate exception

I have this problem:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: mvc3.model.Topic.comments, no session or session was closed
Here is the model:
#Entity
#Table(name = "T_TOPIC")
public class Topic {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
#ManyToOne
#JoinColumn(name="USER_ID")
private User author;
#Enumerated(EnumType.STRING)
private Tag topicTag;
private String name;
private String text;
#OneToMany(mappedBy = "topic", cascade = CascadeType.ALL)
private Collection<Comment> comments = new LinkedHashSet<Comment>();
...
public Collection<Comment> getComments() {
return comments;
}
}
The controller, which calls model looks like the following:
#Controller
#RequestMapping(value = "/topic")
public class TopicController {
#Autowired
private TopicService service;
private static final Logger logger = LoggerFactory.getLogger(TopicController.class);
#RequestMapping(value = "/details/{topicId}", method = RequestMethod.GET)
public ModelAndView details(#PathVariable(value="topicId") int id)
{
Topic topicById = service.findTopicByID(id);
Collection<Comment> commentList = topicById.getComments();
Hashtable modelData = new Hashtable();
modelData.put("topic", topicById);
modelData.put("commentList", commentList);
return new ModelAndView("/topic/details", modelData);
}
}
The jsp-page looks li the following:
<%#page import="com.epam.mvc3.helpers.Utils"%>
<%# page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%# page session="false" %>
<html>
<head>
<title>View Topic</title>
</head>
<body>
<ul>
<c:forEach items="${commentList}" var="item">
<jsp:useBean id="item" type="mvc3.model.Comment"/>
<li>${item.getText()}</li>
</c:forEach>
</ul>
</body>
</html>
Exception is rised, when viewing jsp. In the line with c:forEach loop
If you know that you'll want to see all Comments every time you retrieve a Topic then change your field mapping for comments to:
#OneToMany(fetch = FetchType.EAGER, mappedBy = "topic", cascade = CascadeType.ALL)
private Collection<Comment> comments = new LinkedHashSet<Comment>();
Collections are lazy-loaded by default, take a look at this if you want to know more.
From my experience, I have the following methods to solved the famous LazyInitializationException:
(1) Use Hibernate.initialize
Hibernate.initialize(topics.getComments());
(2) Use JOIN FETCH
You can use the JOIN FETCH syntax in your JPQL to explicitly fetch the child collection out. This is some how like EAGER fetching.
(3) Use OpenSessionInViewFilter
LazyInitializationException often occur in view layer. If you use Spring framework, you can use OpenSessionInViewFilter. However, I do not suggest you to do so. It may leads to performance issue if not use correctly.
I know it's an old question but I want to help.
You can put the transactional annotation on the service method you need, in this case findTopicByID(id) should have
#Transactional(propagation=Propagation.REQUIRED, readOnly=true, noRollbackFor=Exception.class)
more info about this annotation can be found here
About the other solutions:
fetch = FetchType.EAGER
is not a good practice, it should be used ONLY if necessary.
Hibernate.initialize(topics.getComments());
The hibernate initializer binds your classes to the hibernate technology. If you are aiming to be flexible is not a good way to go.
Hope it helps
The origin of your problem:
By default hibernate lazily loads the collections (relationships) which means whenver you use the collection in your code(here comments field
in Topic class)
the hibernate gets that from database, now the problem is that you are getting the collection in your controller (where the
JPA session is closed).This is the line of code that causes the exception
(where you are loading the comments collection):
Collection<Comment> commentList = topicById.getComments();
You are getting "comments" collection (topic.getComments()) in your controller(where JPA session has ended) and that causes the exception. Also if you had got
the comments collection in your jsp file like this(instead of getting it in your controller):
<c:forEach items="topic.comments" var="item">
//some code
</c:forEach>
You would still have the same exception for the same reason.
Solving the problem:
Because you just can have only two collections with the FetchType.Eager(eagerly fetched collection) in an Entity class and because lazy loading is more
efficient than eagerly loading, I think this way of solving your problem is better than just changing the FetchType to eager:
If you want to have collection lazy initialized, and also make this work,
it is better to add this snippet of code to your web.xml :
<filter>
<filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
What this code does is that it will increase the length of your JPA session or as the documentation says, it is used "to allow for lazy loading in web views despite the original transactions already being completed." so
this way the JPA session will be open a bit longer and because of that
you can lazily load collections in your jsp files and controller classes.
#Controller
#RequestMapping(value = "/topic")
#Transactional
i solve this problem by adding #Transactional,i think this can make session open
The best way to handle the LazyInitializationException is to join fetch upon query time, like this:
select t
from Topic t
left join fetch t.comments
You should ALWAYS avoid the following anti-patterns:
FetchType.EAGER
OSIV (Open Session in View)
hibernate.enable_lazy_load_no_trans Hibernate configuration property
Therefore, make sure that your FetchType.LAZY associations are initialized at query time or within the original #Transactional scope using Hibernate.initialize for secondary collections.
The problem is caused by accessing an attribute with the hibernate session closed. You have not a hibernate transaction in the controller.
Possible solutions:
Do all this logic, in the service layer, (with the #Transactional), not in the controller. There should be the right place to do this, it is part of the logic of the app, not in the controller (in this case, an interface to load the model). All the operations in the service layer should be transactional.
i.e.: Move this line to the TopicService.findTopicByID method:
Collection commentList = topicById.getComments();
Use 'eager' instead of 'lazy'. Now you are not using 'lazy' .. it is not a real solution, if you want to use lazy, works like a temporary (very temporary) workaround.
use #Transactional in the Controller. It should not be used here, you are mixing service layer with presentation, it is not a good design.
use OpenSessionInViewFilter, many disadvantages reported, possible instability.
In general, the best solution is the 1.
The reason is that when you use lazy load, the session is closed.
There are two solutions.
Don't use lazy load.
Set lazy=false in XML or Set #OneToMany(fetch = FetchType.EAGER) In annotation.
Use lazy load.
Set lazy=true in XML or Set #OneToMany(fetch = FetchType.LAZY) In annotation.
and add OpenSessionInViewFilter filter in your web.xml
Detail See my POST.
In order to lazy load a collection there must be an active session. In a web app there are two ways to do this. You can use the Open Session In View pattern, where you use an interceptor to open the session at the beginning of the request and close it at the end. The risk there is that you have to have solid exception handling or you could bind up all your sessions and your app could hang.
The other way to handle this is to collect all the data you need in your controller, close your session, and then stuff the data into your model. I personally prefer this approach, as it seems a little closer to the spirit of the MVC pattern. Also if you get an error from the database this way you can handle it a lot better than if it happens in your view renderer. Your friend in this scenario is Hibernate.initialize(myTopic.getComments()). You will also have to reattach the object to the session, since you're creating a new transaction with every request. Use session.lock(myTopic,LockMode.NONE) for that.
One of the best solutions is to add the following in your application.properties file:
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
If you are trying to have a relation between a entity and a Collection or a List of java objects (for example Long type), it would like something like this:
#ElementCollection(fetch = FetchType.EAGER)
public List<Long> ids;
Two things you should have for fetch = FetchType.LAZY.
#Transactional
and
Hibernate.initialize(topicById.getComments());
There are multiple solution for this Lazy Initialisation issue -
1) Change the association Fetch type from LAZY to EAGER but this is not a good practice because this will degrade the performance.
2) Use FetchType.LAZY on associated Object and also use Transactional annotation in your service layer method so that session will remain open and when you will call topicById.getComments(), child object(comments) will get loaded.
3) Also, please try to use DTO object instead of entity in controller layer. In your case, session is closed at controller layer. SO better to convert entity to DTO in service layer.
I got this error after a second execution of a method to generate a JWT token.
The line user.getUsersRole().stream().forEachOrdered((ur) -> roles.add(ur.getRoleId())); generated the error.
// MyUserDetails.java
#Service
public class MyUserDetails implements UserDetailsService {
#Override
public UserDetails loadUserByUsername(String email) {
/* ERROR
/* org.hibernate.LazyInitializationException: failed to
/* lazily initialize a collection of role:
/* com.organizator.backend.model.User.usersRole,
/* could not initialize proxy - no Session */
user.getUsersRole().stream().forEachOrdered((ur) ->
roles.add(ur.getRoleId()));
In my case the #Transactional annotation solved it,
// MyUserDetails.java
import org.springframework.transaction.annotation.Transactional;
#Service
public class MyUserDetails implements UserDetailsService {
#Override
#Transactional // <-- added
public UserDetails loadUserByUsername(String email) {
/* No Error */
user.getUsersRole().stream().forEachOrdered((ur) ->
roles.add(ur.getRoleId()));
#Transactional annotation on controller is missing
#Controller
#RequestMapping("/")
#Transactional
public class UserController {
}
I found out that declaring #PersistenceContext as EXTENDED also solves this problem:
#PersistenceContext(type = PersistenceContextType.EXTENDED)
To solve the problem in my case it was just missing this line
<tx:annotation-driven transaction-manager="myTxManager" />
in the application-context file.
The #Transactional annotation over a method was not taken into account.
Hope the answer will help someone
your list is lazy loading, so the list wasn't loaded.
call to get on the list is not enough.
use in Hibernate.initialize in order to init the list.
If dosnt work run on the list element and call Hibernate.initialize for each .
this need to be before you return from the transaction scope.
look at this post.
search for -
Node n = // .. get the node
Hibernate.initialize(n); // initializes 'parent' similar to getParent.
Hibernate.initialize(n.getChildren()); // pass the lazy collection into the session
The problem is caused because the code is accessing a lazy JPA relation when the "connection" to the database is closed (persistence context is the correct name in terms of Hibernate/JPA).
A simple way of solving it in Spring Boot is by defining a service layer and using the #Transactional annotation. This annotation in a method creates a transaction that propagates into the repository layer and keeps open the persistence context until the method finish. If you access the collection inside the transactional method Hibernate/JPA will fetch the data from the database.
In your case, you just need to annotate with #Transactional the method findTopicByID(id) in your TopicService and force the fetch of the collection in that method (for instance, by asking its size):
#Transactional(readOnly = true)
public Topic findTopicById(Long id) {
Topic topic = TopicRepository.findById(id).orElse(null);
topic.getComments().size();
return topic;
}
it was the problem i recently faced which i solved with using
<f:attribute name="collectionType" value="java.util.ArrayList" />
more detailed decription here and this saved my day.
By using the hibernate #Transactional annotation, if you get an object from the database with lazy fetched attributes, you can simply get these by fetching these attributes like this :
#Transactional
public void checkTicketSalePresence(UUID ticketUuid, UUID saleUuid) {
Optional<Ticket> savedTicketOpt = ticketRepository.findById(ticketUuid);
savedTicketOpt.ifPresent(ticket -> {
Optional<Sale> saleOpt = ticket.getSales().stream().filter(sale -> sale.getUuid() == saleUuid).findFirst();
assertThat(saleOpt).isPresent();
});
}
Here, in an Hibernate proxy-managed transaction, the fact of calling ticket.getSales() do another query to fetch sales because you explicitly asked it.
This is an old question but the below information may help people looking for an answer to this.
#VladMihalcea 's answer is useful. You must not rely on FetchType.EAGER , instead you should load the comments into the Topic entity when required.
If you are not explicitly defining your queries so that you could specify a join fetch, then using #NamedEntityGraph and #EntityGraph you could override the FetchType.LAZY (#OneToMany associations use LAZY by default) at runtime and load the comments at the same time as the Topic only when required. Which means that you restrict loading the comments to only those methods (queries) which really require that. An entity graph as JPA defines it:
An entity graph can be used with the find method or as a query hint to
override or augment FetchType semantics.
You could use it based on the JPA example here. Alternatively, if you use Spring Data JPA, then you could use it based on the example provided by Spring.
To get rid of lazy initialization exception you should not call for lazy collection when you operate with detached object.
From my opinion, best approach is to use DTO, and not entity. In this case you can explicitly set fields which you want to use. As usual it's enough. No need to worry that something like jackson ObjectMapper, or hashCode generated by Lombok will call your methods implicitly.
For some specific cases you can use #EntityGrpaph annotation, which allow you to make eager load even if you have fetchType=lazy in your entity.
For those working with Criteria, I found that
criteria.setFetchMode("lazily_fetched_member", FetchMode.EAGER);
did everything I needed had done.
Initial fetch mode for collections is set to FetchMode.LAZY to provide performance, but when I need the data, I just add that line and enjoy the fully populated objects.
In my case following code was a problem:
entityManager.detach(topicById);
topicById.getComments() // exception thrown
Because it detached from the database and Hibernate no longer retrieved list from the field when it was needed. So I initialize it before detaching:
Hibernate.initialize(topicById.getComments());
entityManager.detach(topicById);
topicById.getComments() // works like a charm
In my case, I had the mapping b/w A and B like
A has
#OneToMany(mappedBy = "a", cascade = CascadeType.ALL)
Set<B> bs;
in the DAO layer, the method needs to be annotated with #Transactional if you haven't annotated the mapping with Fetch Type - Eager
Not the best solution, but for those who are facing LazyInitializationException especially on Serialization this will help. Here you will check lazily initialized properties and setting null to those. For that create the below class
public class RepositoryUtil {
public static final boolean isCollectionInitialized(Collection<?> collection) {
if (collection instanceof PersistentCollection)
return ((PersistentCollection) collection).wasInitialized();
else
return true;
}
}
Inside your Entity class which you are having lazily initialized properties add a method like shown below. Add all your lazily loading properties inside this method.
public void checkLazyIntialzation() {
if (!RepositoryUtil.isCollectionInitialized(yourlazyproperty)) {
yourlazyproperty= null;
}
Call this checkLazyIntialzation() method after on all the places where you are loading data.
YourEntity obj= entityManager.find(YourEntity.class,1L);
obj.checkLazyIntialzation();
The reason is you are trying to get the commentList on your controller after closing the session inside the service.
topicById.getComments();
Above will load the commentList only if your hibernate session is active, which I guess you closed in your service.
So, you have to get the commentList before closing the session.
The collection comments in your model class Topic is lazily loaded, which is the default behaviour if you don't annotate it with fetch = FetchType.EAGER specifically.
It is mostly likely that your findTopicByID service is using a stateless Hibernate session. A stateless session does not have the first level cache, i.e., no persistence context. Later on when you try to iterate comments, Hibernate will throw an exception.
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: mvc3.model.Topic.comments, no session or session was closed
The solution can be:
Annotate comments with fetch = FetchType.EAGER
#OneToMany(fetch = FetchType.EAGER, mappedBy = "topic", cascade = CascadeType.ALL)
private Collection<Comment> comments = new LinkedHashSet<Comment>();
If you still would like comments to be lazily loaded, use Hibernate's stateful sessions, so that you'll be able to fetch comments later on demand.
Hi All posting quite late hope it helps others,
Thanking in advance to #GMK for this post Hibernate.initialize(object)
when Lazy="true"
Set<myObject> set=null;
hibernateSession.open
set=hibernateSession.getMyObjects();
hibernateSession.close();
now if i access 'set' after closing session it throws exception.
My solution :
Set<myObject> set=new HashSet<myObject>();
hibernateSession.open
set.addAll(hibernateSession.getMyObjects());
hibernateSession.close();
now i can access 'set' even after closing Hibernate Session.

LazyInitializationException in #RequestScoped Bean after explicit EntityManager.find

we are currently migrating from JavaEE5 to JavaEE6 and are using JBoss 6.0.0 and JSF2. For simplicity this example is constructed and based on the Maven archetype: org.jboss.weld.archetypes:jboss-javaee6-webapp:1.0.1.CR2
I have added a simple LAZY relationship to User:
#NotNull #ManyToMany(fetch=FetchType.LAZY)
private List<Address> addresses;
This bean is part of the maven archetype, and I added a few lines to retrieveAllMembersOrderedByName().
#RequestScoped
public class MemberListProducer {
#Inject private Logger log;
#Inject #MemberRepository
private EntityManager em;
private List<Member> members;
#Produces #Named
public List<Member> getMembers(){return members;}
#PostConstruct
public void retrieveAllMembersOrderedByName()
{
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Member> criteria = cb.createQuery(Member.class);
Root<Member> member = criteria.from(Member.class);
criteria.select(member).orderBy(cb.asc(member.get("name")));
members = em.createQuery(criteria).getResultList();
Member m1 = members.get(0);
log.info("Id: "+m1.getId());
Member m2 = em.find(Member.class, m1.getId());
log.info("Addr m1: "+m1.getAddresses().size()); // OK
log.info("Addr m2: "+m2.getAddresses().size()); // Error
}}
As you see, the List<Member>is retrieved by a CriteriaQuery, then the Member m1 is taken from the List and Member m2 is explicitly loaded from the same EntityManager em. Now the interesting part: m1.getAddresses().size() works, m2.getAddresses().size() gives a
15:41:32,910 ERROR [org.hibernate.LazyInitializationException]
failed to lazily initialize a collection of role: test.Member.addresses,
no session or session was closed: org.hibernate.LazyInitializationException:
failed to lazily initialize a collection of role:test.Member.addresses,
no session or session was closed
Can anybody explain this, or knows how to solve this issue? Thank you, Thor
This is normal behavior for lazy loading all your lazy classes are proxy. and when you fetching the class from proxy your Hibernate session is already closed.
The solution is to implement Open Session in View Filter which will keep your Hibernate session open until your Request is alive.
You can read more about it in this article
http://community.jboss.org/wiki/OpenSessionInView
If you are using Spring Framework then you already have this job done OpenSessionInViewFilter class.
Hope it helps.
Thor, can you please double check? I thought this was interesting and tried it myself, however I'm getting the exception in both calls. Neither of them work. I could be doing something wrong but I've checked a couple of times and both methods give me that exception. Do you get the logger to log the size of the first collection?
You can fetch related objects dynamically through code given below which has default lazy initialization :
criteria.setFetchMode("addresses", FetchMode.JOIN);

Passing complex JPA Entities to the controller with POJO

My team is coding an application that involves editing wikipedia-like pages.
It is similar to the problem we have with registration:
A straightforward implementation gives something like
public static void doRegistration(User user) {
//...
}
The user parameter is a JPA Entity. The User model looks something like this:
#Entity
public class User extends Model {
//some other irrelevant fields
#OneToMany(cascade = CascadeType.ALL)
public Collection<Query> queries;
#OneToMany(cascade = CascadeType.ALL)
public Collection<Activity> activities;
//...
I have read here and there that this fails. Now, in Play!, what is the best course of action we can take? There must be some way to put all that data that has to go to the server in one object, that easily can be saved into the database.
EDIT: The reason this fails is because of the validation fail. It somehow says "incorrect value" when validating collection objects. I was wondering if this can be avoided.
SOLUTION: Changing the Collection to List has resolved the issue. This is a bug that will be fixed in play 1.2 :)
Thanks beforehand
this works. To be more clear, you can define a controller method like the one you wrote:
public static void doRegistration(User user) {
//...
}
That's completely fine. Just map it to a POST route and use a #{form} to submit the object, like:
#{form id:'myId', action:#Application.doRegistration()}
#{field user.id}
[...]
#{/form}
This works. You may have problems if you don't add all the field of the entity in the form (if some fields are not editable, either use hidden inputs or a NoBinding annotation as described here).
EDIT: on the OneToMany subject, the relation will be managed by the "Many" side. That side has to keep the id of the related entity as a hidden field (with a value of object.user.id). This will solve all related issues.
It doesn't fail. If you have a running transaction, the whole thing will be persisted. Just note that transactions are usually running within services, not controllers, so you should pass it from the controller to the service.

Categories