티스토리 뷰
스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 - 김영한 인프런 강의 참고
이전 포스팅
Spring Boot 프로젝트에 JPA 적용하기
build.gradle
파일에 JPA 관련 라이브러리 추가
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
// implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'mysql:mysql-connector-java'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
spring-boot-starter-data-jpa는
내부에 jdbc 관련 라이브러리를 포함한다. 따라서 jdbc는 제거해도 된다.
Spring Boot에 JPA 설정 추가
resources/application.properties
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test_db?serverTimezone=UTC&characterEncoding=UTF-8
spring.datasource.username=
spring.datasource.password=
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
show-sql
: JPA가 생성하는 SQL을 출력한다.ddl-auto
: JPA는 테이블을 자동으로 생성하는 기능을 제공하는데none
을 사용하면 해당 기능을 끈다.
JPA 엔티티 매핑
domain/Member.java
package com.example.practice.domain;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Member {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Entity
: 클래스가 엔티티임을 지정. JPA가 같은 이름을 가진 테이블과 매핑 시킴@Id
: 엔티티의 기본 키를 지정@GeneratedValue
: 기본 키 값에 대한 생성 전략 스펙을 제공- 위와 같이
strategy = GenerationType.IDENTITY
을 지정해 주면 기본 키 생성을 데이터베이스에 위임하는 전략을 설정
JPA 회원 리포지토리
/repository/JpaMemberRepository.java
package com.example.practice.repository;
import java.util.List;
import java.util.Optional;
import com.example.practice.domain.Member;
import jakarta.persistence.EntityManager;
public class JpaMemberRepository implements MemberRepository{
private final EntityManager em;
public JpaMemberRepository(EntityManager em) {
this.em = em;
}
@Override
public Member save(Member member) {
em.persist(member);
return member;
}
@Override
public Optional<Member> findById(Long id) {
Member member = em.find(Member.class, id);
return Optional.ofNullable(member);
}
@Override
public Optional<Member> findByName(String name) {
List<Member> result = em.createQuery("select m from Member m where m.name = :name", Member.class)
.setParameter("name", name)
.getResultList();
return result.stream().findAny();
}
@Override
public List<Member> findAll() {
return em.createQuery("select m from Member m", Member.class)
.getResultList();
}
}
EntityManager
: 데이터베이스와의 연결 정보, 테이블과 매핑된 엔티티 정보 등을 가지고 있는 인터페이스로 스프링이 생성해 주고 DI도 가능하다.persist
: 객체를 테이블에 삽입(저장)find
: 지정된 클래스 및 기본 키의 엔터티를 검색createQuery
: Jakarta Persistence 쿼리 언어 문을 실행하기 위한TypedQuery
인스턴스를 생성getResultList()
:SELECT
쿼리를 실행하고 쿼리 결과를List
로 반환
Jakarta Persistence 쿼리 언어 문은 보통 JPQL라고 줄여서 부르며 객체지향 쿼리 언어다. JPA에서 해당 JPQL을 분석한 다음 적절한 SQL로 변환해 주어서 데이터베이스에서 데이터를 가져오게 된다.
(참고 : https://docs.spring.io/spring-data/jpa/docs/current/reference/html/)
위 예제에서 알 수 있는 점은 간단한 삽입이나 조회는 특별한 구현 없이 이미 JPA 구현체인 Hiberate에서 구현되어 있기 때문에 코드가 매우 간결해졌다는 것이다. 그리고 이 구현체는 데이터베이스 테이블이 아닌 객체와 매핑된 엔티티에 맞춰져 있기 때문에, 코드 상에서 조회의 결과 값을 그냥 객체처럼 사용할 수 있다.
또한 자신의 엔티티 스펙에 맞춰진 특정 조회 로직같은 경우는 JPQL 문을 사용하면 되기 때문에 보다 간결하고 유연하게 데이터 접근 로직을 구현할 수 있다.
(각 메서드에 대한 보다 자세한 내용은 jakarta 공식 문서 참고)
서비스 계층에 트랜잭션 추가
service/MemberService.java
import org.springframework.transaction.annotation.Transactional;
@Transactional
public class MemberService {
// ...
org.springframework.transaction.annotation.Transactional
를 사용
스프링은 해당 클래스의 메서드를 실행할 때 트랜잭션을 시작하고, 메서드가 정상 종료되면 트랜잭션을 커밋한다. 만약 런타임 예외가 발생하면 롤백한다.
JPA를 통한 모든 데이터 변경은 트랜잭션 안에서 실행해야 한다.
JPA를 사용하도록 스프링 설정 변경
SpringConfig.java
// ...
@Configuration
public class SpringConfig {
private final DataSource dataSource;
private final EntityManager em; // 추가
public SpringConfig(DataSource dataSource, EntityManager em) {
this.dataSource = dataSource;
this.em = em;
}
@Bean
MemberService memberService() {
return new MemberService(memberRepository());
}
@Bean
MemberRepository memberRepository() {
// return new MemoryMemberRepository();
// return new JdbcMemberRepository(dataSource);
// return new JdbcTemplateMemberRepository(dataSource);
return new JpaMemberRepository(em);
}
}
이전과 마찬가지로 MemberRepository
구현체만 갈아 끼우면 된다.
JPA는 이처럼 개발자에게 말도 안되는 편리함을 준다. 하지만 잘 사용하는 것은 또 다른 문제다.
JPA는 10년 이상 된 기술이기 때문에 자세히 알기 위해서는 공부해야 하는 양이 상당하다. 데이터를 접근하는 민감한 기술이기 때문에 실무에서 사용하기 위해서는 많은 공부와 연습이 필요하다.
Reference
'Spring&Spring Boot' 카테고리의 다른 글
[Spring Boot] Spring Data JPA 페이징/정렬 처리 (0) | 2023.03.09 |
---|---|
[Spring Boot] 입문 - Spring Data JPA 맛보기 (0) | 2023.02.25 |
[Spring Boot] 입문 - JPA를 사용하는 이유 (0) | 2023.02.23 |
[Spring Boot] 입문 - JDBC Template(feat. 스프링 통합 테스트) (0) | 2023.02.21 |
[Spring Boot] 입문 - 순수 JDBC로 DB 연결하기(feat. mysql) - 2 (1) | 2023.02.17 |
- Total
- Today
- Yesterday
- 스프링 mvc
- 파이썬 for Beginner 솔루션
- Do it! 정직하게 코딩하며 배우는 딥러닝 입문
- Gradle
- git branch
- 스프링
- 쉘 코드
- 스프링 테스트
- Spring Boot
- 패킷 스위칭
- Thymeleaf
- 스프링 컨테이너
- Python Cookbook
- Spring
- spring mvc
- git merge
- jsp
- 프로그래머스
- JPA
- 쉽게 배우는 운영체제
- git
- Computer_Networking_A_Top-Down_Approach
- 생활코딩 javascript
- 지옥에서 온 git
- 선형 회귀
- 파이썬 for Beginner 연습문제
- Spring Data JPA
- 방명록 프로젝트
- 김영환
- 운영체제 반효경
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |