• Home
  • About
    • on Weekend photo

      on Weekend

      ๐™Ž๐™ฉ๐™ช๐™™๐™ฎ๐™ž๐™ฃ๐™œ

    • Learn More
    • Instagram
    • Github
  • Archive
    • All Posts
    • All Tags
    • All Categories
  • Categories
    • Problem Solving
    • TIL
    • Study
    • Etc
    • ํ•„์‚ฌ
  • Projects

Spring Study - 6

15 Dec 2020

6. ์Šคํ”„๋ง DB ์ ‘๊ทผ ๊ธฐ์ˆ 

๋ชฉ์ฐจ

  1. H2 ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค์น˜
  2. ์ˆœ์ˆ˜ JDBC
  3. ์Šคํ”„๋ง ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ
  4. ์Šคํ”„๋ง JdbcTemplate
  5. JPA
  6. ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA

์ˆ˜๊ฐ• ์ฝ”์Šค๋Š” ์ธํ”„๋Ÿฐ ์Šคํ”„๋ง ์ž…๋ฌธ ๊ฐ•์˜๋ฅผ ๋“ฃ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.


H2 ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค์น˜

  • ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ์˜ ์—ญ์‚ฌ
    1. JDBC๋ฅผ ์ด์šฉํ•ด DB์™€ Spring์„ ์—ฐ๊ฒฐ
    2. ์Šคํ”„๋ง์ด ์ดํ›„ JDBC ํ…œํ”Œ๋ฆฟ์œผ๋กœ ํŽธ๋ฆฌํ•˜๊ฒŒ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ๋ฐฉ๋ฒ•์„ ๋„์ž…
    3. ์ดํ›„์—๋Š” SQL ์กฐ์ฐจ๋„ ์ง์ ‘ ์งœ๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์กฐํšŒ์ฟผ๋ฆฌ ๋“ฑ์„ ๋‚ ๋ ค์ฃผ๋Š” JPA๋ผ๋Š” ๊ธฐ์ˆ ๋กœ ๊ฐ์ฒด๋ฅผ ๋ฐ”๋กœ DB์— ์ฟผ๋ฆฌ์—†์ด ์ €์žฅํ•ด์ฃผ๋Š” ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•œ๋‹ค. ์ด๋ฅผ ์Šคํ”„๋ง์—์„œ ํŽธ๋ฆฌํ•˜๊ฒŒ ์“ธ ์ˆ˜ ์žˆ๋„๋ก ํ•œ ๋ฒˆ ๊ฐ์‹ผ ๊ธฐ์ˆ ์„ ์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA๋ผ๊ณ  ํ•œ๋‹ค.
  • H2๋Š” ๋ฉ”๋‰ด์–ผ์„ ๋”ฐ๋ผ ํ•˜๋ฉด ๋œ๋‹ค.
drop table if exists member CASCADE;
create table member
(
 id bigint generated by default as identity,
 name varchar(255),
 primary key (id)
);

์œ„์˜ ์ฝ”๋“œ๋ฅผ H2์— ์ž…๋ ฅํ•˜์—ฌ ํ…Œ์ด๋ธ” ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ sql/ddl.sql์„ ์ƒ์„ฑํ•ด์ค€๋‹ค. id๋Š” ์ž๋ฐ”์—์„œ๋Š” long์ด๊ณ  db์—์„œ๋Š” bigint๋ฅผ ์‚ฌ์šฉํ–ˆ๊ณ , generated by default as identity๋Š” null๋กœ ๋“ค์–ด์˜ค๋”๋ผ๋„ ์ž๋™์œผ๋กœ ๊ฐ’์„ ์ฑ„์›Œ์ค€๋‹ค.


์ˆœ์ˆ˜ JDBC

์•„์ฃผ ์˜ˆ์ „ ๋ฐฉ์‹์˜ ๋ฐ์ดํ„ฐ์ €์žฅ๊ธฐ์ˆ ๋กœ, ์—ญ์‚ฌ๋ฅผ ๋“ฃ๋Š”๋‹ค๋Š” ์ƒ๊ฐ์œผ๋กœ ํ‚ค์›Œ๋“œ๋งŒ ์ •๋ฆฌํ•˜๋ฉด ๋œ๋‹ค๊ณ  ํ•˜์‹ ๋‹ค.

private final DataSource dataSource; //DB์— ๋ถ™๊ธฐ ์œ„ํ•œ ๋ฐ์ดํ„ฐ์†Œ์Šค

public JdbcMemberRepository(DataSource dataSource) {
    this.dataSource = dataSource;
}

@Override
public Member save(Member member) {
    String sql = "insert into member(name) values(?)";
    Connection conn = dataSource.getConnection();
    PreparedStatement pstmt = conn.prepareStatement(sql);
    pstmt.setString(1, member.getName());
    //..์–ด์ฉŒ๊ตฌ์ €์ฉŒ๊ตฌ..
    pstmt.executeUpdate();
    return null;
}

์ด๋Ÿฐ ์‹์œผ๋กœ ์ง„ํ–‰๋˜๋Š”๋ฐ, ๊ฐ ๋ฉ”์†Œ๋“œ๋ฅผ ๋‹ค ์ง€์ •ํ•ด์ฃผ์–ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋…ธ๊ฐ€๋‹ค ์ž‘์—…์ด๋‹ค.

  • ๋‹คํ˜•์„ฑ์„ ์ด์šฉํ•ด ๋น ๋ฅด๊ฒŒ ํ™•์žฅ์ด ๊ฐ€๋Šฅํ•˜๋‹ค
    => ๊ฐœ๋ฐฉ-ํ์‡„ ์›์น™ (OCP, Open-Closed Princople)

    ํ™•์žฅ์—๋Š” ์—ด๋ ค์žˆ๊ณ , ์ˆ˜์ •, ๋ณ€๊ฒฝ์—๋Š” ๋‹ซํ˜€์žˆ๋‹ค. <= ๊ฐ์ฒด์ง€ํ–ฅ์˜ ์žฅ์  (๊ตฌํ˜„์ œ ๋ณ€๊ฒฝ ์—†์ด ์‰ฝ๊ฒŒ ํ™•์žฅ์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ์ )

์Šคํ”„๋ง ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ

  • ์Šคํ”„๋ง + DB ๋ฅผ ํ†ตํ•ฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ
  • @Transactional
    • DB๋Š” commit ์ „์—๋Š” ์ฟผ๋ฆฌ๊ฐ€ ์ ์šฉ์ด ์•ˆ๋œ๋‹ค(ํŠธ๋žœ์žญ์…˜). ํ…Œ์ŠคํŠธ ์‹œ์ž‘ ์ „์— ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•˜๊ณ , ํ…Œ์ŠคํŠธ๊ฐ€ ๋๋‚˜๋ฉด ๋กค๋ฐฑ์„ ํ•ด์ฃผ๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ด๋‹ค.
    • ๋กค๋ฐฑ์„ ํ•ด์ฃผ๋ฏ€๋กœ ํ…Œ์ŠคํŠธ ์—ฌ๋Ÿฌ๊ฐœ๋ฅผ ๋ฐ˜๋ณตํ•  ์ˆ˜ ์žˆ๋‹ค.
  • @SpringBootTest
    • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์™€ ํ…Œ์ŠคํŠธ๋ฅผ ๊ฐ™์ด ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ.
      <-> ๋‹จ์ผ ํ…Œ์ŠคํŠธ
      ์ž๋ฐ” ์ฝ”๋“œ? ๋ฉ”์†Œ๋“œ ํ•˜๋‚˜์˜ ๋‹จ์œ„๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋Š” ๊ฒƒ. ์‹œ๊ฐ„๋„ ์งง๊ฒŒ ๊ฑธ๋ฆฌ๊ณ , ๋ณด๋‹ค ์ •ํ™•ํ•˜๊ฒŒ ํ…Œ์ŠคํŠธํ•  ํ™•๋ฅ ์ด ๋†’์œผ๋ฏ€๋กœ ๋‹จ์ผํ…Œ์ŠคํŠธ๋กœ๋„ ๋ชจ๋‘ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•˜๊ฒŒ๋” ํ…Œ์ŠคํŠธ๋ฅผ ์„ค๊ณ„ํ•ด์•ผ ํ•œ๋‹ค.

์Šคํ”„๋ง JdbcTemplate

  • ๋งˆ์ด๋ฐ”ํ‹ฐ์Šค์™€ ์œ ์‚ฌํ•œ ๋А๋‚Œ
  • JDBC API ์ค‘๋ณต ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•ด์ค€๋‹ค. ์‹ค๋ฌด์—์„œ ๋งŽ์ด ์“ด๋‹ค.
  • ์ƒ์„ฑ์ž๊ฐ€ ํ•˜๋‚˜๋ฉด @autowired๋ฅผ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ๋‹ค.

JPA

  • JPA๋Š” SQL, ๋ฐ์ดํ„ฐ ์ค‘์‹ฌ์„ค๊ณ„์—์„œ ๊ฐ์ฒด์ค‘์‹ฌ์„ค๊ณ„๋กœ ์˜ฎ๊ฒจ์ค€๋‹ค.
  • spring.jpa.show-sql = true : jpa๊ฐ€ ๋‚ ๋ฆฌ๋Š” sql์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
  • spring.jpa.hibernate.ddl-auto=none
    • hibernate๋Š” ์ž๋ฐ” ๊ฐ์ฒด๋ฅผ RDMS์˜ ํ•˜๋‚˜์˜ ROW๋กœ ๋งคํ•‘ํ•ด์ค€๋‹ค.
    • ddl-auto ์„ค์ •์„ ํ†ตํ•ด ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์˜ฌ๋ผ๊ฐˆ ๋•Œ Data Source์— ์ ‘๊ทผํ•ด ์ž๋™์œผ๋กœ DBMS์— ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค. (ํ•ด๋‹น ๊ฐ•์˜์—์„œ๋Š” none์œผ๋กœ ์„ค์ •ํ•˜์—ฌ ์‚ฌ์šฉ์„ ํ•ด์ œํ•ด์ค€๋‹ค.)
  • @Entity
    • JPA ์‚ฌ์šฉ์„ ์œ„ํ•œ ์–ด๋…ธํ…Œ์ด์…˜์ด๋‹ค. JPA๋Š” ์ž๋ฐ” ์ง„์˜ ํ‘œ์ค€ ์ธํ„ฐํŽ˜์ด์Šค์ด๊ณ , ๊ตฌํ˜„์ฒด ์ค‘ ํ•˜๋‚˜๊ฐ€ Hibernate์ด๋‹ค.
      • Hibernate๋Š” ORM์œผ๋กœ, Object Relational Mapping์„ ์˜๋ฏธํ•œ๋‹ค. (Object๋ฅผ Relational-DBMS ROW๋กœ ๋งคํ•‘ํ•ด์ค€๋‹ค.)
@Entity
public class Member {
  @Id @GeneratedValue(...)
  .
  .
  .
  private Long id;
  private String name;
  Getter and Setter . . .
}

์ด๋Ÿฐ ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ ํด๋ž˜์Šค(?)์˜ ์œ„์— @Entity ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ์ฃผ๋ฉด ์ดํ•˜์˜ ํด๋ž˜์Šค๋ฅผ hibernate๊ฐ€ ๊ด€๋ฆฌํ•˜๊ฒŒ ๋œ๋‹ค.

  • @Id : pk(primary key)๋กœ ์‚ฌ์šฉํ•œ๋‹ค
  • @GeneratedValue(strategy = GenerationType.IDENTITY) : Id์ฒ˜๋Ÿผ DB๊ฐ€ pk๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ด์ค€๋‹ค.

  • EntityManager : JPA์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์ธ์Šคํ„ด์Šค๋กœ, ์ด๋ฅผ ์‚ฌ์šฉํ•ด DB์™€ ํ†ต์‹ ํ•œ๋‹ค.
    • ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‚ฌ์ด์— ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ(Persistence Context)๋ผ๋Š” ๊ฐœ๋…์„ ๋‘๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ฒŒ ๋œ๋‹ค.
    • ์ด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด EntityManager๊ฐ€ insert ์ฟผ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด์„œ ๋„ฃ์–ด์ฃผ๊ณ , get name ๋“ฑ ๊นŒ์ง€ ์ž๋™์œผ๋กœ ๋‹ค ํ•ด์ค€๋‹ค.
    • ํ•ญ์ƒ @Transactional์ด ๋ถ™์–ด์žˆ์–ด์•ผ ์ž‘๋™ํ•œ๋‹ค.
package hello.hellospring.repository;

import hello.hellospring.domain.Member;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.transaction.Transactional;
import java.util.List;
import java.util.Optional;

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();
    }
}

๋ณด๋ฉด ์ผ๋ฐ˜ sql ์ฟผ๋ฆฌ์™€๋Š” ๋‹ค๋ฅด๊ฒŒ ์ง„ํ–‰๋œ๋‹ค.

  • save์˜ ๊ฒฝ์šฐ์—๋„ persist ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด EntityManager์— member๋ฅผ ๋„ฃ๋Š” ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค. (return member ํ•ด์ค€๊ฑด, ์‚ฌ์‹ค ์•ˆํ•ด์ค˜๋„ ๋˜์ง€๋งŒ ์ด์ „์— Test๋ฅผ ์ € ๋ฐฉ์‹์œผ๋กœ ์งฐ๊ธฐ ๋•Œ๋ฌธ์— ์ถ”๊ฐ€)
  • findById๋ฅผ ๋ณด๋ฉด sql ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ฆฌ์ง€ ์•Š๊ณ , EntityManager์˜ find ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์ฐพ์•„์ค€๋‹ค.
  • findByName๊ณผ findAll์„ ๋ณด๋ฉด SQL ์ฟผ๋ฆฌ์™€ ๋‹ค๋ฅด๊ฒŒ Member m ๊ฐ์ฒด๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ›์•„์™€์„œ, result๋กœ ๋„˜๊ฒจ์ฃผ๊ณ , ์ด๋ฅผ List๋กœ ๋งŒ๋“ค์–ด returnํ•ด์ฃผ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. (findByName์€ stream().findAny() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ์ŠคํŠธ๋ฆผ์—์„œ ์ฒซ ๋ฒˆ์งธ ์š”์†Œ๋ฅผ ์ฐธ์กฐํ•˜๋Š” Optional ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ฃผ๊ณ  ์žˆ๋‹ค.)

์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA

  • ์ธํ„ฐํŽ˜์ด์Šค๋งŒ์œผ๋กœ๋„ ๊ฐœ๋ฐœ์ด ๊ฐ€๋Šฅํ•ด์ง€๋ฉฐ, ๋‹จ์ˆœ๋ฐ˜๋ณต์ด๋ผ ์ƒ๊ฐ๋˜๋Š” ๊ฐœ๋ฐœ์  ์š”์†Œ๋ฅผ ์—†์•จ ์ˆ˜ ์žˆ์–ด ๊ฐœ๋ฐœ์ƒ์‚ฐ์„ฑ ์ฆ๋Œ€ ๊ฐ€๋Šฅ
  • ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ์žˆ์œผ๋ฉด Bean์— ์ž๋™์œผ๋กœ ๋“ฑ๋กํ•ด์ค€๋‹ค.
  • findById๊ฐ€ JPA์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณต์ด ๋œ๋‹ค. pk ๊ฒ€์ƒ‰๋„ ๊ฐ€๋Šฅํ•˜๊ณ , ์™ ๋งŒํ•œ ๊ณตํ†ต ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๋‹ค ์ œ๊ณต๋œ๋‹ค.



springbackend Share Tweet +1