Why does #Transactional save automatically to database - spring

I have a method annotated with #Transactional. I retrieve an object from my DB, change a field, and then return from the method. Without saving my object, the database gets updated anyway which is strange.
Could you please tell me how to avoid this beahvior?

This behaviour is one of the main purposes of transactionality.
Before the transactional method is about to return, the transaction commits, meaning all changes to the managed entities are flushed to the database.
If an error occurs, the transaction will be rolled back, meaning that no changes will be committed to the database.
You are probably getting the LazyInitializationException when trying to access a lazily loaded property, probably a collection from an entity. Lazily loded properties do not get instantiated when you fetch an entitiy from DB.
If you access a lazily loaded property in a transaction, the persistence provider will create a query, instantiate the result and attach it to the 'parent' entity.
EDIT: If you want to have the lazy properties loaded AND be able to change your entity without the changes being persisted to the DB, you can fetch the entity with fetch joins for the lazy properties.
em.createQuery("SELECT e FROM MyEntity e JOIN FETCH e.lazyProp");
Then proceed with one of the methods described by #orid.
If you are not using fetch joins, you will need to access the lazily loaded properties while still inside the transaction:
myEntity.getLazyProp().size();
Note the call to size(). Calling the getter is not enough as you will get a proxy. You need to perform an operation that needs the actual data from the property.

This a normal JPA behavior.
Once you retrieve an object via find() or so, that object is regarded as attached, or belongs to a persistence context. Once you exit the method the #Transactional triggers a Spring transaction management aspect which flushes every "dirty" object to database and commits the transaction. Since your object is already changed within the context of the persistence context and the transaction, the changes are saved to the database even without the need to explicitly call a save method.
If you want to change your object without affecting the database, you have two options:
Update the field after returning from the method annotated with #Transactional
If withing the method, call detach on the entity manager

Related

How to get updated objects after flush() in the same transaction (Hibernate/ Spring boot)

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

Best way to update the entity object from DTO object using Hibernate and Spring

First to explain the context. I have backend Java (Spring/Hibernate) application that is accessible via Rest client.
Problem: Since API is exposed as RestApi, I get the DTO object from the client with ID of the entity which needs to be updated.
Current approach: I am getting the entity from DB based on the ID, and detaching it from persistent context, converting DTO object to entity object,
then sending it to DAO, where again I am fetching the entity from DB (as DAO can be called directly by other internal classes) then again detaching it and later merge operations get called.
So for every update call hibernate will fire 3 select statement and 1 update statement. Is there any way I can reduce the number of the select calls.
if all your queries are done in the same session, hibernate shouldn't load the entities again for every request to the repository, just use the #Transactional annotation on your service classes
https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction-declarative-annotations
another aproach is to use hibernates second level cache:
https://docs.jboss.org/hibernate/orm/5.3/userguide/html_single/chapters/caching/Caching.html
http://www.baeldung.com/hibernate-second-level-cache

Spring Transaction propagation: can't get the #OneToMany related entities when using the same transaction for creation and consultation operation

I have the following problem: I am working on a spring-boot application which offers REST services and use a relational (SQL) database using spring-data-jpa.
I have two REST services:
- a entity-creation service, which create the child-entity, the parent-entity and associate them in a same transaction. When this service ends, the data are committed into the database.
- an entity consultation service, which get back the parent-entity with its children
These two services are annotated with the #Transactional annotation. It production case, it works well: I can create an parent-entity with its children in one transaction (which is commited/ended), and get it in another transaction latter.
The problem is when I want to create integration-tests. My idea was to annotate each test with the #Transactional annotation, and do a rollback after each test. This way I keep my database clean between each test, and I don't have a generate the schema again or clean all the records in the database.
The integration test consists in creating a parent and its children and then reading it, everything in one transaction (as the test is annotated with #Transaction). When reading the entity previously created in the same transaction, I can get the parent entity, but the children are not fetched (null value). I am not sure to understand very well the transaction mechanism: I was thinking that using the #Transactional on the test method, the services (annotated with "#Transactional") invoked by this test should detect and use the same transaction opened by the test method (the propagation is configured to "REQUIRED"). Hence as the transaction uses the same EntityManager, this one should be able to return the relation between the parent entity and its children created previously in the same transaction, even if the data has not been committed to the database. The strange thing is that it retrieve the parent entity (which has not been yet committed into the database), but not its children. Is my understanding of the transaction concept correct? If not, could someone explains me what am I missing?
Also, if someone did something similar, could he explain me how he did it please?
My code is quite complex. I first want to know if I understand well how are transaction managed and if someone already did something similar. If really it is required, I can send more information about my implementation (how the transaction-manager and the entity-manager are initialized, the JPA entities, the services etc...)
Binding the Entity-manager in my test and calling its flush method from my test,between the creation and the reading, the reading operation works well: I get the parent entity with its children. But the data are written into the database during the creation to read it latter during the read operation. And I don't want the transaction to be committed as I need my test to work on an empty database. My misunderstanding is not so much about the Transaction mechanism, but more about the entity-manager: it does not keep as a cache the entities created and theirs relations...
This post help me.
Issue with #Transactional annotations in Spring JPA
As a final word, I am thinking about calling an SQL script before each test to empty my database.

Object from a different session - saveOrUpdate in another session?

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.

Spring callback when Entity exits #Transactional context?

Does Spring have any hooks to call a method on an entity or an entity listener for each entity at the exit of a transactional context?
We're using Spring and Hibernate to manage a bunch of entities that we also index for searching. We currently use an entity listener with Hibernate's #PreUpdate method to perform a reindex when an entity is created or modified. Of course, this event only fires when one or more of the entity's own properties (i.e., values in its database row) is updated.
The problem occurs when an entity has a #OneToMany mapping for non-trivial child properties. When one of those child properties is updated, the PreUpdate callback is not called on the parent entity.
We already track when properties are updated, but we want to wait until all updates are
complete before triggering a reindex. What is the best place to put such a reindex call? PreUpdate works well for most cases, but this wrinkle led me to wonder if there was a hook for when an entity leaves a #Transactional scope. Alternatively, is there a Hibernate way to trigger a callback on the parent when a OneToMany child is persisted?
i think aspect is for rescue. have a look section 10.5.8 Advising transactional operations Advising transactional operations in spring documentation this will help you to write aspect around #Transactional method and then you do indexing.

Resources