๐Ÿ–ฅ๏ธ Web Development Study/Back-End

[Back-end] ์Šคํ”„๋ง ์ž…๋ฌธ :: ์Šคํ”„๋ง DB ์ ‘๊ทผ ๊ธฐ์ˆ 

ibelieveinme 2025. 1. 29. 14:13
728x90

*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 ๋กœ ์ˆ˜์ •ํ•ด๋†“์ž.

 

728x90