(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가 더 빠르긴하다.
댓글남기기