Spring callback when Entity exits #Transactional context? - spring

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.

Related

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

Hibernate Envers with QueryDSL Update

Hibernate, Hibernate Envers and QueryDSL are configured and working correctly in a Spring boot 1.4.1.RELEASE.
The problem is when using UpdateClause<JPAUpdateClause> updateQueryBuilder = queryFactory.update(collectionTransaction); to build update query and execute that update query, Hibernate Envers does not pick up and audit those changes.
Following is the Spring Data JPA repository that implements QueryDSL
public class CollectionTransactionRepositoryImpl extends QueryDslRepositorySupport implements CollectionTransactionRepositoryCustom {
#Autowired
private JPAQueryFactory queryFactory;
public CollectionTransactionRepositoryImpl() {
super(CollectionTransaction.class);
}
#Override
public Collection<CollectionTransaction> updateCollectionTransaction(UpdateCollectionTransaction updateCollectionTransaction) {
QCollectionTransaction collectionTransaction = QCollectionTransaction.collectionTransaction;
UpdateClause<JPAUpdateClause> updateQueryBuilder = queryFactory.update(collectionTransaction);
.....//Code omitted for brevity
long updated = updateQueryBuilder.execute();
//.....
return ...
}
}
Is it possible for Hibernate Envers to pick up changes in this situation ?
This is a known concern outlined in JIRA HHH-10318.
Envers works based on Hibernate's event subsystem where Hibernate effectively notifies various callbacks that state for an entity has been modified in some way, and provides both the prior and new entity state. This state is precisely what Envers uses to determine what changed and insert audit change rows.
Lets take a trivial example:
UPDATE MyEntity e SET e.status = :status
Hibernate will perform the following tasks:
Flush the persistence context any any modifications.
Invalidate any cached instances of MyEntity.
Execute the bulk update operation.
No where in any of these steps does Hibernate load any existing state. It simply guarantees that current changes are flushed prior to the bulk update and that any subsequent operations will fetch from the datastore rather than a cache due to the bulk update.
Therefore from Envers perspective, it gets no callbacks and thus isn't aware that any operation took place because Hibernate ORM cannot provide any entity state for such an operation, it simply does not exist.
The big question here is how (if possible) to model and handle a change unit for such an operation.
It's difficult because Envers would effectively need some type of PreBulkOpEvent so that it can cache what it needs that is about to change and a PostBulkOpEvent to require and merge the two results to generate change log entries. The concern with such a concept really centers around how to do this effectively to avoid
Running out of memory due to large result-set manipulation.
Long execution time to load state from datastore for large result-set manipulation.
Anyway, you're welcomed to read over the JIRA and provide any feedback or ideas. But presently, its just something that falls outside the scope of what we can capture at the present moment.

Query interceptor for spring-data-mongodb for soft deletions

I want to add where condition to all repository fetching methods for not viewing deleted items. In Spring JPA it's possible to add #Where annotation to Entity. But for Spring Data MongoDB AFAIK it's not possible. Tried Mongodb lifecycle events but not succeeded. Is there a way of modifying repository queries before execution.
Can you explain what do you mean with "viewing deleted items"? If you want, you can use MongoTemplate and write your own repository and so can add desired where condition to every method

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.

Why does #Transactional save automatically to database

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

Resources