public interface MyEntityRepository extends JpaRepository<MyEntity, KeyClass>, MyEntityRepositoryCustom { }
QueryDslPredicateExecutor
를 추가하지 않아도 된다. Custom 에서 QueryDslJpaRepository
를 구현해서 직접 사용해도 된다.JpaRepository
, QueryDslJpaRepository
, JpaSpecificationExecutor
등을 조합하고자 할 경우에 이것들을 통합 상속하는 인터페이스를 만들고 JpaRepository
대신 이를 extends 해도 된다.@Transactional(value = "transactionManager", readOnly = false) public abstract class MyDomainRepositorySupport extends QueryDslRepositorySupport { // JdbcTemplate, jooq 등을 injection할 수도 있다. public MyDomainRepositorySupport(Class<?> domainClass) { super(domainClass); } @PersistenceContext(unitName = "persistenceUnitName") @Override public void setEntityManager(EntityManager entityManager) { super.setEntityManager(entityManager); } }
@Transactional
을 붙여야 한다.autocommit=false
가 기본으로 하고 작업시마다 autocommit=false|true
토글을 하지 않고 hibernate.connection.provider_disables_autocommit: true
인 경우에 문제가 된다.@Transactional
을 붙여야한다.
BoardRepository
가 도메인 모듈에 있을 때, API 모듈에서 이를 상속해서 BoardApiRepository
처럼 만들거나 하는 경우가 발견됨. 절대 상속하지 말 것Pageable
을 인자로 받는 메소드는 기본적으로 전체 갯수를 세는 쿼리를 추가로 요청한다.Pageable
과 달리 전체 갯수를 세지 않는다.Slice
를 이용해 페이지 데이터를 가져오게 한다.Slice
도 offset/limit
방식으로 성능이 떨어지는 것은 동일하다.@Query(value = "select user_id, user_name from users ", nativeQuery = true) List<Object[]> findUSBCandidates();
@Query(value=“쿼리문”, nativeQuery = true)
로 수행한다.Object []
로 받아서 컬럼 지정 순서대로 값을 뽑아서 사용한다.@Query
결과를 Projection 하려면 Value Object의 필드 이름과 동일하게 alias 하여 컬럼을 select 한다.QueryDslRepositorySupport
을 상속하면 QueryDSL 사용이 가능해진다.QuerydslRepositorySupport
로 이름 변경QueryDslRepositorySupport
상속 객체를 Spy()
로 만들고 repositoryImpl.from(_) » jpqlQuery
로 한 뒤에 jpqlQuery
에 대해 행위를 정의하면 된다.java
extension으로 추가한다.#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end import org.springframework.stereotype.Repository; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.querydsl.QueryDslPredicateExecutor; #parse("File Header.java") @Repository public interface ${EntityClass}Repository extends JpaRepository<${EntityClass}, ${EntityKey}>, QuerydslPredicateExecutor<${EntityClass}>, ${EntityClass}RepositoryCustom { }
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end import org.springframework.data.jpa.repository.support.QueryDslRepositorySupport; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; public class ${EntityClass}RepositoryImpl extends QuerydslRepositorySupport implements ${EntityClass}RepositoryCustom { public ${EntityClass}RepositoryImpl() { super(${EntityClass}.class); } @PersistenceContext @Override public void setEntityManager(EntityManager entityManager) { super.setEntityManager(entityManager); } }
Optional
, CompletableFuture
, Stream
등 지원CompletableFuture
, Stream
사용시에 Transaction Boundary 조심할 것.interface CustomerRepository extends Repository<Customer, Long> { @Async CompletableFuture<List<Customer>> readAllBy(); @Query("select c from Customer c") Stream<Customer> streamAllCustomers(); // CRUD method using Optional Optional<Customer> findOne(Long id); // Query method using Optional Optional<Customer> findByLastname(String lastname); }
existsByXXX
형태의 메소드로 가능.Repository.exists(example)
가능? is null or 비교
를 붙이면 된다.(? IS NULL OR COLUMN = ?)
@Query("select u from User u where u.age = ?#{[0]}") List<User> findUsersByAge(int age); @Query("select u from User u where u.firstname = :#{#customer.firstname}") List<User> findUsersByCustomersFirstname(@Param("customer") Customer customer);