6. ์คํ๋ง DB ์ ๊ทผ ๊ธฐ์
๋ชฉ์ฐจ
- H2 ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค์น
- ์์ JDBC
- ์คํ๋ง ํตํฉ ํ ์คํธ
- ์คํ๋ง JdbcTemplate
- JPA
- ์คํ๋ง ๋ฐ์ดํฐ JPA
์๊ฐ ์ฝ์ค๋ ์ธํ๋ฐ ์คํ๋ง ์ ๋ฌธ ๊ฐ์๋ฅผ ๋ฃ๊ณ ์์ต๋๋ค.
H2 ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค์น
- ๋ฐ์ดํฐ ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ ์ญ์ฌ
- JDBC๋ฅผ ์ด์ฉํด DB์ Spring์ ์ฐ๊ฒฐ
- ์คํ๋ง์ด ์ดํ JDBC ํ ํ๋ฆฟ์ผ๋ก ํธ๋ฆฌํ๊ฒ ์ฐ๊ฒฐํด์ฃผ๋ ๋ฐฉ๋ฒ์ ๋์
- ์ดํ์๋ 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๋ก ๋งคํํด์ค๋ค.)
- JPA ์ฌ์ฉ์ ์ํ ์ด๋
ธํ
์ด์
์ด๋ค. JPA๋ ์๋ฐ ์ง์ ํ์ค ์ธํฐํ์ด์ค์ด๊ณ , ๊ตฌํ์ฒด ์ค ํ๋๊ฐ Hibernate์ด๋ค.
@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 ๊ฒ์๋ ๊ฐ๋ฅํ๊ณ , ์ ๋งํ ๊ณตํต ์ธํฐํ์ด์ค๊ฐ ๋ค ์ ๊ณต๋๋ค.