JPA EntityManager
를 직접 사용해 DAO를 작성하는 예시입니다.
@Repository
@Transactional
public class OfferDao {
@PersistenceContext
private EntityManager entityManager;
public Product createProduct(Product product) {
entityManager.persist(product);
return product;
}
public Product findProduct(Long id) {
return entityManager.find(Product.class, id);
}
public Product updateProduct(Product product) {
return entityManager.merge(product);
}
public void deleteProduct(Long id) {
Product product = findProduct(id);
if (product != null) {
entityManager.remove(product);
}
}
}
Entity
타입과 기본 키 타입만 다를 뿐 코드가 유사함Spring Data JPA를 사용하면 레포지토리 인터페이스만 정의해도 기본 CRUD 구현을 자동으로 제공합니다.
public interface ProductRepository
extends CrudRepository<Product, Integer> {
}
위와 같이 선언하면 다음 메서드들이 자동 생성됩니다:
findAll()
findById(ID id)
save(S entity)
deleteById(ID id)
CrudRepository<T, ID>
: CRUD 기본 기능 제공PagingAndSortingRepository<T, ID>
: 페이징·정렬 기능 추가JpaRepository<T, ID>
: 배치 삭제, 플러시 기능 등 JPA 확장 기능 제공CrudRepository
가 제공하는 메서드 예시:
메서드 | 설명 |
---|---|
long count() | 엔티티 개수 조회 |
void delete(T entity) | 특정 엔티티 삭제 |
void deleteById(ID id) | ID로 엔티티 삭제 |
Iterable<T> findAll() | 모든 엔티티 조회 |
Optional<T> findById(ID id) | ID로 엔티티 조회 |
<S extends T> S save(S entity) | 엔티티 저장/수정 |
<S extends T> Iterable<S> saveAll(...) | 여러 엔티티 저장/수정 |
페이징과 정렬을 지원합니다.
public interface ProductRepository
extends PagingAndSortingRepository<Product, Long> {
}
사용 예시:
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
public List<Product> findAllSortedByPrice() {
Sort sort = Sort.by(Sort.Direction.DESC, "price");
return (List<Product>) productRepository.findAll(sort);
}
public Page<Product> findByPage(int page, int size) {
Pageable pageable = PageRequest.of(page, size,
Sort.by(Sort.Direction.ASC, "name"));
return productRepository.findAll(pageable);
}
}
Page<T>
를 통해 페이징 정보(총 페이지, 총 요소 등) 제공JpaRepository
는 PagingAndSortingRepository
를 상속하며, 추가로 다음 기능을 제공합니다:
void flush()
void deleteAllInBatch()
등 배치 삭제List<T> findAll()
의 리턴 타입이 List<T>
public interface ProductRepository
extends JpaRepository<Product, Integer> {
}
@Service
public class ProductService {
@PersistenceContext
private EntityManager entityManager;
@Transactional
public Product save(Product product) {
if (product.getId() == null) {
entityManager.persist(product);
return product;
} else {
return entityManager.merge(product);
}
}
public Product findById(Integer id) {
return entityManager.find(Product.class, id);
}
@Transactional
public void deleteById(Integer id) {
Product product = findById(id);
if (product != null) {
entityManager.remove(product);
}
}
public boolean existsById(Integer id) {
return findById(id) != null;
}
}
public interface ProductRepository
extends JpaRepository<Product, Integer> {
}
@Service
@Transactional
public class ProductService {
@Autowired
private ProductRepository repo;
public Product get(long id) {
return repo.findById(id).orElse(null);
}
public List<Product> listAll() {
return repo.findAll();
}
public void save(Product product) {
repo.save(product);
}
public void delete(long id) {
repo.deleteById(id);
}
}
메소드 이름만으로 동적 쿼리 생성이 가능합니다.
public interface MemberRepository
extends JpaRepository<Member, Long> {
List<Member> findByUsername(String username);
List<Member> findByUsernameAndAgeGreaterThan(
String username, int age);
}
findByXxxAndYyy
, findByAgeLessThan
, findByFirstnameContaining
등 다양한 키워드 지원List<T>
, Page<T>
, Optional<T>
등메소드 이름으로 표현하기 어려운 복잡한 쿼리는 @Query
로 JPQL 또는 네이티브 SQL을 직접 지정할 수 있습니다.
public interface BoardRepository
extends JpaRepository<Board, Long> {
@Query("SELECT b FROM Board b WHERE b.title LIKE %:kw% " +
"ORDER BY b.seq DESC")
List<Board> searchByTitle(@Param("kw") String keyword);
@Query(value = "SELECT seq, title FROM board " +
"WHERE title LIKE %?1% ORDER BY seq DESC",
nativeQuery = true)
List<Object[]> searchNative(String keyword);
}
?1
), 이름 기반(:param
) 파라미터 바인딩 지원