Code is shared in github. Situation looks like this I have opened Transaction. I create ExampleEntity and ExampleChildEntity. They are connected by bidirectional reference. Steps which i take:
ExampleEntity.setChild(child);
saveAndFlush() // insert goes to db
ExampleEntity.setChild(null)
saveAndFlush() // delete goes to db
ExampleEntity.setChild(child)
saveAndFlush() // insert goes to db
ExampleEntity.setChild(null)
saveAndFlush() // no delete here
I tagged hibernate because I think it's Hibernate problem (I'm using spring data jpa) because when I switch JPA provider to EclipseLink everything goes well. Am I doing something wrong or it's a bug? I have tried setting child reference to parent to null but this does not work also. Example project:
https://github.com/pustypawel/delete-twice-bug
Related
I use spring data and hibernate. I have an Entity (TestEntity). I made a custom hibernate type that deserializes one String field to two columns.
If I persist an entity and then change it everything works fine and hibernate sends update query (it makes my type work and update query to DB "splits" my old column to two new).
But my goal is to make this king of migration for every record. I can't use an ordinary DB migration because there is some logic in my custom type.
I want to make something like this:
// here I persist all my entities
List<TestEntity> entities = entityRepository.findAll();
for (TestEntity entity : entities) {
// This piece of code does nothing, because when hibernate merges two entities, it understands, that nothing changed, so it won't send update query.
entityRepository.save(entity);
}
But I want him to send update query, although nothing has changed. Moreover, I want this hibernate behaviour to be in one place only (for example, I will create controller to execute this DB update). What is a solution to my problem? Is there any approach to its solving?
I don't understand why you need it but you need to detach the entity from the session for this to work.
As far as I understand, you need the EntityManger:
#PersistenceContext
private EntityManager entityManager;
...
List<TestEntity> entities = entityRepository.findAll();
for (TestEntity entity : entities) {
entityManager.detach(entity);
entityRepository.save(entity); // or entityManager.unwrap(Session.class).saveOrUpdate();
}
See Spring JpaRepository - Detach and Attach entity
Thanks for reading this in advance.
I use Spring data JPA to query data from DB:
UserProfile userProfile = userProfileRepository.findByCustomerID(id);
After the data returned I want to change some value to some field:
userProfile.setRemark("some remark");
However, I notice that Spring will automatically update the database of this record which I don't want, as this field is just a temp value for some further processing.
May I know how can I let Spring data JPA to kinda "ignore" or "drop" this entity from the managed pool? I found someone said to use:
entityManager.clear();
And tested it definitely will not update the database if this one is called. But I am not sure if this is the correct way to do so, does entityManager.clear(); will clear other managed entities as well?
Many thanks.
The entity I'm trying to save is a parent and child. When I save the entity (i.e. the parent and children saved at the same time), however with normal execution (in debug mode every time) I get a HibernateOptimisticLockingFailureException thrown during session flushing. The testing is on my local machine, single thread, and nobody is changing the entity as I'm also saving it.
We are using the following:
MySQL v5.5.x
Hibernate 4.3.11
Java 8
Spring 4.1.0
Key points:
The relationship between the parent and child is bi-directional one-to-many.
We use optimistic locking with the version column being a timestamp created by MySQL either during insert or during update. On the version field we specify #Generated(GenerationTime.ALWAYS) to ensure that the version details are obtained from the database automatically (avoid the time precision issue between Java and MySQL)
During saving a new entity (id = 0), I can see the logs that the entity is being inserted into the database, I can also see the child entities being inserted in the database (via the Hibernate logs). During this process, I can also see the a select is done to get the version details from the database.
Soon after the entities are inserted and the session is being flushed, there is a dirty checking is done on the collection and I see a message in the log that the collection is unreferenced. Straight after this, I see an update statement on the parent entity's table and this is where the problem occurs as the version value used in the update statement is different to what is in the database, the HibernateOptimisticLockingFailureException exception is thrown.
Hibernate Code
getHibernateTemplate().saveOrUpdate(parentEntity);
// a break point here and wait for 1 sec before executing
// always get the HibernateOptimisticLockingFailureException
getHibernateTemplate().flush();
Parent mapping
#Access(AccessType.FIELD)
#OneToMany(mappedBy="servicePoint", fetch=FetchType.EAGER, cascade={CascadeType.ALL}, orphanRemoval=true, targetEntity=ServicingMeter.class)
private List<ServicingMeter> meters = new ArrayList<ServicingMeter>();
Child mapping
#Access(AccessType.FIELD)
#ManyToOne(fetch=FetchType.EAGER, targetEntity=ServicePoint.class)
#JoinColumn(name="service_point_id", nullable=false)
private ServicePoint servicePoint;
Questions:
1. Why is there an update date on the parent table?
2. How can I avoid this update from happening?
3. Is there something wrong with the way my one-to-many mapping is setup?
The annotated log file can be found here
I'm using JBoss 7.1.1 and the default implementation of Hibernate that comes with it (4.0.1).
I have a message driven bean, that in the same transaction creates an entity and persists it using the entity manager. After that (still the same transaction) I find the newly created entity and try to use the entity manager to lock it with PESSIMISTIC_WRITE, but I get an OptimisticLockException. Its root is as follows:
Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [some.package.name.EntityName#aaa1a1a0-d568-11e1-9f99-d5a00a0a12b6]
at org.hibernate.dialect.lock.PessimisticWriteSelectLockingStrategy.lock(PessimisticWriteSelectLockingStrategy.java:95)
at org.hibernate.persister.entity.AbstractEntityPersister.lock(AbstractEntityPersister.java:1785)
at org.hibernate.event.internal.AbstractLockUpgradeEventListener.upgradeLock(AbstractLockUpgradeEventListener.java:99)
at org.hibernate.event.internal.DefaultLockEventListener.onLock(DefaultLockEventListener.java:85)
at org.hibernate.internal.SessionImpl.fireLock(SessionImpl.java:693)
at org.hibernate.internal.SessionImpl.fireLock(SessionImpl.java:686)
at org.hibernate.internal.SessionImpl.access$1100(SessionImpl.java:160)
at org.hibernate.internal.SessionImpl$LockRequestImpl.lock(SessionImpl.java:2164)
at org.hibernate.ejb.AbstractEntityManagerImpl.lock(AbstractEntityManagerImpl.java:1093)
... 202 more
Any ideas why I can't look up the newly created entity? Also, how can I make it available for searching right after it is created? Using the merge method of the EM doesn't seem to help ...
My understanding of your question is that within your message driven bean's transaction you're doing the following:
1. Create entityA
2. Persist entityA
3. entityB = find entityA
4. lock(entityB, PESSIMISTIC_WRITE)
and step 4 is throwing an exception.
I think Hibernate may not have flushed the persist between 2 and 3 so at that point A (and B) have version 0. Hibernate is then flushing the persist of A at the start of the lock(), which means B now has a stale version.
You could try flushing the persist before the find (so entityManager.flush() after 2).
Or you should be able to skip the find, since entityManager.persist(entityA) makes entityA a managed object, so the following sequence may work:
1. Create entityA
2. Persist entityA
3. lock(entityA, PESSIMISTIC_WRITE)
I have problems updating entities in Googles App Engine.
EntityManager em = ... // constructed like in the doc
MyEntity myE = new MyEntity();
myE.setType("1"); // String
em.persist(myE);em.refresh(myE);
myE.setType("2");
em.merge(myE);em.refresh(myE);
I expect a entity with type="2", but there is only one entity with type="1" :-(
That's the correct behaviour, let me explain (I assume that all your code runs in the same persistence context / transaction).
# This line sets the value in the in-memory object without changing the database
myE.setType("2");
# this line doesn't do anything here, as the entity is already managed in the current
# persistence context. The important thing to note is that merge() doesn't save the
# entity to the DB.
em.merge(myE);
# This reloads the entity from the DB discarding all the in-memory changes.
em.refresh(myE);
It's because merge creates a new instance of your entity, copies the state from the supplied entity, and makes the new copy managed. You can find more info on merge vs. persist here and a full discussion about it here
I was facing similar issue too. My issue is solved after my put the Reresh() after Commit().
It would be something like:
em.getTransaction().begin();
//Code to update the entity
em.persist(myE);
em.getTransaction().commit();
em.refresh(myE)
This will ensure the updated entity in JPA Cache gets refreshed with the updated data.
Hope this helps.