How are custom methods in spring data jpa implemented and executed? - java

I am using spring data jpa for my project and i have following pieces of code:
My Repository:
#Repository
#Transactional
public interface StudentRepository extends PagingAndSortingRepository<Student, Long> {
List<Student> findByIdIn(List<Long> ids);
}
and my entity is :
#Entity
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
// other fields
// getters/setters
}
Somewhere in my service class, i have
#Autowired
StudentRepository studentRepository;
and then i call findByIdIn from my service layer like :
studentRepository.findByIdIn(listOfIds);
findByIdIn(listOfIds) method works perfectly fine and everything is working as expected.
I know that the implementation of findByIdIn() method is provided by spring data jpa.
But i am not able to figure where is its implementation present?
What exactly is its implementation?
Are such methods generated at run time depending upon the method-name? If yes how are they generated and executed dynamically?
Thanks!

You can dig a little bit in the core of the Spring code to see how it works (https://github.com/spring-projects/spring-data-commons/tree/master/src/main/java/org/springframework/data/repository), but basically, it's parsing the interface methods into HQL at the startup time.
You can test just be editing a method name to a field which doesn't exist, and you'll get an error at startup time saying that there is no field as this.

Related

Spring Boot REST Resource Changes not Applying

I have a very simple Spring Boot application, that consists of an Order and a JpaRepository #RepositoryRestResource:
#Entity
public class Order {
#Id
#GeneratedValue
private Long recordId;
#Length(max = 64)
private String orderType;
.....
}
#RepositoryRestResource
public interface OrderRepository extends JpaRepository<Order, Long>,
QuerydslPredicateExecutor<Order> {
}
I had recently changed the field orderKind to orderType. I made sure that the database had been updated. However, on the endpoints, the change isn't applying. It still expects/returns orderKind.
I ruled out any IDE issues by cleaning the project, deleting any generated sources, and running directly from the command line, to no luck.
Also verified, and QOrder.java that gets generated also had orderType defined correctly.
While writing this, discovered the problem was trivial. When I refactored the field name, I forgot to update the getter and setter for that field, such that they still read:
public String getOrderKind() {
return orderType;
}
public void setOrderKind(String orderKind) {
this.orderType = orderKind;
}
Me being new to spring boot didn't realize it was the methods that define the API, which in hindsight seems obvious, since the fields are private.

Optimize JPA performance on inserting many entities with embedded primary key

I naively implemented a web service, that consumes a list of Json objects and stores them in a SQL database using
springframework.data.jpa (JPA & Hibernate). However, the solution has a low performance and the profiler gave me a hint that the main problem lies in creating the entities from the Json objects one by one.
The code below is simplified, but basically: for each Json object in the incoming list there are two entities created: DataEntity and IdentityEntity. The former holds the data of interest and uses the latter as FK, which has a compound PK of a time and a person.
I'd like to speed up the storage process. I've determined with a profiler, that there are too many flush operations that are being done after insert of each new entity. Since I need to insert thousands of records at a given time, this causes the performance issue. Can I perhaps do the insert in one transaction or what are other ways of optimizing it?
Data class (I have many similar classes):
#Entity
public class DataEntity {
#EmbeddedId
private IdentityEntity identity;
private Double data;
}
Embeddable entity:
#Embeddable
public class IdentityEntity implements Serializable {
#NonNull
private Long personId;
#NonNull
private Long datetimeId;
}
JPA repository:
#Repository
public interface DataRepository extends JpaRepository<DataEntity, IdentityEntity> {}
Simplified controller:
public class DataController{
#Autowired
private DataRepository dataRepository;
#Autowired
private DatetimeRepository datetimeRepository;
#PostMapping("/upload")
public void upload(...List<DataJson> items) {
PersonEntity person = getPerson(...); // fast enough
for (DataJson i : items) { // begin transaction here?
saveNewEntity(i, person.getId());
}
}
private void saveNewEntity(DataJson json, Long personId) {
TimeEntity savedDatetime = datetimeRepository.save(new TimeEntity(json.getDatetime()));
IdentityEntity mi = IdentityEntity(personId, savedDatetime.getId());
DataEntity entry = new DataEntity(mi, json.getData());
dataRepository.save(entry);
}
}
Edit: After further digging into the profiler, I've discovered that another time-consuming operation might be the transaction management itself. Although I haven't implemented or configured any transaction behavior, I suspect that the Spring Boot has something default configured for the Hibernate ORM. I'm beginning to think that a transaction is now being created in every iteration of the loop, being the 1st performance issue and also causing the 2nd issue, where at the end of the transaction everything is flushed and written into the DB.
Yep. All the methods in the SimpleJpaRepository are annotated with #Transactional.
Simply add a #Transactional annotation to your upload method.
... or
First create all of the objects and save them in one go using the save(Iterable<S> entities) method.

DAO call DAO, DAO call service or SQL join?

So I'm writing a personal project to learn about web programing and I came across the DAO pattern. I'd built some classes (models) and like almost any program, they are nested (ex: the class Payment has a reference to an Author instance).
Just for the reference, I'm not using any mappers (will add them on a later iteration, and I'm using JDBC, not JPA).
My question is this:
When I create the PaymentJdbcDao I had a method what will return some Payment, but in order to create this payment from the database stored object I must reach also the Author (stored in a separated table).
Should I call UserJdbcDao from the PaymentJdbcDao in order to get the payment's author, should I alter the query with a join to retrieve the fields from both entities, should the PaymentJdbcDao call the UserService (I think this isn't good since the services are on the layer abobe the daos), or should I remove the author reference as an object and just hold a reference to the author_id?
Which of the abobe is the more appropriate way to accomplish this? Or is any other way which is a better practice?
Thanks.
I call my DAOs (DataAccessObjects) "Repositories".
Spring Data JPA is doing this as well.
So I would create a UserRepository and a PaymentRepository.
Repositories can be called by other Repositories or Services.
Services should never be called by Repositories.
UI -> Service -> Repository.
Your PaymentRepository could return an Entity like this
public class PaymentEntity{
private long id;
private DateTime dateTime;
private UserEntity user;
}
Your UserRepository could return an Entity like this
public class UserEntity{
private long id;
private DateTime lastLogin;
private List<PaymentEntity> payments;
}
Your Repositories could look like this.
public interface PaymentRepository{
PaymentEntity getPaymentById(long id);
List<PaymentEntity> getAllPayments();
}
public interface UserRepository{
UserEntity getUserById(long id);
List<UserEntity> getAllUsers();
}
So your PaymentRepository would call the UserRepository to get the User for your Payment.
And your UserRepository would call the PaymentRepository to get all users Payments
I hope I was able to help you

Getting data from View using CrudRepository

For this question,I am not looking for a solution, but looking for a direction from where I can take myself ahead, hence not sharing any code.
I am preparing a REST API and I have postgresql database setup locally, which has 2 tables and one view from those 2 tables.
Normally when I want to get any data from DB, I use following code(for the sake of clarity):
DataRepository class:
public interface DataRepository extends CrudRepository<Data, String>{}
DataService class:
#Service
public class DataService {
#Autowired
private DataRepository repo;
public Data getData(String id){
return repo.findById(id).orElse(null);
}
}
DataController class:
#RestController
public class DataController{
#Autowired
private DataService service;
#RequestMapping("/{id}")
public Data getData(String id){
return service.getData(id);
}
}
Data class:
#Entity
public class Data{
#Id
private String id;
private String name;
//respective getter and setter methods
}
Now I want to retrieve data from a view, so, what should be the approach for that?
Should we use the same approach of creating Model, Service, Ctonroller and Repository classes?
Can we use CrudRepository to achieve the same?
I searched in a lot of places, but didn't find anything useful.
Let me know if anyone has any clue on this.
The reading methods of a CrudRepository should work fine with a view. For the writing methods, the view needs to be updatableenter link description here.
If you only want to read, but not to write to the repository, you can create a ReadOnlyRepository by copying the source code of the CrudRepository and removing all the writing methods.
Note that JPA will still try to persist changes made to managed entities.
To avoid that and also avoid the cost of dirty checking you can mark your entities as immutable if you are using Hibernate.

Fetch data by id AND String from single database

I am totally new to Hibernate, Spring and postgres database world. There may be difference in "terms" using to describe.
So issue is, i want to fetch a data where it matches given "id" AND "string" using hibernate, JPA annotations in spring boot.
I know basic like repository.findOne(id) but i am not aware of how to get data with two parameters.
I guess i need something like, i am not sure as i am new to db world
SELECT *
FROM student
WHERE type='commerce'
AND id='1'"
I thank you in advance and tutorials to study further is most welcome.
Spring boot provides for you some automatic repositories, so you just create a interface that extends "JpaRepository" and then, create methods with a natural language.
Something like:
#Repository
public interface StudentRepository extends JpaRepository<Student, Long> {
public List<Student> findByIdAndType(Long id, String type);
}
Later on, let's say you want to use this class:
#Autowired
private StudentRepository studentRepository;
public void doSomething() {
List<Student> students = studentRepository.findByIdAndType(1, "commerce");
}
And no, there is no need to provide an implementation to the interface "StudentRepository", as spring data will provide it to you in behind the scenes.
More information on how this works, you can find on proper spring-data documentarion
Cheers, Nikolas

Categories

Resources