Hot questions for Spring Data JPA

Hot questions for Spring Data JPA

Top 10 Java Open Source / Spring / Spring Data JPA

Question:

What is the difference between CrudRepository and JpaRepository interfaces in Spring Data JPA?

When I see the examples on the web, I see them there used kind of interchangeably. What is the difference between them? Why would you want to use one over the other?


Answer:

JpaRepository extends PagingAndSortingRepository which in turn extends CrudRepository.

Their main functions are:

Because of the inheritance mentioned above, JpaRepository will have all the functions of CrudRepository and PagingAndSortingRepository. So if you don't need the repository to have the functions provided by JpaRepository and PagingAndSortingRepository , use CrudRepository.

Question:

I am using spring data and my DAO looks like

public interface StudentDAO extends JpaRepository<StudentEntity, Integer> {
    public findAllOrderByIdAsc();   // I want to use some thing like this
}

In above code, commented line shows my intent. Can spring Data provides inbuilt functionality to use such a method to find all records order by some column with ASC/DESC?


Answer:

public interface StudentDAO extends JpaRepository<StudentEntity, Integer> {
    public List<StudentEntity> findAllByOrderByIdAsc();
}

The code above should work. I'm using something similar:

public List<Pilot> findTop10ByOrderByLevelDesc();

It returns 10 rows with the highest level.

IMPORTANT: Since I've been told that it's easy to miss the key point of this answer, here's a little clarification:

findAllByOrderByIdAsc(); // don't miss "by"
       ^

Question:

What are the main differences between Hibernate and Spring Data JPA? When should we not use Hibernate or Spring Data JPA? Also, when may Spring JDBC template perform better than Hibernate / Spring Data JPA?


Answer:

Hibernate is a JPA implementation, while Spring Data JPA is a JPA Data Access Abstraction. Spring Data offers a solution to GenericDao custom implementations. It can also generate JPA queries on your behalf through method name conventions.

With Spring Data, you may use Hibernate, Eclipse Link or any other JPA provider. A very interesting benefit is that you can control transaction boundaries declaratively using the @Transactional annotation.

Spring JDBC is much more lightweight, and it's intended for native querying, and if you only intend to use JDBC alone, then you are better off using Spring JDBC to deal with the JDBC verbosity.

So, Hibernate and Spring Data are complementary rather than competitors.

Question:

In Spring CrudRepository, do we have support for "IN clause" for a field? ie something similar to the following?

 findByInventoryIds(List<Long> inventoryIdList) 

If such support is not available, what elegant options can be considered? Firing queries for each id may not be optimal.


Answer:

findByInventoryIdIn(List<Long> inventoryIdList) should do the trick.

The HTTP request parameter format would be like so:

Yes ?id=1,2,3
No  ?id=1&id=2&id=3

The complete list of JPA repository keywords can be found in the current documentation listing. It shows that IsIn is equivalent – if you prefer the verb for readability – and that JPA also supports NotIn and IsNotIn.

Question:

I am looking into Spring Data JPA. Consider the below example where I will get all the crud and finder functionality working by default and if I want to customize a finder then that can be also done easily in the interface itself.

@Transactional(readOnly = true)
public interface AccountRepository extends JpaRepository<Account, Long> {

  @Query("<JPQ statement here>")
  List<Account> findByCustomer(Customer customer);
}

I would like to know how can I add a complete custom method with its implementation for the above AccountRepository? Since its an Interface I cannot implement the method there.


Answer:

You need to create a separate interface for your custom methods:

public interface AccountRepository 
    extends JpaRepository<Account, Long>, AccountRepositoryCustom { ... }

public interface AccountRepositoryCustom {
    public void customMethod();
}

and provide an implementation class for that interface:

public class AccountRepositoryImpl implements AccountRepositoryCustom {

    @Autowired
    @Lazy
    AccountRepository accountRepository;  /* Optional - if you need it */

    public void customMethod() { ... }
}

See also:

Question:

I have an use case where it calls the following:

@Override
@Transactional(propagation=Propagation.REQUIRES_NEW)
public UserControl getUserControlById(Integer id){
    return this.userControlRepository.getOne(id);
}

Observe the @Transactional has Propagation.REQUIRES_NEW and the repository uses getOne. When I run the app, I receive the following error message:

Exception in thread "main" org.hibernate.LazyInitializationException: 
could not initialize proxy - no Session
...

But If I change the getOne(id) by findOne(id) all works fine.

BTW, just before the use case calls the getUserControlById method, it already has called the insertUserControl method

@Override
@Transactional(propagation=Propagation.REQUIRES_NEW)
public UserControl insertUserControl(UserControl userControl) {
    return this.userControlRepository.save(userControl);
}

Both methods are Propagation.REQUIRES_NEW because I am doing a simple audit control.

I use the getOne method because it is defined in the JpaRepository interface and my Repository interface extends from there, I am working with JPA of course.

The JpaRepository interface extends from CrudRepository. The findOne(id) method is defined in CrudRepository.

My questions are:

  1. Why fail the getOne(id) method?
  2. When I should use the getOne(id) method?

I am working with other repositories and all use the getOne(id) method and all work fine, only when I use the Propagation.REQUIRES_NEW it fails.

According with the getOne API:

Returns a reference to the entity with the given identifier.

According with the findOne API:

Retrieves an entity by its id.

3) When I should use the findOne(id) method?

4) What method is recommended to be used?

Thanks in advance.


Answer:

The basic difference is that getOne is lazy loaded and findOne is not.

Consider the following example:

public static String NON_EXISTING_ID = -1;
...
MyEntity getEnt = myEntityRepository.getOne(NON_EXISTING_ID);
MyEntity findEnt = myEntityRepository.findOne(NON_EXISTING_ID);

if(findEnt != null) {
     findEnt.getText(); // findEnt is null - this code is not executed
}

if(getEnt != null) {
     getEnt.getText(); // Throws exception - no data found, BUT getEnt is not null!!!
}

Question:

I am using Spring JPA to perform all database operations. However I don't know how to select specific columns from a table in Spring JPA?

For example: SELECT projectId, projectName FROM projects


Answer:

You can use projections from Spring Data JPA (doc). In your case, create interface:

interface ProjectIdAndName{
    String getId();
    String getName();
}

and add following method to your repository

List<ProjectIdAndName> findAll();