In a Spring Boot #Transactional Class, how to perform commits to different repositories after changes to the Hibernate DAO object in between commits? - spring

I need to do the following in my #Transactional Class
Do changes to data (empty logs field) inside a DAO object and save to PostGresql DB
Revert the changes and save to ElasticSearch (with the id generated in the same DAO object from first commit return result).
Here is how the code is
emptylogsField(testCaseResponses); //Data modifications
Iterable<TestCaseResponse> result =
PGRepository.saveAll(converter.convertToEntities(testCaseResponses));
PGRepository.flush();
putBackLogs(result); // Data modifications
result = ESRepository.saveAll(result);
The problem is the same data is getting saved in both repositories. The flush() is not working? Please help.

Related

#cachePut for data update in list of object in spring boot

Hi I am using Spring Boot Cache in my application. I am able to fetch data from db and cached that data.
#Cacheable("employee")
public Optional<List<Employee>> employeeData(){
log.info("Fetched employee details from DB and cached in memory!!");
return employeeRepository.findActiveEmployee();
}
I want to delete or update or add new record in cached object.
How can I use #cachePut to update existing record or insert record or delete existing record based on some condition.
You can keep your original method as is to call it whenever you want to fetch data from cache. Note that the #Cacheable annotation does not execute the method's body if the cache with name "employee" is not empty, instead it returns the results from cache.
#Cacheable("employee")
public Optional<List<Employee>> employeeData(){
}
Then proceed in creating a new method annotated with #CachePut. Having in mind that #CachePut annotation will both execute the method as well as cache the results each and every time:
#CachePut(value="employee", condition="#name=='Tom'")
public Optional<List<Employee>> employeeDataCacheByName(String name){
log.info("Fetched employee details from DB and cached in memory depending on condition!!");
return employeeRepository.findActiveEmployee();
}
The above method will run the query every time and put into employee cache the results if the name argument is "Tom" (condition logic is up to you, this is just an example). This way cache is always updated with the results from the database (as long as the condition is truly evaluated).
For deleting (I don't think #CachePut can be used) maybe you can combine the #CacheEvict annotation, you can see an example in this Answer: https://stackoverflow.com/a/62488344/3635454

How to actualize entity in Spring JPA? Actualize or create new one?

I'm wondering what is best practice to update JPA entity in Spring project - update original entity or create new? I see these two approaches:
Use original - Actualize necessary fields in original entity and save this updated entity back to the repository.
Use copy - manually create new instance of entity, set all field from original entity (+ updated fields) into new entity and save the entity back to the repository.
What approach do you use / is recommended? And why?
When it comes to updating, the standard way would be to retrieve the entity reference(read below) and make changes within a transactional method:
private JpaRepository repo;
#Transactional(readOnly = false)
public void performChanges(Integer id){
Entity e = repo.getOne(id);
// alter the entity object
}
Few things regarding the example:
You would want to use the getOne method of JpaRepository as much as possible as it is in general faster than the findOne of the CrudRepository. The only trick is that you have to be sure that entity actually exists in the database with the given id. Otherwise you would get an exception. This does not occur regarding the findOne method so you would need to make that decision regarding each transactional method which alters a single entity within your application.
You do not need to trigger any persist or save methods on the EntityManager as the changes will be automatically flushed when the transaction is commited.. and that is on method return.
Regarding your second option, I dont think thats much of a use as you would need to get the data using above method anyway. If you intend to use that entity outside of the transaction, then again you could use the one retrieved from the exmaple above and then perform merge once it is again needed within the transactional context and thus Persistence Provider.
Getting an entity and then just updating that entity is the easiest way to do that. Also this is faster than a creation of a copy since EntityManager manages an entity and know that managed entity already exists in DB (so no need to execute additional query).
Anyway, there is third and the fastest approach: using executeUpdate on Query object.
entityManager
.createQuery("update EntityName set fieldName = :fieldName where id = :id")
.setParameter("fieldName", "test")
.setParameter("id", id)
.executeUpdate();
It is faster due to bypassing the persistent context

HibernateDAOSupport Get method

I am working on a existing project which uses Hibernate and Spring. I see a following code which uses HibernateDAOSupport class,
Employee emp = getHibernateTemplate().get(Emplyee.class, 1001)
After the above line we set some property like emp.setAge(25); and at the end we don't call any Save or SaveOrUpdate method. But it's saving the data to DB. How is it possible ?
If it can Save then what is the difference between getHibernateTemplate().get() and getHibernateTemplate().save/SaveOrUpdate methods ?
This is expected behaviour of Hibernate and it is because the Employee entity is loaded into the PersistenceContext and therefore enters the 'persistent' entity lifecycle state.
When you commit the transaction, Hibernate will check any 'persistent' entities within the PersistenceContext to see if they are "dirty". Dirty means that any values of the entity have changed. Your call to emp.setAge(25) means that Hibernate understands that data within the entity has changed (it is dirty), and it should therefore make the changes persistent when the transaction commits.
It is worth reading and understanding how Hibernate manages entity states as it can be a little confusing to start with. The documentation is here.

Get original object property stored in DB with Hibernate in same transaction

I opened hibernate transaction and read the object. I changed some properties of object without store. I want to get the original properties stored in DB but with
Criteria cr = new Criteria(...);
cr.add(Restrictions.eq("id", id));
cr.setProjection(Projections.property("someProperty"));
cr.uniqueResult();
or reload whole object with getSession().get(id). But as a result I got changed properties and if I reload whole object I got the same instance of changed object. How to get original object properties stored in DB with same transaction, changed object must remain with changed properties.
And how to do it with Spring transaction annotations?
You can use session.refresh() method. See documentation: http://docs.jboss.org/hibernate/orm/4.1/manual/en-US/html_single/#objectstate-loading
But this will overwrite any changes. You can clone the object before refresh, i think.

Spring Transactional annotation, Hibernate and persist

I've a misunderstanding of Spring #Transactional annotation and persist. I am using Spring 3.1, with JPA and Hibernate. I thought that persist meant, add the entity to the persistence context (but don't execute any query until commit or flush), and that the #Transactional annotation meant, wrap the method with a transaction.
However, in this short example, when the execution pointer reaches persist, it fails with an exception, since name can't be null (db constraint).
import javax.persistence.EntityManager;
#PersistenceContext
private EntityManager entityManager;
#Transactional
public void test() {
Brand brand = new Brand();
entityManager.persist(brand);
brand.setName("test");
}
If I swap setName() and persist(), everything works. However, I don't understand why the other way around doesn't since I thought that any query would be built and executed at the end of the method.
Can someone please explain?
In JPA, once an object passed to persist() it becomes "managed", as part of becoming managed JPA implementation must generate an id for the persistent object.
If id generation is based on auto-increment (GenerationType.IDENTITY), then an insert statement needs to be issued to the db to get and assign the key. When the id generation is based on sequence / table then ids are managed and assigne by the JPA Implementation managed id pools, in which case a straight insert is not a requirement.
Having an object is passed to persist() and has become managed, any changes to it is persistent fields must be flushed to the database at the and of the transaction. In your case if the id generation is Identity then an insert must be followed an update. If the id generation is some other method then, a single insert statement is sufficient. If the transaction is rolled back, no SQL should be get sent to database at all.
This is the implementation in Batoo JPA.
Hope this makes sense.
Its committed at end of method thanks to transactional annotation. But the new record is created on persist, and any exceptions can be thrown.
Before the end of method it can still be rolled back; I normally annotate with rollback for exception.
The persist executes the "insert" query. The transacation annotation is just for starting a transaction and if a exception occurs roll back the transaction.

Resources