I'm gonna go with this design:
create an object and keep it alive during all web-app session.
And I need to synchronize its state with database state.
What I want to achieve is that :
IF between my db operations, that is, modifications that I persist to a db
someone intentionally spoils table rows, then on next saving to a database
all those changes WOULD BE OVERWRITTEN with the object state, that always contains valid data.
What Hibernate methods do you recommend me to use to persist the modifications in a database?
saveOrUpdate() is a possible solution, but maybe there's anything better?
Again, I repeat how it looks. First I create an object without collections. Persist it (save()).
Then user provides us with additional data. In a serviceLayer, again, we modify our object in memory (say, populate it with collections) and then, persist it again.
So every serviceLayer operation of the next step must simply guarantee that database contains the exact persistent copy of this object that we have in memory. If data in a database differ, it MUST BE OVERRIDDEN with the object (kept in memory) state.
What Session operations do you recommend?
FWIW saveOrUpdate() looks like the best option overall:
The saveOrUpdate() method is in practice more useful than update(),
save(), or lock(): In complex conversations, you don’t know if the item is in
detached state or if it’s new and transient and must be saved. The automatic
state-detection provided by saveOrUpdate() becomes even more useful when you
not only work with single instances, but also want to reattach or persist a network
of connected objects and apply cascading options.
However for your case, if you are sure the entity was modified in detached state, and/or don't mind occasionally hitting the DB with an unnecessary UPDATE, maybe update() is the safest choice:
The update() operation
on the Session reattaches the detached object to the persistence context and
schedules an SQL UPDATE. Hibernate must assume that the client modified the
object while it was detached. [...] The persistence context is flushed automatically
when the second transaction in the conversation commits, and any
modifications to the once detached and now persistent object are synchronized
with the database.
Quotes from Java Persistence with Hibernate, chapter 11.2.2.
Related
I came across this example from a book while learning about the Hibernate framework.
public class BasicMovieManager()
{
private void persistMovie(Movie movie)
{
Session session=sessionFactory.getCurrentSession();
session.beginTransaction();
session.save(movie);
session.getTransaction().commit();
}
}
I can understand that the Movie object has to be mapped and written to the database. I also understand that the commit step will write to the database. But what is the purpose of save() here? A few sources I referred say that save() persists the data. Doesn't persist mean writing to a permanent storage? If not,what exactly does it mean?
I Believe the comparison is misplaced,you should compare
Commit vs Flush
and
Save vs Persist
Edited:
You should know this:
transient: never persistent, not associated with any Session.
persistent: associated with a unique Session.
detached: previously persistent, not associated with any Session.
Commit will save the data to DB, so you cannot rollback anymore, in opposed to Flush.
Save will generate and return identifier prior to writing the object, later upon Flush or Commit it writes the data to the database.
Where Persist will not return a value,as you only mark the object as dirty in the cache, so upon flush or commit it will be saved, this is useful when persisting multiple objects in a transaction.
Quick answer: save() stores the data in the database. commit() makes it visible to others (cf. isolation levels).
Slightly longer answer: Database operations should obey the ACID principle, (A)tomicity being the operative element here. If you are doing more than one change/insert, you can wrap it in a transaction and commit/reject the entire set of operations as a whole.
In your example it doesn't make much sense to start a transaction, but in real-life situations it very much makes sense.
Cheers,
Basically transactions are used when you are trying to persist related set of objects. If you are trying to insert only one object then transaction is not necessary. But when you are trying to persist a set of related objects which are dependent on each other then you should go for transaction where it comes handy
As for example:
//1.Load session
//2. persist an object
In above scenario nothing will happen if your persisting of a single object fails or success but when you will do like this:
//1. Load session
//2. Persist one object
//3. Persist other object whose data affects previous
In above scenarion suppose second was performed successfully but third failed that can adversely affect your data or business. This can be resolved as:
//1. Load session
//2. Begin transaction
//3. perform set of related operation
//4. commit
If any thing will go wrong in above scenario the whole transaction will be rollbacked nothing will be persisted. And if you want to do something after your transaction fails you can handle it by using try catch.
So, basically save() is used to save data in tables but commit() is used in transaction management
In a container managed transaction i get a detached object and merge it so that the detached object is brought to managed state.My initial question is by caching the Pojo java objects and merging is a better idea to get the object into session or performing the get of the data from the DB to get in to session context a better idea in terms of cost of operation/time involved in getting the data from the DB?If i am performing an merge at start to get the object into the session context and doing the modification on this merged object will the hibernate take care of generating all the required sql statements and at the end will it be taken care ?
Please comment back which is better approach to get the entity to session , using a merge of the cached detached object or fetching the data from the DB is lesser time consumption?
when you call detach and then merge, merge returns you the attached entity in the context. it's a common mistake that users would use the passed entity after merge operation hoping that would be managed but this is not the case. you have to use the returned entity from merge which will be managed by hibernate and subsequent changes will be flushed at transaction end automatically.
it doesnt matter much when u load your entity coz hibernate will anyways fire a select if it is already not loaded in the context. also even if you keep on doing changes to your managed entity, hibernate will fire update only when you exit your transaction or call flush() explicitly.
Copy the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded. Return the persistent instance. If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session. This operation cascades to associated instances if the association is mapped with cascade="merge".
According to the API it saves a copy when you perform the merge and then returns a new instance. Based on my experience its always better to merge at the end after you have performed all the updates on the objects in detached state. Its better because you will call merge operation only at the end when the object state is ready to be persisted.
Also this will perform better because the object is moved to persistent context at the end and hence Hibernate will not have to come into picture till the end.
I have three layers i.e Action,Service,DAO layers. I have loaded an object(of Employee class) from DB using hibernate with id 123.I have done some modifications to employee object.Later, I have create hibernate business object and done some modifications to that.
Employee e = service.getEmp(123);
e.setName("Ashok");
Order o = new Order
o.setNumber(567);
service.saveOrUpdate(o);
In this scenario, why it is trying to update employee object even though I not saying to save it? How to detach that from session?I don't want hibernate to update employee object.
In this scenario, why it is trying to update employee object even
though I not saying to save it?
I quote from the hibernate docs:
Transactional persistent instances (i.e. objects loaded, saved,
created or queried by the Session) can be manipulated by the
application, and any changes to persistent state will be persisted
when the Session is flushed. [...].
There is no need to call a particular method (like update(), which has
a different purpose) to make your modifications persistent.
And
How to detach that from session?
Mark collections with cascade="evict". Then Session.evict(Object) the object before flushing on your object (if you have FlushMode.AUTO then maybe set it to MANUAL until you have done what you want).
Hibernate, as I know updates the Database once the attached Objects in the session's value changes. Is there a way to obtain a fresh copy from the database and reattach the fresh copy discarding the changed object?
Below is an object I obtained from Querying the Database using Hibernate.
Rtpmast rtpmast = (Rtpmast) iterator.next();
Once executed the below code
rtp.setRptval1(promotionMethod.getType());
Hibernate registers that the the object has changed. And when I commit a transaction later on or query the Database the Session is flushed?
What I want is to temporally update the Rtpmast object and discard the changed object later.
Hibernate, as I know updates the Database once the attached Objects
in the session's value changes.
Actually,Hibernate updates the database only after invoking session.save(...), session.delete(...) etc. methods. If you're in a transaction you'd also have to commit changes.
What you want is either use evict() and re-query the object, as you've mentioned, or detach the instance you're working on, which means you need to close() the Session (there are other, less trivial, ways to do so as mentioned here).
I have an entity that has a state table associated with it. The state table is managed by another process, and contains a list of objects that my business logic must process. I would like to get a new snapshot of the state table each time I reload the entity. How can I ensure that no part of Hibernate or its support libraries ever caches any of the values of this table? Basically, I want to get a new view of the collection every time I call getMyStateValues ().
Most of the point of Hibernate is to prevent that from happening and return a consistent view of an entity's state in the scope of a given transaction. So either reload the whole entity, in different transactions every time. Or, if you need to reload the state table during a business transaction, load only the state table by the parent entity's id in a separate Hibernate session.
You can create a method in your entity that queries the database and return the collection. getXYXReload(). It´s not a very nice design decision, thought.
You can use Hibernate's CacheMode. It allows you to instruct a hibernate session on how to interact with the cache. You can get access to the underlying session with:
#PersistenceContext EntityManager manager;
...
org.hibernate.Session session = (Session)manager.getDelegate();
Unfortunately, this technique applies to the whole session, and not specifically to an entity.