Spring Boot + Hibernate - lazy initialization error on two levels of child hibernate objects - spring

I feel like this issue has been discussed before, but I can't find a solid answer. I'm getting a LazyInitializationException...no Session when attempting to go two levels deep in accessing lazily-loaded hibernate objects. I'm doing this through Spring Boot.
Suppose I have three Hibernate objects, Table1, Table2 & Table3. Table1 has a one-to-many foreign-key reference to Table2 & Table2 has a one-to-many foreign-key reference to Table3. Each foreign-key reference is LAZY loaded (I think this issue occurs with one-to-one relationships as well, but not 100% sure)
Table1 has the following code:
#OneToMany(mappedBy = "table1", fetch = FetchType.LAZY)
private Set<Table2> table2s;
//and corresponding getter method
public Set<Table2> getTable2s(){
return table2s
}
And the same pattern in the Table2 class for referencing Table3.
I would expect that I can write the following code:
Table1 table1 = tableOneRepository.getOne(...);
Set<Table2> table2s = table1.getTable2s()
singleTable2 = table2s.iterator().next() // just get any one element, assume set in not empty
Set<Table3> table3s = singleTable2.getTable3s() // "no session" error
However, the final line always produces this error:
Caused by: org.hibernate.LazyInitializationException: could not initialize proxy [com...] - no Session
Note this issue never occurs when doing the first lazy load, it's always when doing a lazy load from an object that was itself lazy loaded
I've seen lots of suggestions about adding #Transactional to methods, but it hasn't worked. Help please?

Well we need more informations. First the declaration of the entities. Somehting might be missing. Then more code. Here we don't even have the declaration of the function
Even if it might not be the real cause, check you have imported the spring transactional annotation and not the javax annotation
Edit : as far as I remember I've also worked with "nested" objects like this.
Not sure, but might work : try to do this after you retrieved the singleTable2. I don't remember you have to do this when you access an object, but try it anyway
Hibernate.initialize(singleTable2)

Related

Spring data update just one entity field

i’m new to spring when i try to update just one field of an entity I noticed in logs that hibernate perform two queries, before update it does a SELECT of all fields. Is that ok? Why does Hibernate perform that SELECT? How can i update a field with just one UPDATE query? Additionally when I tried to update a single title in an entity that has another nested entity i end up with a bunch of SELECT. I think it’s not good for performance or I’m wrong?
Something s = somethingRepository.findById(id);
s.setField1(someData);
somethingRepository.save(s);
On the internet I found a solution to make custom query with #Modifying and #Query(“UPDATE …”) but in this way I need to make custom query for every single field. Is there a better solution?
As per the source code you have pasted in the question
Something s = somethingRepository.findById(id);
s.setField1(someData);
somethingRepository.save(s);
if the entity Something which you are asking does not exist in the hibernate first level cache, it will make one SELECT call.
and as you are updating field 1 value then it will make another update call.
It does not matter if you are using save or not because Hibernate dirty checks will ensure that all changes are updated.
otherwise you can use custom method with #Modifying with JPQL and named params. It is more readable than ?1,
#Modifying
#Query("UPDATE Something s SET s.field = :fieldValue WHERE s.id = :id")
void updateField(String fieldValue, UUID id);
Regarding that you are seeing multiple calls "when I tried to update a single title in an entity that has another nested entity". It depends on how you have created the relationship among entities. If you can share the entities and their relationship then only it can be answered accurately.
Because internally the repository.save() method does an upsert. If you go to the inner classes and check you will see that first, it will check whether the entity is present in the database then based on that it will perform add or update. If you don't want the SELECT query to run then you can use the native query offered by the JPA repository. You can do something like this:
#Modifying
#Transactional
#Query("UPDATE <tableName> SET <columnName> = ?1 WHERE <condition>" ,nativeQuery=true)
void updateSomething(String value);

Spring JpaRepository Perform delete only if given Id exists and avoid race condition

my situtation is as follows:
I have #Entity class Ingredient in my Spring JPA Project.
I would like to implement a method performing delete operation on DB record by record Id
public boolean deleteIngredient(String id) and if possible avoid handling exceptions for non-existent Ids.
Unfortunately the only recommendations I can find in this area are based on the fact of querying by Id before deleting record e.g.
ingredientRepository.findById(id).ifPresent(x -> ingredientRepository.deleteById(id));
or
if(ingredientRepository.existsById(id)){
ingredientRepository.deleteById(id);
}
which I believe are prone to race conditions (other thread may delete record after this one queries for existence.
Is the best approach really just wrapping it in a try-catch block and handling EmptyResultDataAccessException in case record with given Id does not exist?
If you are using JPA, you need the entity to be marked for deletion in the persistence context (e.g. not in the Database). Keep in mind JPA Repository follows the ORM paradigm and is not acting on the record directly.
Any race conditions will be handled on the persistence context level.
If you use #Transactional and you will be safe.
Also if you don't want the explicit error thrown by deleteById, when the ID is not known to the EntityManager, consider using delete (which will just return with no exception being thrown in case the ID is unknown).

How to create a dyncamic update query with JPQL?

I have to update an entity by ensuring it's already there in the database(Primary key is not auto generated).Therefor I cannot use only thesave() method to overcome this issue.There must be a way to ensure that the inserted primary key is already existing.To overcome this issue I know I can follow several approaches like below.But I found creating my own update statement is the most optimal way to solve this problem.
So I need to create a dynamic update query with JPQL . I know you will say why don't you use a method like getOne() or findOne() and set the necessary fields for the entity and save() .But I think using a findOne() or getOne() leads to an additional db hit to fetch the relevant entities .So I can omit the fetch by going with a custom update query.
I guess using #DynamicUpdate also won't resolve the problem ,because as far as I know it's also fetch the entity from the database to compare the changed fields during an updation.
So both of the above mentioned approaches leads to an additional db hit.
So is there a way to write a custom jpql query to update only the fields which are not null.
I have achieved similar kind of behaviour with fetching by writing dynamic where clauses.But didn't find a way to do the same with update.
Ex for dynamic select with JPQL:
SELECT d FROM TAndC d WHERE (:termStatus is null or d.termStatus= :termStatus ) AND (:termType is null or d.termType=:termType) AND (:termVersion is null or d.termVersion=:termVersion)"
#Modifying
#Query("update entity e set e.obj1=:obj1 and e.obj2=:obj2 where e.id=:id")
public void updateCustom(String obj1, String obj2, String id);
I wrote a pseudo code.
It is possible with spring data.
Also you can use jpa entity manager to create update statement and dynamic query programatically

What would happen if entity model has relations but data (views) in database doesn't have relations and if they are inconsistent?

My question is would Spring JPA throw exceptions for every query?
I mean, let say there are tables without any relation (FK) between them in database. It is bad design but you cannot change it and it is not up to you.
But you know that data itself should be as there are relations.
That's why you create Entity model with all relations like they are there.
But as I said there is no real relations in database.
And in one point data are inconsistent in database.
Would Spring JPA throw exceptions if there are inconsistency or it will just return you inconsistent data?
I assume with "relations" you mean "foreign keys".
JPA doesn't care about foreign keys.
All it cares about is if the data matches the mapping information on the entities.
So if you have an entity A that references an entity B with id b but such a B does not exist you might eventually get an exception.
Or you might just get an A with a null reference to B.
If the reference is marked as mandatory you might actually not be able to load the A in the first place, because a join is used and therefore not returning any data at all.
Side note: All this depends more on the JPA implementation you are using than on Spring Data JPA.

preventing OpenJPA N+1 select performance problem on maps

When I have an entity that contains a Map, e.g.
#Entity
public class TestEntity {
#ElementCollection(fetch = FetchType.EAGER)
Map<String, String> strings = new HashMap<String, String>();
}
and I select multiple entities (SELECT z FROM TestEntity z), OpenJPA 2.0 performs one query for each TestEntity to fetch the map, even though I used FetchType.EAGER. This also happens when the Map value is an entity and I use #OneToMany instead of #ElementCollection. In principle this can be done more efficiently with one query that selects all the map entries for all returned TestEntities. For Collection-valued fields OpenJPA already does this by default (openjpa.jdbc.EagerFetchMode" value="parallel") but it seems to fail on this simple entity. (Same problem with value="join").
Could I be doing something wrong? Is there an easy way to tell OpenJPA to not perform a query per entity but only one?
Or is there already any work planned on improving this (I filed it under https://issues.apache.org/jira/browse/OPENJPA-1920)?
It is a problem for us because we wish to fetch (and detach) a list of about 1900 products which takes almost 15 seconds with OpenJPA. It takes less than a second with my own native query.
Having to write only one native query wouldn't be much of a problem but the map we use is inside a reusable StringI18N entity which is referenced from several different entities (and can be deep in the object graph), so native queries are a maintenance headache.
Any help getting performance up is greatly appreciated.
EDIT: explicitly using JOIN FETCH does not help either:
"SELECT z FROM TestEntity z JOIN FETCH z.strings"
OpenJPA's TRACE still shows that it executes one SQL statement for each individual TestEntity.
It might be a pain (correction: I know it'll be a pain) but have you tried actually mapping your 2-field TestEntity as a full JPA-persisted #Entity?
I know that Hibernate used to treat #ElementCollections rather differently to #OneToManys for example - OpenJPA could well be doing something similar.

Resources