JPA란?
Jakarta Persistence API는 ORM(Object Relation Mapping)기술 표준으로 사용되는 인터페이스의 모음이다.
즉 실제로 구현된 클래스가 아니라 실질적으로 구현된 클래스와 매핑시켜주기 위한 프레임워크(도구)이다.
강의에서 들은 사용 단계이다.
- 테이블 생성하고 활용할 때 -> Entity 클래스에서 그 역할을 함
(Entity클래스는 테이블을 생성한다. 가방 역할을 함
엔티티클래스는 DTO 그자체로 볼 수 있다.) - 데이터 제어 -> Repository
findById(), findAll(), save(), count() - 페이징
- 연관관계 N:1 @ManyToOne
1:N @OneToMany
1:1 @OneToOne - 조건 검색 -> QueryMthod
특징
- DAO와 DB테이블의 의존성 문제를 해결해준다.
- 엔티티 작성시 자동으로 테이블 생성해준다.
- SQL문을 이용하지 않고도 메소드 호출시 자동으로 SQL 문장 실행시켜줌
장점
- 유지보수
- 생산성 향상
- DB에 종속적이지 않음(객체를 중심으로 개발을 진행가능하다.)
그럼 왜 JPA를 사용해야할까?
JPA는 반복적인 CRUD SQL을 처리해준다.
JPA는 매핑된 관계를 이용해서 SQL을 생성하고 실행하는데, 개발자는 어떤 SQL이 실행될지 생각만하면된다.
JPA Dialect
방언이라고도 하는 Dialect는 DB형태에 따라 다르게 설정이 된다.
Dialect를 설정해주면 스프링부트 실행 시 연결되어있는 DB에 알맞게 자동으로 지정이 되므로
특별한 이유없이 수동 설정을 할 필요가없음
그럼 생성을 해보자 정말 간단하다
현재 프로젝트 파일에서
resources/application.properties에 들어간다.
spring.jpa.database-platform=org.hibernate.dialect.MariaDBDialect
그냥 이 코드 한줄이면 Db연결 설정이 끝난다.(너무 간단한데.;;;)
그리고 살짝 추가하면 편리한 설정도 있다.
- 데이터베이스 식별자(테이블 이름, 컬럼 이름 등)에 인용부호 사용
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
- 데이터베이스 예약어와 충돌할 때만 인용부호 사용 SQL의 ? 에 입력되는 값 확인
logging.level.org.hibernate.orm.jdbc.bind=trace
JPA 매핑 어노테이션
- @Entity
- JPA가 관리할 객체이다.
- DTO의 역할을 할 수 있다고 볼 수 있다.
- 이 어노테이션이 붙은 클래스는 테이블을 생성해준다.(가방 역할을 하는?)
- @Id
- DB테이블에서는 기본키라고 불리는 키를 자바에서는 Id로 붙여서 기본키로 만들어준다.
- @Table
- 엔티티와 매핑할 테이블이다.(테이블 이름을 지정해주는 것이라고 보면 될듯?)
- 생략시 Entity이름을 테이블 이름으로 사용한다.
- @Column
- 컬럼과 관련된 속성 지정(name, nullable, length 속성 자주 사용 -> 생략시 기본 자료형은 not null, 참조자료형은 nullable로 지정되며 변수명과 동일한 컬럼 생성)
- 카멜 케이스 적용시 스네이크 케이스로 변경해줌
ex) UserAge -> user_age로 변경된다.
- @Enumerated
- 열거형 데이터(DB에 값을 넣을 수 있고, 구분할 수 있게 해주는 어노테이션이다.)
- EnumType.ORDINAL: 순서를 DB에 저장해준다.
- EnumType.STRING: 이름 값을 DB에 저장해준다.
- @Temporal
- 날짜 데이터이다.
- TemporalType.DATE : yyyy/mm/dd가 나온다. ex)2012-03-25)이렇게 나온다.
- TemporalType.TIME: 시간만 나온다. ex) 11:00:00
- TemporalType.TIMESTAMP: DATE와 TIME 합쳐놓은 것이라고 생각하면 됨
솔직히 백날 개념 설명해봐야 실제로 코드를 만들어 봐야지 알 수 있다.
엔티티 생성
package com.example.basic.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import lombok.Data;
@Data//데이터 어노테이션이 있으면 Setter와 Getter를 만들어준다.
@Entity(name = "table_exam_1")
public class TableExam1 {
@Id
Integer id;
@Column(length = 100, nullable = false)
String title;
@Column(name = "description", length = 1000, nullable = true)
String content;
Long price;
String brand;
}
여기서 테이블 이름은 table_exam_1이다.
위 코드를 실행하여 테이블이 실제로 만들어졌는지 보자
진짜로 id는 기본키, title은 not null로 생성됐고 content는 description이라는 칼럼으로 이름이 지어졌다!!
Long은 이제 DB에서는 BIGINT로 표현이 되는것을 알 수 있다.(굉장히 신기했다...)
※순수 궁금함
String brand -> brandTitle로 바꾸면 스네이크 케이스로 될까?
정말로 스네이크 케이스로된 칼럼이 새로생겼다;;;
이렇게 테이블 이름이 table_exam_1인 테이블이 생겼다.
데이터 제어
데이터를 생성했으니까 제어를 해줘야한다.(생성만 하면 뭐하나 값을 주고받아야되는데)
여기서 우리는 킥인 JpaRepository를 사용할것이다.
JpaRepository는 데이터 입력/조회/수정/삭제 하기 위해서 사용이 된다.
객체(Entity)와 RDB를 매핑하여 DB의 SQL을 자동으로 생성해준다.(진짜 킥이네)
JpaReposiotry 지원 메소드
- 입력/수정: save()
- 삭제: delete()
- 조회: findById(), findAll()
모종의 이유로 ServiceRepository를 이용해서 CRUD를 해보겠다.
package com.example.basic.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.example.basic.entity.ServiceCenter;
@Repository
public interface ServiceCenterRepository
extends JpaRepository<ServiceCenter, Integer> {
}
JpaRepository는 인터페이스이기때문에 컨트롤러에서 메서드 구현을 해줘야한다.
이제 컨트롤러에서 데이터를 입력 해보겠다.
@GetMapping("/sc/add")
@ResponseBody
public ServiceCenter scAdd(
@ModelAttribute ServiceCenter sc) {
LocalDateTime ldt = LocalDateTime.now();
sc.setPurDate(ldt);
Date date = new Date();
sc.setVstDate(date);
ServiceCenter result = serviceCenterRepository.save(sc);
return result;
}
해당 경로로 들어간 뒤
add?customer=최길동&prodName=노트북
이라고 url에 입력을 해주면
다음과 같이 JSON데이터로 출력이 되게 된다.
그럼 DB에서 값이 들어갔는지 확인을 해야겠다
DB에 값이 잘 들어간 것을 확인 할 수 있다.
※Date와 LocalDateTime
LocalDateTime은 시간대를 확인 해주는 객체이다.
- LocalDateTime.now(): 현재 지역의 시간대를 나타내줌
- Date(): 기본생성자만 생성시 세계 표준시 UTC를 기준으로 설정해준다.
마지막에 ServiceCenter 엔티티 객체 result에 Repository에서 접근한 sc값들을 save함수로 저장해준다.
데이터 조회
데이터를 추가했으니까 데이터 조회도 해보자
@GetMapping("/sc/list")
@ResponseBody
public List<ServiceCenter> scList() {
List<ServiceCenter> result = serviceCenterRepository.findAll();
return result;
}
결이 전부 비슷하다. 다만 ServiceCenter 객체를 받아서 한개만 출력할 것이 아니면
findAll함수를 사용했으면 리턴값이 List형태로 나와줘야하는것이 우리들의 약속? 이랄까
아까전에 추가된 값이 잘 나오는 것을 볼 수 있다.
데이터 수정
수정도 똑같은 save함수를 사용한다.
다만 해당 기본키가 입력되어 있어야지 데이터를 수정할 수 있다.
@GetMapping("/sc/modify")
@ResponseBody
public ServiceCenter scModify(@ModelAttribute ServiceCenter sc) {
// sc.setId(1);
// 이렇게 넣으면 date가 null로 바뀐다.
// 그래서 수정하고싶으면 save하기 전에 데이터를 불러와줘라
// 수정을 위해 DB의 데이터를 조회회
Optional<ServiceCenter> opt = serviceCenterRepository.findById(sc.getId());
ServiceCenter savedSC = opt.get();
// 기존 방문일자를 새로 저장할 객체에 입력
savedSC.setVstDate(savedSC.getVstDate());
// 기존 예약일자를 새로 저장할 객체에 입력
savedSC.setPurDate(savedSC.getPurDate());
ServiceCenter result = serviceCenterRepository.save(sc);
return result;
}
여기서 무작정 setId(1)을 설정하고 update하면 date값이 사라진다.
왜? --> 우리는 값을 수정할 때 date값도 수정을 하지 않기 때문이다.
findById의 리턴값은 무조건 Optional인데
여기서 Optional은 순수 자바 클래스이다.
null일 수도 있는 객체를 감싸주는 역할을 한다.
- 값을 수정하기 전에 savedSC에 수정 전 값을 저장해준다.
- 기존의 일자를 새로 저장할 객체에 입력해준다.
- 그리고 save함수를 통해 sc값을 새로 저장한다.
이렇게 새로 저장한 값을 불러와 주는 것도 가능해진다.
데이터삭제
세상에서 가장 간단하다.(실제로 서비스 구현하려면 간단하지 않겠지만..)
@GetMapping("/sc/delete")
@ResponseBody
public String scRemove(@ModelAttribute ServiceCenter sc) {
serviceCenterRepository.delete(sc);
return "삭제 완료";
}
그냥 sc객체를 delete해주기만 하면 된다.
이렇게 DB에서 삭제가 된 것을 볼 수 있다.
'Spring' 카테고리의 다른 글
[스프링부트] - 페이징 (0) | 2025.05.05 |
---|---|
[스프링부트] - JPA 연관관계 (0) | 2025.04.30 |
[스프링 부트] -Spring JDBC (1) | 2025.04.25 |
[스프링 부트] - AJAX 요청 파라미터 전달 (1) | 2025.04.24 |
[스프링부트] - Web MVC (1) | 2025.04.22 |