I have a process which updates a tree to the database, and in doing so, performs reads to check for duplicates entities.
I'm finding that trying to do a criteria.uniqueResult() midway through this process causes the following error:
org.hibernate.PropertyValueException:
not-null property references a null or
transient value
Digging through the stack trace, I see that the uniqueResult() is flushing the session, attempting to perform updates that aren't ready to go to the database yet.
at org.hibernate.engine.Cascade.cascade(Cascade.java:153)
at org.hibernate.event.def.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:154)
at org.hibernate.event.def.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:145)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:88)
at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:58)
at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:996)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1589)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:306)
at org.hibernate.impl.CriteriaImpl.uniqueResult(CriteriaImpl.java:328)
at com.inversion.dal.BaseDAO.findUniqueByCriterion(BaseDAO.java:59)
Have I set something up wrong here?
Any help greatly appreciated.
Marty
hibernate remembers with objects needs to be saved. when issuing a select, hibernate will flush these changes. this ensures the select will return the correct results.
setting flushmode to anything else than FlushMode.AUTO will prevent this behaviour. But the error is in your code, where you pass an incomplete object to hibernate to persist or update. So the correct solution is to pass the object later to hibernate, when it is complete.
Turn off auto-flushing on the Session object to fix this exception.
Session s;
// if you're doing transactional work
s.setFlushMode(FlushMode.COMMIT);
// if you want to control flushes directly
s.setFlushMode(FlushMode.MANUAL);
This is not your error however. Something earlier in your code is causing the in memory objects to be in an invalid state which is trying to be persisted to the DB during the autoflush.
I've pulled my hair out many times trying to get to the bottom of these issues. The problem being that it's so difficult to get to the root of the issue causing it.
If you're nearing your wits end you can also execute the supporting queries such as findAll in a new session:
Domain.withNewSession { session -> ... }
That has usually circumvented the problem for me in most cases.
Related
We are facing a bug that is not always happening in our app, it happens when we use Entity manager find after updating an entity, for some reason it is retrieving the outdated version of the entity.
Is this happening because of the transaction taking time to commit the changes? and why is it not always happening?
The code for fetching the entity and updating it based on the primary key:
Order order = em.find(order.class, orderId);
em.refresh(order);
order.setStatus("OPEN");
em.merge(order);
em.flush();
The code after updating in another method (same order id):
Order order = em.find(order.class, orderId);
if (order == null) return;
if (!"OPEN".equals(order.getStatus))
throw new Exception(...);
else
//some logic
Sometimes, the exception is thrown, meaning the order status is not changed yet.
We are using JTA with weblogic and eclipse persistence as the JPA implementation.
If anyone has any clue what might be causing this, I would be grateful, if any extra info is required, feel free to call it out.
Is the two methods in the same transaction ? if not, it's possible that the the first transaction is not committed when you call the second method.
Second thing to verify, is the cache, it's possible that you implement the second level of cache by default, it cause error like this.
I have a complex set of code that has to go through my domain and merge some different entities, and that ends up having to merge a bunch of other entities. This is non-trivial code, so it's not something I can give an example of. The problem I have is that I'm getting a Not-null property references a null or transient value, but I can't figure out what entity is actually causing the problem. I've looked at the entity class type that is says has the null/transient value, but every time I see it loaded, I don't see any that have a null, or non-saved value in their references.
So far I haven't been able to find a way to trouble shoot this to get at what exactly hibernate thinks is missing the value it should have. If I could find what instance of the object it thinks is wrong, it would give me a clue where to look.
I've stepped through the hibernate code as best as I can, but so far I haven't actually been able to find an instance of the object that hibernate is complaining about.
As an addendum, the call that actually blows up is later in the code, and given the entity it is complaining about, the call itself (a delete call) that is blowing up does not have any unattached entities, I double checked that. So I think it's a case of hibernate flushing some things, and then finding out there is an issue, and blowing up there, even though the call itself isn't doing anything wrong.
Any advice as to how to track this particular object down?
I'm totally with shmosel: Your question is very vague...
Nevertheless: I think one of the problem diagnosing exceptions like yours is hibernates flush behavior. As you probably know hibernate flushes the session cache at the end of a transaction or once it needs to (for example hibernate needs to flush if a SELECT statement involves querying a table which is affected by an not yet flushed DELETE statement).
The consequence is of course the time of the exception being raised has little to do with the time the exception is "produced".
If no other approach is available you can spam flush statements throughout your code. There is no beauty in it, but it will likely help you to narrow down the problem.
This seems like it would come up often, but I've Googled to no avail.
Suppose you have a Hibernate entity User. You have one User in your DB with id 1.
You have two threads running, A and B. They do the following:
A gets user 1 and closes its Session
B gets user 1 and deletes it
A changes a field on user 1
A gets a new Session and merges user 1
All my testing indicates that the merge attempts to find user 1 in the DB (it can't, obviously), so it inserts a new user with id 2.
My expectation, on the other hand, would be that Hibernate would see that the user being merged was not new (because it has an ID). It would try to find the user in the DB, which would fail, so it would not attempt an insert or an update. Ideally it would throw some kind of concurrency exception.
Note that I am using optimistic locking through #Version, and that does not help matters.
So, questions:
Is my observed Hibernate behaviour the intended behaviour?
If so, is it the same behaviour when calling merge on a JPA EntityManager instead of a Hibernate Session?
If the answer to 2. is yes, why is nobody complaining about it?
Please see the text from hibernate documentation below.
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.
It clearly stated that copy the state(data) of object in database. if object is not there then save a copy of that data. When we say save a copy hibernate always create a record with new identifier.
Hibernate merge function works something like as follows.
It checks the status(attached or detached to the session) of entity and found it detached.
Then it tries to load the entity with identifier but not found in database.
As entity is not found then it treat that entity as transient.
Transient entity always create a new database record with new identifier.
Locking is always applied to attached entities. If entity is detached then hibernate will always load it and version value gets updated.
Locking is used to control concurrency problems. It is not the concurrency issue.
I've been looking at JSR-220, from which Session#merge claims to get its semantics. The JSR is sadly ambiguous, I have found.
It does say:
Optimistic locking is a technique that is used to insure that updates
to the database data corresponding to the state of an entity are made
only when no intervening transaction has updated that data since the
entity state was read.
If you take "updates" to include general mutation of the database data, including deletes, and not just a SQL UPDATE, which I do, I think you can make an argument that the observed behaviour is not compliant with optimistic locking.
Many people agree, given the comments on my question and the subsequent discovery of this bug.
From a purely practical point of view, the behaviour, compliant or not, could lead to quite a few bugs, because it is contrary to many developers' expectations. There does not seem to be an easy fix for it. In fact, Spring Data JPA seems to ignore this issue completely by blindly using EM#merge. Maybe other JPA providers handle this differently, but with Hibernate this could cause issues.
I'm actually working around this by using Session#update currently. It's really ugly, and requires code to handle the case when you try to update an entity that is detached, and there's a managed copy of it already. But, it won't lead to spurious inserts either.
1.Is my observed Hibernate behaviour the intended behaviour?
The behavior is correct. You just trying to do operations that are not protected against concurrent data modification :) If you have to split the operation into two sessions. Just find the object for update again and check if it is still there, throw exception if not. If there is one then lock it by using em.(class, primary key, LockModeType); or using #Version or #Entity(optimisticLock=OptimisticLockType.ALL/DIRTY/VERSION) to protect the object till the end of the transaction.
2.If so, is it the same behaviour when calling merge on a JPA EntityManager instead of a Hibernate Session?
Probably: yes
3.If the answer to 2. is yes, why is nobody complaining about it?
Because if you protect your operations using pessimistic or optimistic locking the problem will disappear:)
The problem you are trying to solve is called: Non-repeatable read
I am getting following error while trying to persist object using jpa.AM getting following error
NestedThrowables:
<openjpa-1.2.2-SNAPSHOT-r422266:778978M-OPENJPA-975 nonfatal store error> org.apache.openjpa.persistence.OptimisticLockException: An optimistic lock violation was detected when flushing object instance "org.apache.openjpa.enhance.com$ibm$cloud$bss$client$db$data$Offeringattribute$pcsubclass-com.ibm.cloud.bss.client.db.data.Offeringattribute-10013800" to the data store. This indicates that the object was concurrently modified in another transaction.
Now i had solved this error last time by inserting some flush statement as shown below
em.persist(xyz);
em.flush(); //added this line
dbAttr.setOid((xyz.getId());
em.merge((xyz);
But i am not remembering if i did something else last time.Am getting this error even after adding this flush statement.
Note: am running my application as standalong console app and am sure that only 1 thread is running
You are running with subclassing enabled and there are a number of known issues with it. First, start off by reading this page about enhancing your entities. It shouldn't take more than than a few minutes and in the long run you'll be a much happier camper. The net of that link is that you need to set the following property and use another method of enhancement.
<openjpa.RuntimeUnenhancedClasses=unsupported/>
If this doesn't get you going, you'll need to post your Entity for more clues as to what is going on.
-Rick
An optimistic locking exception happens if you try to update a record which was updated by someone/thing else since you loaded it. This does not require multiple threads to happen.
You should be able to resolve the issue be reloading the entity just before modifying and saving it.
---- update to answer the question ---
The secure way to do it would be to close the Session and use load or get, and make sure you don't change the version attribute (assuming you have such a thing)
Often this is not what you want to do, and if you work only with on thread you entity in the session should be current. So maybe just making sure you don't change the version when merging is enough: load or get the entity from the session, store the version in a variable, perform a merge, reset the version and flush/commit might work.
If it doesn't I need more information, about what you are actually doing.
I am getting this exception in a controller of a web application based on spring framework using hibernate. I have tried many ways to counter this but could not resolve it.
In the controller's method, handleRequestInternal, there are calls made to the database mainly for 'read', unless its a submit action.
I have been using, Spring's Session but moved to getHibernateTemplate() and the problem still remains.
basically, this the second call to the database throws this exception. That is:
1) getEquipmentsByNumber(number) { firstly an equipment is fetched from the DB based on the 'number', which has a list of properties and each property has a list of values. I loop through those values (primitive objects Strings) to read in to variables)
2) getMaterialById(id) {fetches materials based on id}
I do understand that the second call, most probably, is making the session to "flush", but I am only 'reading' objects, then why does the second call throws the stale object state exception on the Equipment property if there is nothing changed?
I cannot clear the cache after the call since it causes LazyExceptions on objects that I pass to the view.
I have read this:
https://forums.hibernate.org/viewtopic.php?f=1&t=996355&start=0
but could not solve the problem based on the suggestions provided.
How can I solve this issue? Any ideas and thoughts are appreciated.
UPDATE:
What I just tested is that in the function getEquipmentsByNumber() after reading the variables from list of properties, I do this: getHibernateTemplate().flush(); and now the exception is on this line rather then the call to fetch material (that is getMaterialById(id)).
UPDATE:
Before explicitly calling flush, I am removing the object from session cache so that no stale object remains in the cache.
getHibernateTemplate().evict(equipment);
getHibernateTemplate().flush();
OK, so now the problem has moved to the next fetch from DB after I did this. I suppose I have to label the methods as synchronized and evict the Objects as soon as I am finished reading their contents! it doesn't sound very good.
UPDATE:
Made the handleRequestInternal method "synchronized". The error disappeared. Ofcourse, not the best solution, but what to do!
Tried in handleRequestInternal to close the current session and open a new one. But it would cause other parts of the app not to work properly. Tried to use ThreadLocal that did not work either.
You're mis-using Hibernate in some way that causes it to think you're updating or deleting objects from the database.
That's why calling flush() is throwing an exception.
One possibility: you're incorrectly "sharing" Session or Entities, via member field(s) of your servlet or controller. This is the main reason 'synchronized' would change your error symptoms.. Short solution: don't ever do this. Sessions and Entities shouldn't & don't work this way -- each Request should get processed independently.
Another possibility: unsaved-value defaults to 0 for "int" PK fields. You may be able to type these as "Integer" instead, if you really want to use 0 as a valid PK value.
Third suggestion: use Hibernate Session explicitly, learn to write simple correct code that works, then load the Java source for Hibernate/ Spring libraries so you can read & understand what these libraries are actually doing for you.
I also have been struggling with this exception, but when it continued to recur even when I put a lock on the object (and in a test environment, where I knew I was the only process touching the object), I decided to give the parenthetical in the stack trace its due consideration.
org.hibernate.StaleObjectStateException: Row was updated or deleted by
another transaction (or unsaved-value mapping was incorrect):
[com.rc.model.mexp.MerchantAccount#59132]
In our case it turned out that the mapping was wrong; we had type="text" in the mapping for one field that was a mediumtext type in the database, and it seems that Hibernate really hates that, at least under certain circumstances. We removed the type specification altogether from the mapping for this field, and the problem was resolved.
Now the weird thing is that in our production environment, with the supposedly problematic mapping in place, we do NOT get this exception. Does anybody have any idea why this might be? We are using the same version of MySQL - "5.0.22-log" (I don't know what the "-log" means) - in dev and production envs.
Here are 3 possibilities (as I do not know exactly, which kind of hibernate session handling you are using). Add one after another and test:
Use bi-directional mapping with inverse=true between parent object and child object, so the change in parent or child will get propagate to the other end of relation properly.
Add support for Optimistic Locking using TimeStamp or Version column
Use join query to fetch the whole object graph [ parent+children] together to avoid the second call altogether.
Lastly, if and only if nothing works:
Load the parent again by Id (you have that already) and populate modified data then update.
Life will be good! :)
This problem was something that I had experienced and was quite frustrating, although there has to be something a little odd going on in your DAO/Hibernate calls, because if you're doing a lookup by ID there is no reason to get a stale state, since that is just a simple lookup for an object.
First, make sure all your methods are annotated with #Transaction(required=true) // you'll have to look up the exact syntax
However, this exception is usually thrown when you try to make changes to an object that has been detached from the session it was retrieved from. The solution to this is often not simple and would require more code posted so we can see exactly what is going on; my general suggestion would be to create a #Service that performs these kinds of things within a single transaction