◉ @Query
▪︎ JPA에서 직접 쿼리를 작성할 수 있게 해주는 애너테이션
▪︎ JPA가 쿼리를 자동으로 생성해주지만, 상황에 따라 직접 쿼리를 작성할 필요가 생기기도 함
- 이럴 경우를 대비해, JPA에서 직접 쿼리를 작성할 수 있는 방법에 대해 알아보자
◉ JPA에서 직접 쿼리 작성하는 방법
1. JPQL로 작성
2. 일반 SQL로 작성
▪︎ JPQL : JPA의 일부분으로 정의된 플랫폼 독립적인 객체지향 쿼리 언어
일반 SQL : 데이터베이스를 보고 작성 / JPQL : 엔티티 클래스를 보고 작성
▪︎ JPQL과 SQL 모두 직접 쿼리를 작성하는 방법은 동일하게 @Query 어노테이션 이용
- @Query 어노테이션의 nativeQuery 속성 이용하여 JPQL로 작성할지, SQL로 작성할지 결정
• nativeQuery=true → SQL
• nativeQuery=false → JPQL
▪︎ Snack.java 생성 ( 엔티티 추가 )
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name="snack") // DB의 경우, 스네이크 표기법 이용
public class Snack {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "snack_id")
private int id; // 스낵 과자의 구분 번호
private String name; // 스낵 과자 이름
private int price; // 스낵 과자 가격
}
SELECT구문 쿼리
▪︎ SnackRepository 생성
< @Query 사용 방법 >
- 사용자 정의 Query 메서드 작성으로, 메서드 이름 자유롭게!
- 데이터베이스에 특화된 쿼리(nativeQuery)가 아닌 경우, Entity에 친화된 JPA 쿼리(JPQL)를 쓴다는 의미로
메서드명 뒤에 'JPQL'이라고 붙임
- JPQL과 일반 쿼리일 때 비교해보자
public interface SnackRepository extends JpaRepository<Snack, Integer>{
// * 일반 JPQL 쿼리
// - nativeQuery = false인 경우로, 생략 가능
// - from 뒤에는 엔티티명 ( 소문자로 할 경우, 에러 발생 )
// - Entity로 반환되므로, 별칭만 적어두어도 전체 데이터 반환됨
@Query(value = "Select sn From Snack sn")
public List<Snack> selectAllJPQL();
// * 일반 SQL 쿼리 ( = 순수 SQL )
// - nativeQuery = true인 경우
// - nativeSQL로, DB마다 약간씩 문법 다름
// - from 뒤에는 엔티티명이 아닌 테이블명
@Query(value = "Select snack_id, name, price From snack", nativeQuery = true)
public List<Snack> selectAllSQL();
- 실행 결과 콘솔창에 출력된 로그
DML구문 쿼리
▪︎ 일반 SQL 쿼리 중 SELECT문이 아닌 DML(insert, update, delete문) 사용 시, 다음의 어노테이션 추가
1. @Modifying
- DML구문 뿐만 아니라 DDL구문을 사용할 때도 표기해주어야 함
- 엔터티를 수정하고 버퍼를 비운 후, 새로운 내용으로 새로고침
- 이유 : 영속성 컨텍스트에 오래된 데이터를 비워주고 새로운 데이터를 읽어오기 위해서
즉, DB에 변화가 생기는 경우 이 애너테이션이 필요하다고 생각하면 됨
( 영속성 데이터를 DB와 동기화시킬 때 이용 )
2. @Transactional
- UPDATE, DELETE할 때, 표기를 해주어야 정상 실행이 됨
- 쿼리 처리 과정에서 오류가 날 경우를 대비해서 이 애너테이션을 사용해야 함
즉, @Modifying 중에 예외가 발생하면, 원상복귀하는 기능 설정
▪︎ SnackRepository.java
// 1) UPDATE구문
// - 검색 후 업데이트 진행 → 메서드의 파라미터로 검색할 내용이 들어감
// - 매개변수로 모든 필드를 넘겨주기 보다는 엔터티 자체를 넘겨주기
// @Param 어노테이션 이용 ( value 속성을 이용해 명명된 파라미터에서 사용된 별명 지정 )
// - 수정된 레코드의 개수가 리턴됨
@Query(value = "UPDATE Snack SET name = :#{#paramSnack.name}, price = :#{#paramSnack.price} WHERE id = :#{#paramSnack.id}")
@Modifying(clearAutomatically = true, flushAutomatically = true)
@Transactional
public int updateJPQL(@Param(value = "paramSnack")Snack snack);
▪︎ DemoApplication.java
@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
// * @Slf4j 어노테이션의 실제 구현의 예시
// - 생성자 패턴 ( 팩토리 패턴 )
private static final Logger logger = LoggerFactory.getLogger(DemoApplication.class);
// CommandLineRunner의 run 메서드에서 사용할 carRepository 멤버 변수를 선언 ( 의존성 주입 이용 )
@Autowired
private SnackRepository snackRepository;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
logger.info("Application started");
}
@Override
public void run(String... args) throws Exception {
// * Snack 테이블과 작업하기
// selectAllJPQL() 메서드 결과, List<Snack>
// -> Object 객체의 toString() 이용해서 문자열로 콘솔에 출력
logger.info(snackRepository.selectAllJPQL().toString());
logger.info(snackRepository.selectAllSQL().toString());
// UPDATE JPQL 사용
// 1) updateJPQL() 메서드의 매개변수인 엔터티 객체(데이터 변경 가능한 DTO)생성
// - 실제 업데이트하고 싶은 스낵 레코드가 3번이라고 가정하자
Snack snack = snackRepository.findById(3).get();
// 2) 업데이트할 내용으로 변경
snack.setName("메로나");
snack.setPrice(1000);
// 3) snack DTO는 검색한 내용을 새로운 업데이트 내용으로 변경함
snackRepository.updateJPQL(snack);
// 4) 변경 후, 새로운 내용으로 수정되었는지 확인 - logger 이용
logger.info(snackRepository.findById(3).toString());
}
}
- 실행 결과 콘솔창에 출력된 로그
// 1) INSERT구문
// - 검색 쿼리 : @Query
// - INSERT문 : @Modifying
@Query(value = "INSERT INTO snack (name, price) VALUES (?1, ?2)", nativeQuery = true)
@Modifying(clearAutomatically = true, flushAutomatically = true)
@Transactional
public int insertSQL(String name, int price); // 몇 건의 엔터티를 수정했는지 int 타입으로 반환
'백엔드 > Spring Boot' 카테고리의 다른 글
모던 웹 애플리케이션 개발 - 3. JPA를 이용한 데이터베이스 생성 및 접근 (2) (0) | 2023.08.22 |
---|---|
모던 웹 애플리케이션 개발 - 3. JPA를 이용한 데이터베이스 생성 및 접근 (1) (0) | 2023.08.21 |
모던 웹 애플리케이션 개발 - 1. 환경과 툴 설정 (0) | 2023.08.21 |
6. 블로그 기획하고 API 만들기 흐름 요약 (0) | 2023.08.14 |
Maven Project를 Gradle Project로 변경하기 (0) | 2023.08.11 |