I am learning hibernate and i am using the debugger to understand how hibernate fetches objects. I have enabled lazy loading in my XML and i use create a query to get an object. This object has a Set associated with it.
When i look at the variable values in my debugger it seems to be completely loading the object graph, ie not lazily fetching the set and its properties. I can think of several reasons why this might be the case.
1) something is wrong with my xml / config and i have eager fetching enabled. I'm not sure this is the case, everything is at its defaults which is to lazy fetch.
2) The way the IDE debugger works is that is causes hibernate to trigger the lazy loading when i look at them.
3) Hibernate is fetching the entire object graph from the 2nd level cache. Ive tried to disable this but this seems to have no effect
Any other ideas?
Debugging (showing the lazy fields, to be precise) triggers the lazy loading already. Get the entity, detach it and access your lazy field. Should throw some sort of exception if lazy loading works.
If you really want to know how hibernate does it, have a look at the sources.
#atamanroman's answer is fully correct. I just wanted to add in some details. In order to test lazy loading in a JavaEE environment, I use Arquillian tests. In the test class, use a UserTransaction to control transaction boundaries. After committing the transaction, access the lazy loaded attribute and expect an Exception
#Inject
private UserTransaction tx;
#Test(expected=Exception.class)
public void testLazyLoading() throws Exception {
tx.begin();
MyEntity entity = em.find(entityId);
tx.commit();
entity.getLazyLoadedProperty().someMethod();
}
Please note that in order to trigger the loading of a lazy loaded attribute, it is often not enough to call the getter inside the transaction, you must also perform some operation with the attribute, like calling size() on a list. Otherwise, the getter will simply return a proxy.
Related
I was lately working on optimizing my application performance, and I noticed that when I lazy load a dependency with MazyToOne relationship, object that hibernate provides is not just lazy loads the object itself, but also all of its fields - so, it has made me think if I maybe can use this to my advantage
Let's imagine the situation like this
#Transactional
public void updateUserNameToHarry(Long userId){
User u = dao.findById(userId);
u.setName("Harry");
}
So we have opened a transaction, loaded Harry into our persistence context, and updated his name.
Once the transaction is closed Hibernate will do its magic and update the name of the user entity we have.
But, in this scenario, I don`t really need to parse Harry db row into entity graph, load Harry into application context, and I definitely do not need to do all of this for the eagerly loaded relationships of Harry.
So here is the question - can I avoid this somehow?
Ideally, I would like Harry to be a lazy loaded object that upon calling setName method adds a single update query, that is going to be executed once the transaction commits.
I am currently using Spring boot 2.0 stack, but my question applies to any other versions and approaches to ORM with java.
If I understand correctly, these options came to my mind:
1 - obvious one - don't load User at all, just perform update query yourself (UPDATE user SET name = 'Harry' WHERE id = :userId) - number of ways to achieve this, named query, spring method with annotation etc.
2 - there is a getReference method in EntityManager, it allows you to get User proxy with only it's ID filled, unless you perform some actions on it, then the fields are loaded. It's not gonna help with such as simple case as you posted, but if your User had relations to other entities, then you could benefit from it - have a look at this, it's a perfect explanation
what is meaning of could not initialize proxy - no Session error?? what meaning of lazy object and why occur??, and how to avoid it without change the hibernate laze property and without using Hibernate.initialize() because that doesn't work for me.
There are a couple of things here, first of all you appear to asking "what is lazy loading".
If you have an object to be loaded from the database which has a relationship with another object, lazy loading allows you to only load the required object, and the related object will only be loaded when you need it.
The exception you are having is caused by trying to access the related object after the objects have been disconnected from the database session (obviously a db session is required to load them).
There are a few ways we can deal with the situation, the most appropriate will entirely depend your application.
You can always load all the data you need inside the transaction where the object is first loaded (Hibernate.initialise, or sometimes just calling the getter will work), this will remove your exception: the down side to this is to will find that you are regularly leading a lot of data and could have performance issues
Another way is to pass the Id to where you need to use the object, load a new one from the database and do your work inside the transaction, passing ids a lot is not very OO but sometimes it's the best option.
If for instance you are having this error in UI bindings or other places where you only want to "get", you may want to consider a "session in view" which will provide a db session for your lazy loading.
I can not tell you what is the best option without knowing about your application and it's architecture.
If you wish to discuss a any of this further please let me know.
You should mark your method with annotation #Transactional
#Transactional
void method(){
Entity e = ... (from database);
e.getLazyField();
}
Well, i have class named "Consultation" that have a list of "ItemBudget", and i have a class named "Budget" that have a list of "ItemOrcamento" too. The relation Consultation<-->ItemBudget is ManyToMany, and relation Budget<-->ItemBudget is OneToMany.
In JSF i do the following:
<p:dataTable rowKey="#{item.id}" var="item" value="#{consultationMB.consultation.budget.itensAsList}" selection="#{consultationMB.itemBudget}" >
I use method "getItensAsList" that return a ArrayList() instead of a HashSet() that primefaces dataTable tag can't read correctly
As you can see, my selection is "itemBudget", so in my ManagedBean called ConsultationMBImpl i try to execute the following:
if (!itemBudget.getSituation().getCode().equals("WAITING_CONCLUSION")){
//some code here
}
When i try make the code above all fields that have reference to another class like: Situation, Dentist and others have this: "Dentist_javassist_32", "Situation_javassist_49"...
And all fields are null or zero.
That's caused by Hibernate, which loads a proxy (suffixed with _javassist) instead of the original object. If you debug your code with an IDE and try to call a getter on the fly, you'll get the real value, even it seems to be null for the property.
Why is it that done? Because it's much faster to load proxies rather than real objects for the ORM tool. Hibernate keeps a cache with already loaded objects instead of hitting the DB once and again.
If you want to avoid lazy loading, you could use a get instead of a load method over Hibernate's Session. Also for its relations, you can mark them as lazy="false", so Hibernate will load them as real objects. If you want to directly unproxy an already loaded instance, there are also some methods to achieve that.
However, don't do that unless you strictly require it. As I said before, that will make Hibernate load more information from DB and consequently, loose eficiency.
I was wondering if there was a way to tell Hibernate to generate some kind of console warning when it has too many objects of a certain type in the session cache. I would like to do this for load testing as we have OutOfMemoryException problems on occasion with BLOB loading from Oracle.
We are still using Hibernate 3.6.10 for now. Our best approach for this testing at the moment is to just generate more data than the system would be able to handle in a normal use case and try to load the parent object and see if it crashes. Doing it this way just feels kind of bad.
Any suggestions are welcome.
One note that I forgot to mention is that this "logging" idea is something I would like to be able to leave in production code to pinpoint specific problems.
- EDIT -
Here's an example of what I'm trying to do:
Say I have an #Entity ClassX that has a lazy loaded list of #Entity ClassY objects. Some how, I would like to have a log message spit out when 100 or more instances of ClassY are loaded into the session cache. This way, during development I can load a ClassX object and notice if I (or another developer on the team) happen to be accessing that list when I shouldn't be.
You could attach an Interceptor to listen to object load events, maintaining a count for each unique entity type and logging a warning whenever it goes past a certain threshold. The documentation shows you how to define a session-scoped interceptor, by passing it in at creation time:
Session session = sf.openSession( new AuditInterceptor() );
Most likely you're not creating your Session manually so this may not be helpful, but possibly the way that you are declaring your session has some way of passing an Interceptor through.
It's easier to declare a SessionFactory-scoped Interceptor but it doesn't seem to give you any reference back to the Session that the object is being created within, otherwise you'd be able to knock up some sort of counter in a WeakHashMap (with Session as the key so that you don't leak memory). If you're using the default Thread-local session strategy then you could always ask sessionFactory.getCurrentSession().
I'm having a difficult time understanding Spring Transactions. First off, I am trying to use as little of Spring as possible. Basically, I want to use #Transactional and some of its injection capabilities with JPA/Hibernate. My transactional usage is in my service layer. I try to keep them out of test cases. I use CTW and am spring-configured. I have component scan on the root of my packages right now. I also am using Java configuration for my datasource, JpaTransactionManager, and EntityManagerFactory. My configuration for the JpaTransactionFactory uses:
AnnotationTransactionAspect.aspectOf().setTransactionManager( txnMgr );
I do not use #EnableTransactionManagement.
Unfortunately, I'm having a hard time understanding the rules for #Transactional and can't find an easy page that describes them simply. Especially with regards to Session usage. For example, what if I want to use #Transactional on a class that does not have a default no-arg constructor?
The weirdest problem I'm having is that in some of the POJO service classes Transacitonal works great while in others I can see the transactions being created but operations ultimately fall saying that there is "no session or the session has been closed". I apologize for not having code to reproduce this, I can't get it down to a small set. This is why I am looking for the best resources so I can figure it out myself.
For example, I can have a method that gets a lazily fetched collection of children, iterates through it and puts it into a Set and returns that set. In one class it will work fine while in another class also marked with #Transactional it will fail while trying to iterate through the PersistentSet saying that there is no session (even though there IS a transaction).
Maybe this is because I create both of these service objects in a test case and the first one is somehow hijacking the session?
By the way, I have read through the spring source transaction documents. I'm looking for a clear set of rules and tips for debugging issues like this. Thanks.
Are you sure you loaded your parent entity in the scope of the very transaction where you try to load the lazy children? If it was passed in as parameter for example (that is, loaded from outside your #Transactional method) then it might not be bound to a persistence context anymore...
Note that when no #Transactional context is given, any database-related action may have a short tx to be created, then immediately closed - disabling subsequent lazy-loading calls. It depends on your persistence context and auto-commit configurations.
To put it simply, the behaviour with no transactional context being sometimes unexpected, the ground rule is to always have one. If you access your database, then you give yourself a well-defined tx - period. With spring-tx, it means all your #Repository's and #Services are #Transactional. This way you should avoid most of tx-related issues.