Entity can still be selected after deleted by hibernate in transaction - java

I have a method to delete record by hibernate. I add a query after deletion. And the record deleted is still in the result list. It should not be. Here is the code.
#Transactional
public void deleteFoo(long fooId){
Foo foo = fooDao.find(fooId);
fooDao.delete(foor);
List<Foo> brothers = fooDao.findByParentId(foo.getParentId());
// I think the brothers does not contains foo.
// Unfortunately, foo is still in the list.
// I do not know why and how to make sure the brothers does not contains foo.
...
}
The record is deleted from database where the transaction committed.

You should flush the hibernate session.
When your work with database via Hibernate you are using Hibernate session.
Hibernate sessions flushed to the database by following three situations.
commit()- When you commit a transaction
Before you run a query
When you call session.flush()
or you can flush it manually by
session.flush()

Related

Update request to DB even if nothing has changed in Entity

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

Update entity in jpa

How can I update every fields in Entity without write sql query:
(update Entity u set u.m1= ?1, u.m2= ?2, ... where u.id = ?3)
Class has 20+ fields and if I write sql query This will take a long time. And I often add new fields
Can I update everything automatically? Like this:
entityRepo.update(entity);
If i do entityRepo.save(); create unnecessary record in base.
No, you can use JpaRepository.save(S entity) that saves or updates the entity if existing.
To achieve that, make sure that the entity has its JPA #Id valued before invoking save() otherwise a new record will indeed be created.
This is an alternative to #davidxxx's answer.
If the transaction with which the entity was fetched is not yet closed (i.e. the entity is still attached), you can simply update the java-object and the changes will be committed to the database when the transaction is committed.

Saving the entity outside the transaction

I have the below code which tries to save the entity outside the transaction:
Session session = HibernateUtil.buildSessionFactory().openSession();
Teacher t= new Teacher();
t.setName("jonathan");
session.save(t);
session.flush();
According to the definition of save() if used outside the transaction we need to do flush() to save the entity in the db.However the above code does not save it. I have to create a transaction and commit it in order to add a row in db. Why is this so?
I am using HIbernate 4.3.6
EDIT: I just noticed that the session.save() returns the id but only after transaction.commit() the row is added.The other question does not answer my question.Since this basically means that save() in order to add the row in db has to be in a transaction only

How does detach work in a Transactional method on persisted entity

I have a Transactional method, inside it an entity is instantiated and inserted in the Hibernate context using persist method. Then some properties of the entity are changed (so it will be reflected in the database). What will happen if detach method is called on the entity and then some properties of the entity are changed. When the method finishes (and transaction commits), will Hibernate insert the entity and update the attributes to the point before the detach call?
For example:
#Transactional
public void transactionalMethod(){
MyEntity entity = new MyEntity();
getEntityManager().persist(entity);
entity.setAttribute1(data1);
entity.setAttribute2(data2);
getEntityManager().detach(entity);
entity.setAttribute3(data3);
}
Well, I'm answearing my own question for people having a similar question.
When using Spring Transactional method, all the inserts will be commited at the end of the transaction. If you use detach on an entity, all the updates (before or after detach) will be discarted, so no commits of updates will be done when transaction finishes.
If you want to reattach an entity to Persistence Context, you can do a merge or update method on the entity, then all changes to the entity will be commited when transaction finishes.
Hope this helps.

EntityManager unwanted background commit

I have a strange problem on one of my glassfish server. Have a look on this piece of code:
userTransaction.begin();
MyEntity entity = new MyEntity(12345);
//setting values..
entityManager.persist(entity);
MyEntity persistedEntity = entityManager.createQuery("SELECT p FROM MyEntity p WHERE p.idpk=12345").getSingleResult();
//...
userTransaction.commit(); //OK => the tuple is in the DB
Now there is a business problem and the transaction needs to be rollbacked.
userTransaction.begin();
MyEntity entity = new MyEntity(12345);
//setting values..
entityManager.persist(entity);
MyEntity persistedEntity = entityManager.createQuery("SELECT p FROM MyEntity p WHERE p.idpk=12345").getSingleResult();
//...
//Business problem => rollback
userTransaction.rollback(); //ERROR => the tuple 12345 is in the DB !
Even if the rollback seems to work (no exception raised or strange log output), the tuple has been committed in the database...
To search where the problem is, I tried the following code:
userTransaction.begin();
MyEntity entity = new MyEntity(12345);
//setting values..
entityManager.persist(entity);
//Business problem => rollback
userTransaction.rollback(); //OK => the tuple 12345 is NOT in the DB !
With this code (the entity is not retrieved), the tuple is not committed to the database, which is the correct behaviour. Let's go further:
userTransaction.begin();
MyEntity entity = new MyEntity(12345);
//setting values..
entityManager.persist(entity);
MyEntity persisted = entityManager.find(MyEntity.class, 12345);
//...
//Business problem => rollback
userTransaction.rollback(); //OK => the tuple 12345 is NOT in DB
In this last case, the result is still correct and there is no tuple committed to the database. It seems the EntityManager makes a magic [unwanted] commit when retrieving the entity with a query...
I also tried to make a query on another table and that doesn't cause the wrong commit (the rollback works). Moreover, I tried to reproduce the problem on my own server, and there is no problem: all the rollbacks work correctly. Hence, it should really be a server configuration problem.
For information, it is a glassfish v2.1.1 running on linux. The EntityManager is in FlushModeType.AUTO.
Does anyone have an idea ?
Thanks & best regards !
Found some discussion which seems to explain some of what you're seeing:
Via P-331 of EJB3 In Action Book:
By default, the database flush mode is set to AUTO. This means that
the Entity-Manager performs a flush operation automatically as needed.
In general, this occurs at the end of a transaction for
transaction-scoped EntityManagers and when the persistence context is
closed for application-managed or extendedscope EntityManagers. In
addition, if entities with pending changes are used in a query, the
persistence provider will flush changes to the database before
executing the query. If the flush mode is set to COMMIT, the
persistence provider will only synchronize with the database when the
transaction commits. However, you should be careful with this, as it
will be your responsibility to synchronize entity state with the
database before executing a query. If you don’t do this and an
EntityManager query returns stale entities from the database, the
application can wind up in an inconsistent state.
P-353 EJB3 In Action Book states:
If the Query is set to FlushModeType.COMMIT, the effect of updates
made to entities in the persistence context is not defined by the
specification, and the actual behavior is implementation specific.
Perhaps try toggling the flush mode on the query returned by
entityManager.createQuery("SELECT p FROM MyEntity p WHERE p.idpk=12345").getSingleResult();
or on the entity manager itself and see if that changes anything?
Some further discussion here:
http://www.coderanch.com/t/475041/ORM/databases/EntityManager-setFlushMode-COMMIT-Vs-Query
Why not do this:
MyEntity persisted = entityManager.persist(entity);
I finally found where was the problem: in the JDBC Connection Pool, there is a section "Transaction" where the option "Non Transactional Connections" was enabled... Simply removing this option made the whole thing work :)

Categories