(spring) JPA (Java Persistence API)

2 분 소요

💼📝🔑⏰ 📙📓📘📒🎓

xml 예제 프로젝트 : spring-boot-demoweb2-starter

💼 JPA 란?

  • 자바 객체와 데이터베이스 테이블 간의 매핑을 처리하는 ORM 기술 표준
  • JAP 구현체
    • JPA 기술 명세를 구현한 제품 → JPA Provider
    • 하이버네이트, 이클립스링크 등
  • 장점
    • 개발이 편리하다
    • 데이터베이스에 대한 종속성 제거 → 데이터베이스 제품 의존성 없음
    • 유지보수가 쉽다.
  • 단점
    • 학습곡선이 가파르다
    • 특정 데이터베이스의 특화된 기능 사용 제한
    • 객체지향 설계 필요

💼 Spring Data JPA

  • 스프링에서 JPA를 쉽게 사용할 수 있도록 지원하는 라이브러리
  • Spring Data JPA가 제공하는 Repository 인터페이스를 상속해서 정해진 규칙에 맞게 메서드를 작성하면 자동으로 데이터 연동 코드 완성
  • 내부에서는 실제 기능을 담당하는 JPA 구현체로 하이버네이트 사용
  • 하이버네이트와 같은 ORM 사용에 필요한 다양한 요구사항을 추상화해서 상대적으로 쉽게 JPA 사용 가능

📝 Spring Data JPA 구현

🔑 application.properties 설정

server.port=8081

spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp

spring.datasource.hikari.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.hikari.jdbc-url=jdbc:mysql://211.197.18.246:3306/demoweb?serverTimezone=UTC
spring.datasource.hikari.username=devuser
spring.datasource.hikari.password=mariadb
spring.datasource.hikari.connection-test-query=SELECT 1

spring.jpa.database=mysql
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.use-new-id-generator-mappings=false

🔑 DatabaseConfig.java 변경

@Bean
@ConfigurationProperties(prefix="spring.jpa")
public Properties hibernateConfig() {		
	return new Properties();
}

🔑 Application 클래스 수정

@EntityScan(basePackages = { "com.demoweb" })
@SpringBootApplication
public class SpringBootDemowebApplication {

🔑 Entity 클래스 정의

@Entity
@Table(name = "tbl_board")
@Data
public class BoardEntity {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private int boardNo;
	@Column(nullable = false)
	private String title;
	@Column(nullable = false)
	private String writer;
	@Column(nullable = false)
	private String content;
	@Column
	@DateTimeFormat(pattern = "yyyy-MM-dd")
	private Date regDate = new Date();
	@Column
	private int readCount = 0;
	@Column
	private boolean deleted = false;
		
	@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
	@JoinColumn(name = "boardNo")
	private Set<BoardAttachEntity> attachments;
	
	@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
	@JoinColumn(name = "boardNo")
	private Set<BoardCommentEntity> comments;
}

📝 Repository interface

  • 스프링 데이터 JPA가 제공하는 인터페이스로 기능 수준에 따라 4가지 인터페이스 제공
  • 각 인터페이스를 상속하는 인터페이스를 정의하면 일정한 패턴에 따라 데이터베이스 연동 메서드를 자동 생성
  • 자동으로 생성된 메서드로 충족되지 않는 기능은 일정한 규칙에 따라 메서드를 선언할 수 있음
  • JPA 에서 제공하는 JPQL 이나 데이터베이스에서 사용하는 SQL을 사용해서 메서드를 만드는 것도 가능

🔑 Repository interface method

  • CrudRepository 인터페이스 기준
    • save(entity): 지정된 엔티티 저장
    • saveAll(entities): 지정된 엔티티 목록 저장
    • findById(id): 지정된 아이디로 식별된 엔티티 반환
    • existsById(id): 지정된 아이디로 식별된 엔티티 존재 여부 반환
    • findAll(): 모든 엔티티 반환
    • findAllById(ids): 지정된 아이디 목록에 의해 식별된 모든 엔티티 반환
    • count(): 사용 가능한 엔티티 개수 반환
    • deleteById(id): 지정된 아이디로 식별된 엔티티 삭제
    • delete(entity): 지정된 엔티티 삭제
    • deleteAll(entities): 지정된 엔티티 목록 삭제
    • deleteAll(): 모든 엔티티 삭제

📝 Query Method Pattern

  • 메서드 이름은 find…By, read…By, query…By, count…By, get…By로 시작
  • 첫 번째 By 뒤쪽은 컬럼 이름으로 구성 → 검색 조건
  • And 또는 Or 키워드를 사용해서 두 개 이상의 속성을 조합
  • 다양한 비교 연산자를 조합해서 필요한 쿼리 작성

사용 예

public interface BoardRepository extends CrudRepository<BoardEntity, Integer> {
	
	@Query(
		value = "SELECT * FROM tbl_board b ORDER BY b.board_no DESC LIMIT :from, :count",
		nativeQuery = true
	)
	List<BoardEntity> findAllWithPaging(@Param("from") int from, @Param("count") int count);

	@Query(
		"SELECT ba FROM BoardAttachEntity ba WHERE ba.attachNo = :attachNo"
	)
	BoardAttachEntity findBoardAttachByAttachNo(@Param("attachNo") int attachNo);

	@Query(
		value = "UPDATE tbl_board SET read_count = read_count + 1 WHERE board_no = :boardNo",
		nativeQuery = true
	)
	void updateBoardReadCount(@Param("boardNo") int boardNo);	
}

성능면으로만 봤을 때 mybatis가 더 빠르긴하다.

댓글남기기