How does Spring-data handle/retrieve data populated by triggers and not by itself? - spring

I have a problem with Spring Data + MySQL triggers.
Currently, before a new row is inserted in a table, a MySQL trigger assigns data to specific columns:
Table User
Columns created_at and updated_at
Those columns are mapped as follow:
#Column(name = "created_at")
private Date createdAt;
#Column(name = "updated_at")
private Date updatedAt;
Likewise, I have a service (annotated as #Transactional) which populates with data the instance User but created_at and updated_at, I mean, when I'm calling save for the userRepository those attributes go as nulls.
MySQL before to insert (trigger) into DB, both attributes are populated with the MySQL function utc_timestamp().
My problem:
Just after I call the service saveUSer, I'm calling findById from the repository. Why both attributes created_at and updated_at has null value in the instance (in db they have values)?

After saving an user , the instance will be cached inside the EntityManager. If the call of findById is still in the same transaction that is used to save the user , it will just return that user instance that is cached inside the EntityManager which the createdAt and updatedAt are null.
In JPA , we can call entityManager.refresh(user) to force selecting that user from the DB such that the user instance managed by JPA will have the latest values as the DB record. So you can use entityManager.refresh(user) after saving the user to ensure the latest value of createdAt and updatedAt are updated back to the user instance managed by JPA.
However , Spring data 's JPA repository does not expose EntityManager 's refresh, you can extend it like this.

The other answer quite accurate, however it assumes you call saveUser and findById from inside an a transaction.
However when you use Spring Data JPA under Spring Boot this issue could happen even if you are out of a transaction.
Spring Boot has a default setting which automatically encapsulates each request in a transaction.
So, if you use Spring Boot it would worth a try to add the following line to the application.properties:
spring.jpa.open-in-view=false

Related

Is using #Entity annotation in Spring boot JPA creates a table?

BACKGROUND
I am new to developing API in spring boot. I have this project wherein it is connected to an Oracle DB and PostgreSQL. The Oracle DB already have an existing tables and I need to fetch some data from multiple tables and send it back as a response. The Postgres DB is where I store the users data and other some data that doesn't need to be stored in the Oracle DB. I am currently using native queries.
The Account is an entity wherein I just marked one of the columns as the #Id (It is actually not an Id but it is unique for all accounts):
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
public class Account {
#Id
private String sampleProperty1;
private String sampleProperty2;
private String sampleProperty3;
private String sampleProperty4;
private String sampleProperty5;
}
Now I have a repository interface:
public interface IAccountRepository extends JpaRepository<Account, String> {
#Query(value = "SELECT * FROM TABLE(SAMPLE_PACKAGE.SAMPLE_FUNC_GETACCOUNTS(?1))", nativeQuery = true)
List<Account> getAllAccountsByClientNumber(String clientNumber);
}
I was able to fetch the data and JPA mapped the columns automatically to my entity. Basically I am creating an Entity (Spring boot) for the data in my Oracle DB where the only purpose of it is to map the data and send it back to the user.
QUESTIONS
Will this approach create a table in my Oracle DB? I checked the Oracle DB and there is no table. But I'm worried it might somehow create a table of ACCOUNT in the oracle DB when it is on production. If this might happen, how can I prevent it?
This scenario also applies to other functionality like fetching transaction history, creating transaction, updating the Account data that are all in the Oracle DB. Am I doing it just right or there is a better option?
Is creating an Entity without a corresponding table have a drawback in Spring boot?
Note
I know you might say that I should just use the Oracle DB and create entities based on the existing tables. But in the future of the API, it will not have a connection with the Oracle DB. I already tried using projections it was also good, but I still needed to create a Response model and mapped it then send it back to user and creating a unit tests using the projection is pretty long and it sucks haha
You can set the following property:
spring.jpa.hibernate.ddl-auto=update
update will update your database if database tables are already created and will create if database tables are not created.

Is it necessary to use Entity annotation for Select query records from Database

I have spring boot application with JPA and MySQL. The table is already created and data are present. From the spring boot application, we need to create two API - get a particular record using id and get all the records. I created a model class but confused with usage of #Entity. Because I'm not going to insert/delete a record from the database. I want to use only for select the record.
For Select query (findBy), do we need to use #Entity annotation at the top of model class?
Yes, you would need to use #Entity to mark your model class, this tells JPA that your class is used for mapping to and from a database table. If you want to make sure that you don't accidentally overwrite the data, you could implement a check via #EntityListener, as described in this answer.

Optimistic locking - session based locking

I have a question related to optimistic locking in Spring/Hibernate actually.
I have following scenario with typical REST application with SQL database.
User A enters page and reads data - version 0 of entity - GET request
User B enters page and reads data - version 0 of entity - GET request
User A saves data - version 1 of entity - PUT request
User B wants to save data (PUT request), but I should see optimistic lock exception
Now my question:
Where hibernate saves data about entity version? I understand the situation when everything is in the same transaction:
Load data
Someone changed entity in the different transaction
Save data
But in my situation version will vanish GET and PUT are in totally different transaction/threads etc.
In my opinion I should save somewhere version loaded by the user to have correlation between GET and PUT requests e.g. in HTTP session or just return version in the response and then send that version in the PUT request.
Can it be done in the better way? Like out of the box?
JPA/Hibernate have #Version column in entity definition to check optimistic or pessimistic lockings. JPA/Hibernate saves versions in the table. For example you have Country table in db:
CREATE TABLE country (
id BIGINT NOT NULL AUTO_INCREMENT,
version BIGINT DEFAULT 0,
...
);
And Country entity:
#Entity
#Table(name = "country")
public class Country implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#Version
#Column(name = "version")
private Long version;
...
}
If you update the country entity instances with optimistic lock conflicts, you get OptimisticLockException in JPA. You don't need to manage the versions, JPA/Hibernate checks the versions of entity instances for you.
Update for different transactions:
In different transactions you can get OptimisticLockException too because JPA/Hibernate checks in every update the version columns with database table. As long as you save your changes (commit), another changes of entity versions will be checked, doesn't matter whether in the same transaction or different transaction. Better you can manage your transactions with #Transactional annotation in Spring framework.

Spring data JPA with H2 database not returning non-merged data

I have an entity with created_date (updateable = false) and updated_date fields. I have #PreUpdate method where I change the updated_date value only (not change created_date), and #PrePersist method which sets new created_date and updated_date values. On Persist the created_date and updated_date are rightly persisted and the returned entity has the correct values. When I pass in the entity to merge, it rightly updates the updated_date (#PreUpdate), and I don't pass the created_date in input. In the database the right updated_date value is updated and created_date value is not changed rightly. But the returned entity has the created_date value set to null. Any Ideas why? Shouldn't the merged entity return the full entity loaded from the database?
Thanks
Sam
I think that is inline with the JPA merge javadoc.
Merge - Merges the state of the given entity into the current persistence context and returns the managed instance that the state was merged to.
(With hibernate as persistence provider) Merge starts with loading the data from the database for that entity, then copies detached entities state to the newly loaded entity. Subsequently, at a later point, during the transaction commit phase(or flush) the dirty checking mechanism fires the update query but won't include the fields marked as updatable=false.
So it doesn't attempt to reload the object with the data in the database after the UPDATE.
To trigger reload, you can rely on refresh(...) that will reload the data.
If it is spring-data-jpa it doesn't expose any refresh method, so you need to add it to your repository and and an example can be found here and discussion on this topic in the spring forum here.

JPA / JTA / #Transactional Spring annotation

I am reading the transaction management Using Spring framework. In first combination I used Spring + hiberante and used Hibernate's API's to control the transaction (Hibenate API's). Next, I wanted to test using #Transactional annotation, and it did work.
I am getting confused on:
Do JPA , JTA, Hibernate have their "own" way of transaction
management. As an example, consider if I use Spring + Hibernate, in
that case would u use "JPA" transactions?
Like we have JTA, is it true to say we can use Spring and JTA to
control transactions?
The #Transactional annotation, is that specific to Spring
Framework? From what I understood, this annotation is Spring
Framework specific. If this is correct, is #Transactional using
JPA/JTA to do the transaction control?
I do read online to clear my doubts, however something I don't get direct answer. Any inputs would be great help.
#Transactional in case of Spring->Hibernate using JPA i.e.
#Transactional Annotations should be placed around all operations that are inseparable.
So lets take example:
We have 2 model's i.e. Country and City.
Relational Mapping of Country and City model is like one Country can have multiple Cities so mapping is like,
#OneToMany(fetch = FetchType.LAZY, mappedBy="country")
private Set<City> cities;
Here Country mapped to multiple cities with fetching them Lazily.
So here comes role of #Transactinal when we retrieve Country object from database then we will get all the data of Country object but will not get Set of cities because we are fetching cities LAZILY.
//Without #Transactional
public Country getCountry(){
Country country = countryRepository.getCountry();
//After getting Country Object connection between countryRepository and database is Closed
}
When we want to access Set of Cities from country object then we will get null values in that Set because object of Set created only this Set is not initialize with there data to get values of Set we use #Transactional i.e.,
//with #Transactional
#Transactional
public Country getCountry(){
Country country = countryRepository.getCountry();
//below when we initialize cities using object country so that directly communicate with database and retrieve all cities from database this happens just because of #Transactinal
Object object = country.getCities().size();
}
So basically #Transactional is Service can make multiple call in single transaction without closing connection with end point.
Hope this will helpful to you.

Resources