๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

WINK-(Web & App)/Spring Boot ์Šคํ„ฐ๋””

[2025 1ํ•™๊ธฐ ์Šคํ”„๋ง ๋ถ€ํŠธ ์Šคํ„ฐ๋””] ์ด์ƒ๋ž˜ #6์ฃผ์ฐจ

๋ฐ˜์‘ํ˜•

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

์ด๋ฒˆ์ฃผ๋Š” ๊ณต๋ถ€๋ฅผ ํ•˜๊ธฐ์ „์— ๋จผ์ € DB๋ฅผ ์„ค์น˜ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค

 

์„ค์น˜๋Š” ๊ฐ„๋‹จํ•˜๊ฒŒ ํด๋ฆฌ์–ด ํ•ด์คฌ์Šต๋‹ˆ๋‹ค!!


๐Ÿ”  ์ˆœ์ˆ˜ Jdbc

์ด์ œ ๋ฌด์Šจ ์ด๊ฒƒ์ €๊ฒƒ ์„ค์ •์„ ํ•˜๋Š”๋ฐ ์ข€ ์–ด๋ ค์›Œ์„œ ๋“ค์œผ๋ฉด์„œ ์ •๋ฆฌ ํ•ด๋ณผ๊ฒŒ์š”

@Override
public Member save(Member member) {
String sql = "insert into member(name) values(?)";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = getConnection();
pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
pstmt.setString(1, member.getName());
pstmt.executeUpdate();
rs = pstmt.getGeneratedKeys();
if (rs.next()) {
member.setId(rs.getLong(1));
} else {
throw new SQLException("id ์กฐํšŒ ์‹คํŒจ");
}
return member;
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
close(conn, pstmt, rs);
}
}
  • rs : ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์Œ
  • members์—์„œ id๋ž‘ ์ด๋ฆ„์„ ๋ฐ›์•„์˜ด

์–˜๋งŒ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹คํ–‰์„ ํ•ด์คฌ๋Š”๋ฐ
์ด๋ ‡๊ฒŒ ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค !!

 

- ๊ฐœ๋ฐฉ-ํ์‡„ ์›์น™(OCP, Open-Closed Principle)

- ํ™•์žฅ์—๋Š” ์—ด๋ ค์žˆ๊ณ , ์ˆ˜์ •, ๋ณ€๊ฒฝ์—๋Š” ๋‹ซํ˜€์žˆ๋‹ค.

- ์Šคํ”„๋ง์˜ DI (Dependencies Injection)์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ์ „ํ˜€ ์†๋Œ€์ง€ ์•Š๊ณ , ์„ค์ •๋งŒ์œผ๋กœ ๊ตฌํ˜„ ํด

๋ž˜์Šค๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.


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

@SpringBootTest
@Transactional
class MemberServiceIntegrationTest {
@Autowired MemberService memberService;
@Autowired MemberRepository memberRepository;
@Test
public void ํšŒ์›๊ฐ€์ž…() throws Exception {
//Given
Member member = new Member();
member.setName("hello");
//When
Long saveId = memberService.join(member);
//Then
Member findMember = memberRepository.findById(saveId).get();
assertEquals(member.getName(), findMember.getName());
}
@Test
public void ์ค‘๋ณต_ํšŒ์›_์˜ˆ์™ธ() throws Exception {
//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));//์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ด์•ผ ํ•œ๋‹ค.
assertThat(e.getMessage()).isEqualTo("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.");
}
}

@SpringBootTest` : ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์™€ ํ…Œ์ŠคํŠธ๋ฅผ ํ•จ๊ป˜ ์‹คํ–‰ํ•œ๋‹ค.

@Transactional` : ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์— ์ด ์• ๋…ธํ…Œ์ด์…˜์ด ์žˆ์œผ๋ฉด, ํ…Œ์ŠคํŠธ ์‹œ์ž‘ ์ „์— ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•˜๊ณ , ํ…Œ

์ŠคํŠธ ์™„๋ฃŒ ํ›„์— ํ•ญ์ƒ ๋กค๋ฐฑํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด DB์— ๋ฐ์ดํ„ฐ๊ฐ€ ๋‚จ์ง€ ์•Š์œผ๋ฏ€๋กœ ๋‹ค์Œ ํ…Œ์ŠคํŠธ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค.


๐Ÿ”  ์Šคํ”„๋ง JdbcTemplate

- ์ˆœ์ˆ˜ Jdbc์™€ ๋™์ผํ•œ ํ™˜๊ฒฝ์„ค์ •์„ ํ•˜๋ฉด ๋œ๋‹ค.

- ์Šคํ”„๋ง JdbcTemplate๊ณผ MyBatis ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” JDBC API์—์„œ ๋ณธ ๋ฐ˜๋ณต ์ฝ”๋“œ๋ฅผ ๋Œ€๋ถ€๋ถ„ ์ œ๊ฑฐํ•ด์ค€

๋‹ค. ํ•˜์ง€๋งŒ SQL์€ ์ง์ ‘ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.

 

์Œ.... ์ข€ ์–ด๋ ค์›Œ์š” ๋ญ”์ง€ ์ž˜ ๊ฐ์ด ์•ˆ์˜ต๋‹ˆ๋‹ค..

@Override
public Optional<Member> findById(Long id) {
List<Member> result = jdbcTemplate.query("select * from member where id
= ?", memberRowMapper(), id);
return result.stream().findAny();
}
@Override
public List<Member> findAll() {
return jdbcTemplate.query("select * from member", memberRowMapper());
}
@Override
public Optional<Member> findByName(String name) {
List<Member> result = jdbcTemplate.query("select * from member where
name = ?", memberRowMapper(), name);
return result.stream().findAny();
}
private RowMapper<Member> memberRowMapper() {
return (rs, rowNum) -> {
Member member = new Member();
member.setId(rs.getLong("id"));
member.setName(rs.getString("name"));
return member;
};
}
}

์ด๋Ÿฐ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์„ธํŒ…์„ ํ•ด์ฃผ๊ธด ํ–ˆ์–ด์š”


๐Ÿ”  JPA

- JPA๋Š” ๊ธฐ์กด์˜ ๋ฐ˜๋ณต ์ฝ”๋“œ๋Š” ๋ฌผ๋ก ์ด๊ณ , ๊ธฐ๋ณธ์ ์ธ SQL๋„ JPA๊ฐ€ ์ง์ ‘ ๋งŒ๋“ค์–ด์„œ ์‹คํ–‰ํ•ด์ค€๋‹ค.

- JPA๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, SQL๊ณผ ๋ฐ์ดํ„ฐ ์ค‘์‹ฌ์˜ ์„ค๊ณ„์—์„œ ๊ฐ์ฒด ์ค‘์‹ฌ์˜ ์„ค๊ณ„๋กœ ํŒจ๋Ÿฌ๋‹ค์ž„์„ ์ „ํ™˜์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

- JPA๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ์„ ํฌ๊ฒŒ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค.

 

๊ฐ•์˜๋ฅผ ๋“ฃ๋Š”๋ฐ ๋‚ด์šฉ์ด ๋„ˆ๋ฌด ์–ด๋ ค์›Œ์„œ...

 

jpa?

  • Java ์ง„์˜์—์„œ ORM(Object-Relational Mapping) ๊ธฐ์ˆ  ํ‘œ์ค€์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค ๋ชจ์Œ
  • ์ž๋ฐ” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์„ ์ •์˜ํ•œ ์ธํ„ฐํŽ˜์ด์Šค
  • ์ธํ„ฐํŽ˜์ด์Šค ์ด๊ธฐ ๋•Œ๋ฌธ์— Hibernate, OpenJPA ๋“ฑ์ด JPA๋ฅผ ๊ตฌํ˜„ํ•จ

์กฐ๊ธˆ ์ฐพ์•„๋ดค์Šต๋‹ˆ๋‹ค

๋‚ด์šฉ์ด ๋„ˆ๋ฌด ์–ด๋ ค์›Œ์š”.....

 

package hello.hello_spring.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.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;
    }
}

์ด๊ฑฐ๋Š” Memeber ํด๋ž˜์Šค ์ฝ”๋“œ์ธ๋ฐ ๋ญ”๊ฐ€ ๊ฐ์ด ์ž˜ ์•ˆ์™€์š”

 


๐Ÿ”  ์Šคํ”„๋ง JPA

  • ๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ ์ฆ๊ฐ€
  • ์ฝ”๋“œ ์ค„์–ด๋“ฌ 

์ด๋ ‡๊ฒŒ ๋งŽ์€ ํด๋ž˜์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค

**์Šคํ”„๋ง ๋ฐ์ดํ„ฐ JPA ์ œ๊ณต ๊ธฐ๋Šฅ**

- ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•œ ๊ธฐ๋ณธ์ ์ธ CRUD

- findByName(), findByEmail() ์ฒ˜๋Ÿผ ๋ฉ”์„œ๋“œ ์ด๋ฆ„ ๋งŒ์œผ๋กœ ์กฐํšŒ ๊ธฐ๋Šฅ ์ œ๊ณต

- ํŽ˜์ด์ง• ๊ธฐ๋Šฅ ์ž๋™ ์ œ๊ณต

 

 

๊ฐœ์ธ์ ์œผ๋กœ ์˜ค๋Š˜ ํ•œ๊ฑด ๋‚ด์šฉ์ด ์–ด๋ ค์›Œ์„œ.... JPA๋„ ๊ทธ๋ ‡๊ณ  ๋”ฐ๋กœ ๊ณต๋ถ€๋ฅผ ๋” ํ•ด์•ผ๊ฒ ์–ด์š”....

ํ™”์ดํŒ…ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.....

๋ฐ˜์‘ํ˜•