i'm new to hibernate, while i add an element and cancel it, I see that the data gets saved in db. Nowhere in my code i called save method to save it.
If you're modifying an object already associated with an Hibernate session all your modifications will be saved. Check the manual.
For example if you do something like:
Load an object from a DB
Modify the object by adding or removing values
The modifications will be saved even if you don't use the save() method.
seems you have AutoFlash and/or AutoCommit parameters On in your hibernate configuration. Try disable them.
Once you load the data from the db, it becomes persistent, and any changes made to it will be updated, if it is updated before the session is closed. If you do not want the data in the db to be updated with the changes you are making after loading it, make the changes only after closing the session. Then after that, if you want to persist the data again, open one more session and call save() or persist().
EDIT:
1) Make sure cache is disabled in order to ensure there is no caching between different sessions.
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
2) Follow the steps:
i) begin session --> begin transaction --> get data from both tables --> close transaction --> close session.
ii) create object of 3rd table--> do whatever u want with it, like adding data from the first two tables.
iii) begin new session --> begin new transaction --> save the object of 3rd table using session.save() --> close transaction --> close session.
After step (i) is done, the objects from table1 and table2 are no more 'persistent', and are 'detached'. If you don't do session.save() in step (iii), the object of table3 won't get saved, because it is no longer dealing with persistent objects.
This is from my understanding of persistent and detached objects. If it doesn't work, do reply. I will code it down and find a solution.
And one more advice, do consider using session.persist() instead of session.save().
If you want to understand their difference, this is the link: What's the advantage of persist() vs save() in Hibernate?
Good Luck!
You may have used the #Transactional annotation.
Try just removing the annotation.
Related
I have a list of ~10 000 objects.
I am trying to call an mysql update query (procedure) and then to get the updated objects inside same transaction.
Can this be achieved ?
When I call a delete statement + flush(), hibernate retrieves me correct objects (deleted objects are missing)
But when I try update statement + flush(), hibernate retrieves me the initial unchanged objects.
#Transactional
void test() {
//...
em.createQuery("delete from StorefrontProduct sp where sp in (:storefrontProducts)")
.setParameter("storefrontProducts", storefrontProductsToDelete)
.executeUpdate();
// example
em.createQuery("update StorefrontProduct sp set sp.orderIndex=0 where sp.id=90")
.executeUpdate();
em.flush();
//Simple JPA query
List<StorefrontProduct> result = repository.findAllByPreviousOrderIndexIsNotNull();
//additional code....
}
After running the code from above and putting a breakpoint after findAll call, provided objects from 1-st query were deleted and flushed, but the update query was not flushed.
That is known counterintuitive behaviour of Hibernate.
First of all, em.flush() call might be superfluous if flush mode set to AUTO (in that case Hibernate automatically synchronises persistence context (session-level cache) with underlying database prior executing update/delete queries).
Delete and successive Select case:
you issues delete then select, since select does not see deleted records anymore you do not see deleted records in resultset, however if you call findById you may find deleted records.
Update and successive Select case:
you issues update then select, when processing resultset Hibernate sees both records stored in database and records stored in persistence context and it assumes that persistence context is a source of truth, that is the reason why you see "stale" data.
There are following options to mitigate that counterintuitive behaviour:
do not perform direct updates, use "slow" find/save API instead
either detach or refresh stale entities after direct update, em.clear() may also help, however it completely cleans up persistence context, which might be undesirable
If I have an ATG Nucleus Repository Item that is not cacheable (ATG/Nucleus simple cache is disabled) AND I'm not in a transaction, the following results in two queries to the database.
The following code results in a db query for every property.
repositoryItem.getPropertyValue("columnA");
repositoryItem.getPropertyValue("columnB");
If debugging for the user entity is enabled you would see the following log statements ever each call:
repositoryItem.getPropertyValue("columnA");
DEBUG loadingPropertyFromDatabase(user:ID_1.columnA, column_a_value) property is not cacheable caching disabled for this transaction
DEBUG loadingPropertyFromDatabase(user:ID_1.columnB, column_b_value) property is not cacheable caching disabled for this transaction
DEBUG getPropertyValue(user:ID_1.columnA) -> "column_a_value" (value from database)
repositoryItem.getPropertyValue("columnB");
DEBUG loadingPropertyFromDatabase(user:ID_1.columnA, column_a_value) property is not cacheable caching disabled for this transaction
DEBUG loadingPropertyFromDatabase(user:ID_1.columnB, column_b_value) property is not cacheable caching disabled for this transaction
DEBUG getPropertyValue(user:ID_1.columnB) -> "column_b_value" (value from database)
We cannot enable caching, due to how the object is being access/updated by other systems.
I also do not want to create a transaction for a read only query of the entity.
If I was using Hibernate, the Hibernate session would keep a state within the session, even if I was not in a transaction. That doesn't seem to be the case with ATG/Nucleus. Is there any way I can get this type of behavior or a thread level cache?
In looking at documentation and walking through the code via debugger (which is difficult w/out source), I am not having any luck finding a work around.
Thanks!
You need to wrap the getPropertyValue calls with a transaction which will save the results of the database queries into the temporary transaction cache. That will prevent the repository from going back to the database for every getPropertyValue call.
You also want to ensure that all the properties you are accessing are part of the same property group (as described here). The first load of the item from the database will pull in the properties in the same group as the ID property. This combined with the transaction cache will significantly reduce the number of database queries.
I also do not want to create a transaction for a read only query of
the entity.
I don't understand why you wouldn't want to explicitly demarcate a transaction. Every getPropertyValue call will automatically create (and end) a transaction if one isn't already present. So in your example, you would have 2 transactions implicitly created for you. Why not just create 1 transaction explicitly?
In the application that i'm working on, i have a senario,
UI updates some data which is already retrived from the database and sends an object back to the server(say using EntityTag.java), Server retrives the object again from the DB(say Entity.java which is mapping file in hibernate) and copies all the values from the EntityTag into Entity.java objct.
Now, using some service, it tries to save the updated Entity.java object. This is does in spring declarative transactions. So, i'm assuming that the new transaction is started on this service.
What I was hoping to see in this service method is a session. merge() because, we updated an object which was detached, but here they use saveOrUpdate on the entity.java object. I see that the object is updated into the table without any issues. This is so wierd, until now i've been thinking that the merge will merge the object into the session and later, i can commit the changes, this seems soo wierd to me.
In what cases does saveandupdate work without issues?
See this answer, saveOrUpdate works well if there is never the risk that there is not already an object with the same database identifier associated to the session where saveOrUpdate is being called.
If an object already exists with the same database Id, saveOrUpdate throws an error, while merge will just replace the object in the session with the new object and return a reference to the new attached object.
Hibernate had a method called saveOrUpdateCopy that provided the same as current merge,
which got standardized as merge in JPA.
Although saveOrUpdateis still available and used in many tutorials, you would be better off always using merge when dealing with detached objects, as it's hard / error prone to try to guess if an object is already in a session.
We keep user object in session. When we update it first time ( using entityManager.merge( ent )) it works fine; but second time I get following exception:
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.kids.domain.Child#22]
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:492)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:256)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:86)
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:781)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:766)
I am using spring with hibernate & jpa. Spring is injecting EntityManager in DAO. I do understand that if I would do a fresh find() everytime then make all the changes on that object and then merge().. it will work fine.. but in my case I cannot do that.
I also checked that the hashcode of EntityManager used is same both time; i.e same EntityManager instance is getting used both time then why it gives this exception when trying to update a record second time
Any help would be highly appreciated.
I tried lots of things but nothing worked. Even on internet there was no solution. Finally, when I removed version from my entities ( i.e. remove OptimisticLockException support provided by hibernate ).. everything started working fine. Probably , I will try to handle OLE myself.
When you call merge method in the current transaction, hibernate will copy the state of the given object onto the persistent object with the same identifier and returns new manageable entity. You need to work on the manageable entity which is returned by the merge in subsequent operations because this entity has new version than in DB.
I have a table and two databases which have the same table, but one is a symlink of the other one and only read is permitted on this table.
I have mapped the table to Java using Hibernate and I use spring to set the Entity Manager's data source as one of the two databases based on some input criteria.
I call only read only operations (selects) when I am connected to the second database, but it seems Hibernate tries to flush something back to the database and it fails telling update is not allowed on this view.
How do I disable this update only for the second datasource and keep it normal for the first one?
Update:
Looking at the stack trace, the flush seems to be started here:
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:365)
at org.hibernate.ejb.AbstractEntityManagerImpl$1.beforeCompletion(AbstractEntityManagerImpl.java:504)
... 55 more
Is this related to hibernate.transaction.flush_before_completion property? Can I set it to false for the second data source?
Most probably your entities become "dirty" the same moment they are loaded from the database, and Hibernate thinks that it needs to store the changes. This happens, if your accessors (get and set methods) are not returning the exact same value or reference that had been set by Hibernate.
In our code, this happened with lists, developers created new list instances because they didn't like the type they got in the setter.
If you don't want to change the code, change the mapping to field access.
You can also prevent Hibernate of storing changes by setting FlushMode to never on the session, but this only hides the real problem which will still occur in other situations an will lead to unnecessary updates.
First you need to determine if this is DDL or DML. If you don't know, then I recommend you set hibernate.show_sql=true to capture the offending statement.
If it is DDL, then it's most likely going to be Hibernate updating the schema for you and you'd want to additionally configure the hibernate.hbm2ddl.auto setting to be either "update" or "none", depending on whether you're using the actual db or the symlinked (read-only) one, respectivley. You can use "validate" instead of none, too.
If it is DML, then I would first determine whether your code is for some reason making a change to an instance which is still attached to an active Hibernate Session. If so, then a subsequent read may cause a flush of these changes without ever explicitly saving the object (Grails?). If this is the case, consider evicting the instance causing the flush ( or using transport objects instead ).
Are you perhaps using any aspects or Hibernate lifecycle events to provide auditing of the objects? This, too, could cause access of a read-only to result in an insert or update being run.
It may turn out that you need to provide alternative mappings for the offending class should the updatability of a field come into play, but the code is doing everything exactly as you'd like ( this is unlikely ;0 ). If you are in an all-annotation world, this may be tricky. If working with hbm.xml, then providing an alternative mapping is easier.