(spring) JPA (Java Persistence API)
💼📝🔑⏰ 📙📓📘📒🎓
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가 더 빠르긴하다.
댓글남기기