*JPA: Java Persistence API.
์๋ฐ์์ ๊ฐ์ฒด๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํ๊ณ ๊ด๋ฆฌํ๊ธฐ ์ํ ์ธํฐํ์ด์ค์ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ API.
Jdbc > JPA๋ก ์งํํ๋ฉฐ ์ฟผ๋ฆฌ ์์ด ๊ฐ์ฒด๋ฅผ DB์ ์ ์ฅํ ์ ์๊ฒ ๋จ.
*JPA ์ฅ์ : ๊ธฐ์กด์ ๋ฐ๋ณต ์ฝ๋๋ ๋ฌผ๋ก ์ด๊ณ ๊ธฐ๋ณธ์ ์ธ SQL ๋ JPA ๊ฐ ์ง์ ๋ง๋ค์ด์ ์คํํด์ค๋ค.
SQL๊ณผ ๋ฐ์ดํฐ ์ค์ฌ์ ์ค๊ณ์์ ๊ฐ์ฒด ์ค์ฌ์ ์ค๊ณ๋ก ํจ๋ฌ๋ค์์ ์ ํํ ์ ์๋ค.
๊ฐ๋ฐ ์์ฐ์ฑ ๋์ด๊ธฐ !
๊ต์ก์ฉ์ผ๋ก ์ข์ ๊ฐ๋ฒผ์ด DB๋ฅผ ์ค์นํด ๋ณด์.
1. H2 Database Engine ์ค์น
https://www.h2database.com/html/main.html
H2 Database Engine
H2 Database Engine Welcome to H2, the Java SQL database. The main features of H2 are: Very fast, open source, JDBC API Embedded and server modes; in-memory databases Browser based Console application Small footprint: around 2.5 MB jar file size Supp
www.h2database.com
window ๋ window ์ฉ ๋ค์ด๋ก๋.
2. H2 > bin > h2.bat ์คํ
3. H2 Database ์ฌ์ฉํ๊ธฐ
ํ์ผ๊ฒฝ๋ก๋ฅผ ๋งํด์ค. jdbc:h2:~/test
์ฐ๊ฒฐ์ ๋๋ฅด๋ฉด DB ํ๋ฉด์ผ๋ก ๋ค์ด๊ฐ๊ฒ ๋จ.
์ผ์ชฝ์๋จ ๋นจ๊ฐ์ ๋๊ทธ๋ผ๋ฏธ 2๊ฐ ๋ฒํผ ๋๋ฅด๋ฉด ๋๊ฐ์ง.
์ปดํจํฐ home(user) ๊ฒฝ๋ก์ test.mv.db ํ์ผ์ด ์๋์ง ํ์ธํ๊ธฐ.
ํ์ผ๋ก ์ ๊ทผํ๋ฉด ๋์ ์ ๊ทผ์ ์ถฉ๋ ๋ฑ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์๋ค. ์์ผ์ ํตํด ์ ๊ทผํ๋๋ก ์๋ ๊ฒฝ๋ก๋ก ์ ๊ทผํ์.
JDBC URL: jdbc:h2:tcp://localhost/~/test
4. member ํ ์ด๋ธ ๋ง๋ค๊ธฐ.
drop table if exists member CASCADE;
create table member
(
id bigint generated by default as identity,
name varchar(255),
primary key (id)
);
MEMBER ํ ์ด๋ธ์ด ๋ง๋ค์ด์ง ๋ชจ์ต!
5. MEMBER ํ ์ด๋ธ ์กฐํํ๊ธฐ
ํ ์ด๋ธ ์ ์ฒด ๋ชฉ๋ก ์กฐํ๋ select * from member; ๋ฅผ ์ ๋ ฅํ๋๊ฐ
input field ์ ์๋ฌด๊ฒ๋ ์๋ ์ํ์์ MEMBER TABLE ์ ํด๋ฆญํ๋ฉด ๋ณด์ธ๋ค.
6. MEMBER ํ ์ด๋ธ ์ถ๊ฐํ๊ธฐ
insert into member(name) values('spring1')
JPA ์ฌ์ฉ์ ์ํ ํ๊ฒฝ ์ ํ ์ ํด๋ณด์.
1. build.gradle ํ์ผ์ JPA dependency ์ถ๊ฐ
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
hibernate 2๊ฐ ์ค์น ๋์๋์ง ํ์ธ.
2. resources > application.properties ์ JPA ์ค์ ์ถ๊ฐ.
1) spring.jpa.show-sql=true : JPA ๊ฐ ๋ ๋ฆฌ๋ SQL ์ ๋ณผ ์ ์์.
2) spring.jpa.hibernate.ddl-auto=none : auto ๋ฅผ true ๋ก ์ผ๋ฉด ๊ฐ์ฒด๋ฅผ ๋ณด๊ณ ํ ์ด๋ธ์ ๋ง๋ค์ด์ค๋ค. ์ง๊ธ์ member ํ ์ด๋ธ์ด ์ด๋ฏธ ๋ง๋ค์ด์ ธ ์์ผ๋ none ์ผ๋ก ๋๊ณ ์์ํ๋ ๊ฒ.
3. Member ๊ฐ์ฒด์ ๋งตํ
ORM(Object-Relational Mapping)
package com.yoonsung.firstproject.domain;
import jakarta.persistence.*;
@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;
}
}
1) JPA ๊ฐ ๊ด๋ฆฌํ๋ Entity๋ผ๊ณ ๋ช ์
2) PK ์ strategy ๋ช ์. ์๋์ผ๋ก ๋ช ์๋๋ ID ๋ฅผ Identity ์ ๋ต์ด๋ผ๊ณ ๋ถ๋ฆ.
+ Column ๋ฑ์ ๋ช ์๋ ๊ฐ๋ฅ.
4. JpaMemberRepository ํด๋์ค ์์ฑ
package com.yoonsung.firstproject.repository;
import com.yoonsung.firstproject.domain.Member;
import jakarta.persistence.EntityManager;
import jakarta.transaction.Transactional;
import java.util.List;
import java.util.Optional;
@Transactional
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();
}
}
1) JPA ๋ EntityManager๋ก ๋์ํ๋ค. Spring Boot ๊ฐ EntityManager๋ฅผ ๋ง๋ค์ด์ค์ ์ฐ๋ฆฐ ์ด๊ฑธ Dependency Injection ๋ง ํ๋ฉด ๋๋ค.
2) em.persist() ํจ์๋ก ํ ์ด๋ธ์ ๋ฃ์ด์ค๋ค.
3) em.find() ํจ์๋ก ์กฐํ ๊ฐ๋ฅ.
4) createQuery() ํจ์ ์์ ์ฟผ๋ฆฌ ์์ฑ. entity๋ฅผ ๋์์ผ๋ก ์กฐํ๊ฐ๋ฅ. m !
5) Spring Data JPA ์ฌ์ฉํ๋ฉด findByName(), findAll()๋ ์ญ์ ๊ฐ๋ฅ. ์ถํ ๋ฐฐ์.
6) ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝ์ Transaction ์ด ํ์ํ๋ค. Transaction ์์์ ์คํ๋์ด์ผ ํ๋ค.
5. SpringConfig ํ์ผ์ ์ฐ๊ฒฐ
package com.yoonsung.firstproject;
import com.yoonsung.firstproject.repository.JpaMemberRepository;
import com.yoonsung.firstproject.repository.MemberRepository;
import com.yoonsung.firstproject.service.MemberService;
import jakarta.persistence.EntityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
private EntityManager em;
@Autowired
public SpringConfig(EntityManager em){
this.em = em;
}
@Bean
public MemberService memberService(){return new MemberService(memberRepository());}
@Bean
public MemberRepository memberRepository() {
return new JpaMemberRepository(em);
}
}
SpringConfig ํด๋์ค์ memberRepository()๋ฅผ ํธ์ถํ์ ๋ JpaMemberRepository ๋ฅผ ๋ฐํํ๋๋ก ์ถ๊ฐ ๋ณ๊ฒฝ.
6. Test ์ฝ๋ ์คํ
package com.yoonsung.firstproject.service;
import com.yoonsung.firstproject.domain.Member;
import com.yoonsung.firstproject.repository.MemberRepository;
import jakarta.transaction.Transactional;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
@SpringBootTest
@Transactional
class MemberServiceIntegrationTest {
@Autowired MemberService memberService;
@Autowired MemberRepository memberRepository;
@Test
void ํ์๊ฐ์
(){
//given
Member member = new Member();
member.setName("spring");
//when
Long saveId = memberService.join(member);
//then
Member findMember = memberService.findOne(saveId).get();
assertThat(member.getName()).isEqualTo(findMember.getName());
}
@Test
public void ์ค๋ณต_ํ์_์์ธ(){
//given
Member member1 = new Member();
member1.setName("spring");
Member member2 = new Member();
member2.setName("spring");
//when
memberService.join(member1);
IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));
//then
assertThat(e.getMessage()).isEqualTo("์ด๋ฏธ ์กด์ฌํ๋ ํ์์
๋๋ค.");
}
}
Spring Data JPA
: JPA ๋ฅผ ๋ ์ฝ๊ฒ ์ฌ์ฉํ๊ธฐ ์ํ Spring Data ํ๋ ์์ํฌ.
1. SpringDataJpaMemberRepository ์ธํฐํ์ด์ค ์์ฑ
import com.yoonsung.firstproject.domain.Member;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface SpringDataJpaMemberRepository extends JpaRepository<Member, Long>, MemberRepository {
@Override
Optional<Member> findByName(String name);
}
interface ๋ง ๋ง๋ค์ด ๋๊ณ JpaRepository ๋ฅผ ์์๋ฐ์ ๋์ผ๋ฉด Spring Data JPA ๊ฐ SpringDataJpaMemberRepository ๋ฅผ ์คํ๋ง ๋น์ผ๋ก ์๋ ๋ฑ๋กํด์ค๋ค.
์ธํฐํ์ด์ค ์์ ์ด๋ฆ๋ง ํน์ ๊ท์น์ ๋ง์ถฐ์ฃผ๋ฉด ๋๋ค.
findByName ์ ์๋์ ๊ฐ์ ์๋ฏธ๊ฐ ์จ๊ฒจ์ ธ ์๋ค.
select m from Member m where m.name = ?
ex. findByEmail(), findByNameAndId(String name, Long id) ์ฒ๋ผ ๋ฉ์๋ ์ด๋ฆ ๋ง์ผ๋ก ์กฐํ ๊ธฐ๋ฅ์ด ์ ๊ณต๋๋ค.
JpaRepository ํด๋์ค๊ฐ ๊ธฐ๋ณธ CRUD ๋ฅผ ์ ๊ณตํด์ ๋ค๋ฅธ ํจ์๋ ํ์ ์๋ค.
2. SpringConfig ์์
import com.yoonsung.firstproject.repository.MemberRepository;
import com.yoonsung.firstproject.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SpringConfig {
private final MemberRepository memberRepository;
@Autowired
public SpringConfig(MemberRepository memberRepository){
this.memberRepository = memberRepository;
}
@Bean
public MemberService memberService(){
return new MemberService(memberRepository);
}
// @Bean
// public MemberRepository memberRepository() {
// return new JpaMemberRepository(em);
// }
}
Spring Config ํ์ผ์ EntityManager ์ง์ฐ๊ณ MemberRepository ๋ก ์์ ํด๋์.
'๐ฅ๏ธ Web Development Study > Back-End' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Back-End][์คํ๋ง ๋ถํธ 3 ์๋ฐ ๋ฒก์๋ ๊ฐ๋ฐ ์ ๋ฌธ] Part1. Spring Boot (0) | 2025.02.02 |
---|---|
[Back-end] ์คํ๋ง ์ ๋ฌธ :: AOP (1) | 2025.01.29 |
[Back-end] ์คํ๋ง ์ ๋ฌธ :: ํ์ ๊ด๋ฆฌ ์์ - ์น MVC ๊ฐ๋ฐ (1) | 2025.01.29 |
[Back-End] ์คํ๋ง ์ ๋ฌธ :: ์คํผ๋ง ๋น๊ณผ ์์กด๊ด๊ณ (1) | 2025.01.23 |
[Back-End] ์คํ๋ง ์ ๋ฌธ :: ํ์ ๊ด๋ฆฌ ์์ - ๋ฐฑ์๋ ๊ฐ๋ฐ (0) | 2024.12.25 |