Correct me if anything is wrong.
Now when we use Spring DAO for ORM templates, when we use #Transactional attribute,
we do not have control over the transaction and/or session when the method is called externally, not within the method.
Lazy loading saves resources - less queries to the db, less memory to keep all the collections fetched in the app memory.
So, if lazy=false, then everything is fetched, all associated collections, that is not effectively, if there are 10,000 records in a linked set.
Now, I have a method in a DAO class that is supposed to return me a User object.
It has collections that represent linked tables of the database.
I need to get a object by id and then query its collections.
Hibernate "failed to lazily initialize a collection" exception occurs when I try to access the linked collection that this DAO method returns.
Explain please, what is a workaround here?
Update: All right, let me ask you this. DAO is an abstract layer, so a method "getUserById(Integer id)" is supposed to return an Object.
What if in some cases I need these linked collections of the User object and in other situation I need those collections.
Are there only two ways:
1) lazy loading = false
2) create different methods: getUserByIdWithTheseCollections(), getUserByIdWithOtherCollections() and inside those methods use your approach?
I mean are there only 2 ways and nothing better?
Update 2: Explain please, what would give me the explicit use of SESSIONFACTORY?
How does it look in practice? We create an instance of DAO object,
then inject it with session factory and this would mean that two consequent
method calls to DAO will run within the same transaction?
It seems to me that anyway, DAO is detached from the classes that make use of it!
The logic and transactions are encapsulated within DAO, right?
You can get the linked collection in transaction to load it while you're still within the transaction:
User user = sessionFactory.getCurrentSession().get(User.class, userId);
user.getLinkedCollection().size();
return user;
As BalusC has pointed out, you can use Hibernate.initialize() instead of size(). That's a lot cleaner.
Then when you return such an entity, the lazy field is already initialized.
Replying to your PS - is using transactions on service level (rather than DAO) level feasible? It seems to be, as doing each DAO call in separate transaction seems to be a waste (and may be incorrect).
I find that it's best to put #Transactional at the service layer, rather than the DAO layer. Otherwise, all your DAO calls are in separate hibernate sessions - all that object equality stuff won't work.
In my opinion best way to solve this problem will be to design application in a session-per-request model. Then, if you even have an object taken from DAO, until your OSIV pattern works you can use the object safely anywhere in application, even in views without bothering this stuff. This is probably better solution that those proposed because:
Hibernate.initialize() or size is a very artificial workaround - what if you want to have User with different collection initialized, would you write another method for getting user?
Service layer transactional model is OK, but the same problem comes when you want to get object extracted from the service layer to use it in controller or view
You could do something like following:
public User getByUserId(Long id, String ... fetch) {
Criteria criteria = createCriteria();
if (fetch != null) {
for (String fieldName : fetch) {
criteria.setFetchMode(fieldName, FetchMode.JOIN); // fetch these fields eagerly
}
}
return criteria.add(Restrictions.eq("id", id)).list();
}
Related
I was generating POJOs from my database using different tools and noticed that some would generate collections as fields, with getters and setters, for one to many relationships and others didn't.
Let's say I have an Order and Product table. Each order can have one or many products.
Collection<Product> list = new ArrayList<>();
list.add(product1);
list.add(product2);
Method 1:
Order order = new Order();
order.setDate(...);
orderDao.add(order);
orderDao.addProductBatch(list)
Method 2:
Order order = new Order();
order.setDate(...);
order.setProductCollection(list);
orderDao.add(order);
and in the add method, include an addProductBatch call.
which method is prefered? Also for some one to many relationships adding multiple objects in a single transaction never occurs - in which case you wouldn't need some of these collections - is this correct?
It depends on the implementation of the DAO...
In the method 2, you build your order and its products in the business model, then pass the complete and consistent order (order + list of products) to be saved by the DAO. The transaction implementation is internal to the DAO.
In the method 1, you call twice the DAO, first with the order (without product), then again with the list of products related to the order. It means, either that the DAO is stateful and you have some method to execute the transaction when you are done setting it up, or that there is 2 transactions. If you are in the case of this last option, consistency of the DB can be wrong (having an order without any products).
Method 2 is certainly better since it allows stateless DAO, and a clean transaction management.
I would prefer variant of the first method. We avoid to use direct data transfer between entities and DAO services in form of collections, but prefer creation such methods as add, get, remove directly in entity (I know it's some against the rules) - all first needed methods for entity life encapsulates in entity.
I have a lazily fetched field in my entity
#ElementCollection(fetch = LAZY)
private List<String> emails;
And my transaction boundary stops at service class, I don't want to keep it open while rendering the view. I want my service classes to return detached entities.
In my service class I tried calling the getters but that seem to be erased by the compiler -- maybe it's an optimization for a statement that appear to do nothing
/* User Service class */
#Transactional
public List<User> getAllUsers() {
List<User> users = new ArrayList();
for(User u : userRepo.findAll()) {
u.getEmails(); // <-- this seem to be erased by the compiler optimization.
users.add(u);
}
return users;
}
Hence I'm forced to print the lazy field into TRACE log so that it won't clutter the production logs. Doing this will ensure the lazy field is pre-populated before the entities are detached:
LOG.trace(u.getEmails().toString());
However this solution isn't pretty at all. Is there any better way to do this?
I don't want to mark the field as EAGER because I have another service method that purposely skips the relationship for efficiency.
Since you are using Hibernate, this is probably going to have to be specific. I'm not aware of any JPA functionality that does this. According to the Hibernate Documentation:
The static methods Hibernate.initialize() and Hibernate.isInitialized(), provide the application with a convenient way of working with lazily initialized collections or proxies. Hibernate.initialize(cat) will force the initialization of a proxy, cat, as long as its Session is still open. Hibernate.initialize( cat.getKittens() ) has a similar effect for the collection of kittens.
This should prevent the compiler from erasing that call, and remove the need for you to do some kind of work with the return value to trick the compiler. So Hibernate.initialize(u.getEmails()) should work for you.
Hibernate.initialize(u.getEmails())
I am currently working on a product that works with Hibernate (HQL) and another one that works with JPQL. As much as I like the concept of the mapping from a relational structure (database) to an object (Java class), I am not convinced of the performance.
EXAMPLE:
Java:
public class Person{
private String name;
private int age;
private char sex;
private List<Person> children;
//...
}
I want to get attribute age of a certain Person. A person with 10 children (he has been very busy). With Hibernate or JPQL you would retrieve the person as an object.
HQL:
SELECT p
FROM my.package.Person as p
WHERE p.name = 'Hazaart'
Not only will I be retrieving the other attributes of the person that I don't need, it will also retrieve all the children of that person and their attributes. And they might have children as well and so on... This would mean more tables would be accessed on database level than needed.
Conclusion:
I understand the advantages of Object Relational Mapping. However it would seem that in a lot of cases you will not need every attribute of a certain object. Especially in a complex system. It would seem like the advantages do not nearly justify the performance loss. I've always learned performance should be the main concern.
Can anyone please share their opinion? Maybe I am looking at it the wrong way, maybe I am using it the wrong way...
I'm not familiar with JPQL, but if you set up Hiernate correctly, it will not automatically fetch the children. Instead it will return a proxy list, which will fetch the missing data transparently if it is accessed.
This will also work with simple references to other persistent objects. Hibernate will create a proxy object, containing only the ID, and load the actual data only if it is accessed. ("lazy loading")
This of couse has some limitations (like persistent class hierarchies), but overall works pretty good.
BTW, you should use List<Person> to reference the children. I'm not sure that Hibernate can use a proxy List if you specify a specific implementation.
Update:
In the example above, Hibernate will load the attributes name, age and sex, and will create a List<Person> proxy object that initially contains no data.
Once the application accesses calls any method of the List that requires knowledge of the data, like childen.size() or iterates over the list, the proxy will call Hibernate to read the children objects and populate the List. The cildren objects, being instances of Person, will also contain a proxy List<Person> of their children.
There are some optimizations hibernate might perform in the background, like loading the children for other Person objects at the same time that might be in this session, since it is querying the database anyways. But whether this is done, and to what extend, is configurable per attribute.
You can also tell hibernate to never use lazy-loading for certain references or classes, if you are sure you'll need them later, or if you continue to use the persistent oject once the session is closed.
Be aware that lazy loading will of course fail if the session is no longer active. If for example you load a Person oject, don't access the children List, and close the session, a call to children.size() for example will fail.
IIRC the hibernate session class has method to populate all not-yet-loaded references in a persistent oject, if needed.
Best read the hibernate documentation on how to configure all this.
It is a rather general question, but I will give a stripped down example. Say I have a Web CRUD application that manages simple entities stored in a database, nothing but classic : JSP view, RequestMapping annotated controller, transactional service layer and DAO.
On an update, I need to know the previous values of my fields, because a business rule asks a for a test involving the old and new values.
So I am searching for a best practice on that use case.
I thing that spring code is way more extensively tested and more robust than my own, and I would like to do it the spring way as much as possible.
Here is what I have tried :
1/ load an empty object in controller and manage the update in service :
Data.java:
class Data {
int id; // primary key
String name;
// ... other fields, getters, and setters omitted for brevity
}
DataController
...
#RequestMapping("/data/edit/{id}", method=RequestMethod.GET)
public String edit(#PathVariable("id") int id, Model model) {
model.setAttribute("data", service.getData(id);
return "/data/edit";
}
#RequestMapping("/data/edit/{id}", method=RequestMethod.POST)
public String update(#PathVariable("id") int id, #ModelAttribute Data data, BindingResult result) {
// binding result tests omitted ..
service.update(id, data)
return "redirect:/data/show";
}
DataService
#Transactional
public void update(int id, Data form) {
Data data = dataDao.find(id);
// ok I have old values in data and new values in form -> do tests stuff ...
// and MANUALLY copy fields from form to data
data.setName(form.getName);
...
}
It works fine, but in real case, if I have many domain objects and many fields in each, it is quite easy to forget one ... when spring WebDataBinder has done it including validation in the controller without I have to write any single thing other than #ModelAttribute !
2/ I tried to preload the Data from the database by declaring a Converter
DataConverter
public class DataConverter<String, Data> {
Data convert(String strid) {
return dataService.getId(Integer.valueOf(strid));
}
}
Absolutely magic ! The data if fully initialized from database and fields present in form are properly updated. But ... no way to get the previous values ...
So my question is : what could be the way to use spring DataBinder magic and to have access to previous values of my domain objects ?
You have already found the possible choices so i will just add some ideas here ;)
I will start with your option of using a empty bean and copying the values over to a loaded instance:
As you have shown in your example it's an easy approach. It's quite easily adaptable to create a generalized solution.
You do not need to copy the properties manually! Take a look at the 'BeanWrapperImpl' class. This spring object allows you to copy properties and is in fact the one used by Spring itself to achieve it's magic. It's used by the 'ParameterResolvers' for example.
So copying properties is the easy part. Clone the loaded object, fill the loaded object and compare them somehow.
If you have one service or just several this is the way to go.
In my case we needed this feature on each entity. Using Hibernate we have the issue that an entity might not only change inside a specific service call, but theoretically all over the place..
So I decided to create a 'MappedSuperClass' which all entities need to extend. This entity has a 'PostLoad' event listener which clones the entity in a transient field directly after loading. (This works if you don't have to load thousands of entities in a request.) Then you need also the 'PostPersist' and 'PostUpdate' listeners to clone the new state again as you probably don't reload the entity before another modification.
To facilitate the controller mapping I have implemented a 'StringToEntityConverter' doing exactly what you did, just generalized to support any entity type.
Finding the changes in a generalized approach will involve quite a bit of reflection. It's not that hard and I don't have the code available right now, but you can also use the 'BeanWrapper' for that:
Create a wrapper for both objects. Get all 'PropertyDescriptors' and compare the results. The hardest part is to find out when to stop. Compare only the first level or do you need deep comparison?
One other solution could also be to rely on Hibernate Envers. This would work if you do not need the changes during the same transaction. As Envers tracks the changes during a flush and creates a 'Revision' you can "simply" fetch twp revisions and compare them.
In all scenarios you will have to write a comparison code. I'm not aware of a library but probably there is something around in the java world :)
Hope that helps a bit.
I have a Singleton-EJB, that reads all objects from a database with a specific state. Then I do something with these objects and set the state to someting else:
#Singleton
public class MyEJB {
#PersistenceContext(unitName = "MyPu")
private EntityManager em;
#Lock(LockType.WRITE)
public void doSomeStuffAndClose() {
List<MyObj> objects = getAllOpenObjects();
for (MyObj obj : objects) {
// do some stuff here...
obj.setClosed(true);
}
}
private List<MyObj> getAllOpenObjects() {
TypedQuery<MyObj> q = em.createQuery("select o from MyObj o "
+ "where o.closed = false", MyObj.class);
return q.getResultList();
}
}
Now, if i would like to ensure that my method cannot be called concurently, I add the annotation #Lock(LockType.WRITE). But the transaction that sets the states in the database is committed AFTER the lock was released and it is possible that the next caller grabs the same objects again.
How could I prevent this?
If you are using Wildfly: This is a bug. https://issues.jboss.org/browse/WFLY-4844 describes your problem which will be fixed in Wildfly 10. There the problem is described as a timer problem which might be the same as yours.
My workaround is to seperate the code that does the work into another bean which is called by the outer (timer) bean. The outer bean method is annotated to not start a transaction (#TransactionAttribute(TransactionAttributeType.NEVER)), so the transaction is started and safely finished in the second new bean.
You could use SELECT FOR UPDATE to serialize the access of the rows.
With JPA 2 use the LockModeType:
http://docs.oracle.com/javaee/6/api/javax/persistence/LockModeType.html
q.setLockMode(LockModeType.PESSIMISTIC_WRITE)
There's no way to do this in JPA (so, in a portable way). Your options might be:
Some JPA implementations allow setting isolation level on a per-query basis (e.g. OpenJPA), some don't (Hibernate). But even in OpenJPA this hint needs to be implemented in a particular database driver, otherwise it has no effect).
Running a native query – consult your database documentation for details.
As a side comment I should say that JPA (and Java EE in general) is not designed with bulk database operations in mind – it's rather for multiple concurrent queries for data items that in most cases don't overlap.
You can invoke from your doSomeStuffAndClose method Stateful Session Bean with implemented SessionSynchronization interface. Than from afterCompletion method in SFSB you can inform singleton bean that data has been commited and can handle another request.
I know that this way we have two really tight coupled beans, but this should solve your problem.
You're using container-managed concurrency (the default). In JavaEE 7 (not sure about older ones, but likely yes) the transaction is guaranteed to commit before the method exits, hence before lock is released. From the JavaEE 7 tutorials:
"Typically, the container begins a transaction immediately before an enterprise bean method starts and commits the transaction just before the method exits. Each method can be associated with a single transaction. Nested or multiple transactions are not allowed within a method."
https://docs.oracle.com/javaee/7/tutorial/doc/transactions003.htm#BNCIJ
If you're experiencing another behavior, check for any cache that might be active (#Cacheable). You may watch another interesting question here: https://stackoverflow.com/questions/26790667/timeout-and-container-managed-concurrency-in-singleton
By the way, LockType(WRITE) is also default, you don't need to explicit it. Hence, getAllObjects is also LockType(WRITE).