mysql μ°κ²°
1.
mysql μ€μΉ
2.
build.gradle
mysql connector λ₯Ό gradle μ μΆκ°ν΄μ£Όκ³ import μν¨λ€.
implementation 'mysql:mysql-connector-java'
Plain Text
볡μ¬
3.
application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/<db>?serverTimezone=Asia/Seoul
username: <username>
password: <password>
YAML
볡μ¬
create table member
(
id bigint not null auto_increment,
name varchar(255),
primary key (id)
);
SQL
볡μ¬
JPA
jpa κ΄λ ¨ λΌμ΄λΈλ¬λ¦¬ μΆκ°
build.gradle
implementation 'mysql:mysql-connector-java'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
Plain Text
볡μ¬
jpa μ€μ μΆκ°
application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Seoul
username: <username>
password: <pw>
jpa:
show-sql: true
hibernate:
ddl-auto: none
YAML
볡μ¬
β’
show-sql : true
JPA κ° μμ±νλ SQL μΆλ ₯
β’
ddl-auto : none
ν
μ΄λΈμ μλμΌλ‘ μμ±νμ§ μλλ€. (create μ ν
μ΄λΈλ μ§μ μμ±ν΄μ€λ€.)
jpa λ μλ° μ§μμ νμ€ ORM μΈν°νμ΄μ€μ΄κ³ ,
hibernate λ jpa λ₯Ό ꡬνν νλ μμν¬μ΄λ€.
μν°ν° μμ±
domain/Member.java
@Entity
public class Member {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; // PK
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;
}
}
Java
볡μ¬
Β @Entity μ΄λ
Έν
μ΄μ
μ λ¬μμ€μΌνλ€.
μ€νλ§ μ€μ μ JPA μ€μ μΆκ°
SpringConfig.java
@Configuration
public class SpringConfig {
private final EntityManager em; // 1οΈβ£
@Autowired
public SpringConfig(EntityManager em) {
this.em = em;
}
@Bean
public MemberService memberService() {
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
// return new MemoryMemberRepository();
return new JpaMemberRepository(em); // 2οΈβ£ κ°μ²΄μ§ν₯ λ€νμ±μ μ₯μ
}
}
Java
볡μ¬
Β JPA κ° EntityManager λ₯Ό μλμΌλ‘ bean μ λ±λ‘ν΄μ£Όκ³ , μ΄ EntityManager λ₯Ό ν΅ν΄ μν°ν°λ₯Ό κ΄λ¦¬νλ€.
Β : μ€νλ§μ μ₯μ μΌλ‘ κ°μ²΄μ§ν₯μ μΈ μ€κ³κ° νΈλ¦¬νλ€λ κ²μΈλ°, νΉν μΈν°νμ΄μ€λ₯Ό λκ³ κ΅¬νμ²΄λ§ λ°κΏ λΌμΈ μ μλ λ€νμ± μ΄ ν° μ₯μ μ΄λ€.
Β : Β JpaMemberRepository κ°μ²΄μ em μ μ£Όμ
νλ€.
Β μ€νλ§ λΉμ μ§μ μμ±ν΄μ μμ±νλ λ°©μμ΄λ―λ‘ MemberService μ MemberRepository ν΄λμ€μμ @Service, @Repository, @Autowired μ΄λ
Έν
μ΄μ
μ μμ μΌ νλ€.
JPA λ©€λ² λ¦¬ν¬μ§ν 리 ꡬν
repository/JpaMemberRepository.java
public class JpaMemberRepository implements MemberRepository{
private final EntityManager em;
// JPA λ₯Ό μ°λ €λ©΄ em μ DI λ₯Ό λ°μμΌνλ€.
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.class : μ‘°νν νμ
// id : μ‘°νν νμ
μ κ°
Member member = em.find(Member.class, id);
return Optional.ofNullable(member);
}
@Override
public Optional<Member> findByName(String name) {
// jpql 쿼리 μΈμ΄ ( μν°ν° κ°μ²΄λ₯Ό λμμΌλ‘ λ 리λ 쿼리 )
// 쿼리 κ²°κ³Όλ κ°μ²΄κ° λ¨
List<Member> result = em.createQuery("select m from Member as m where m.name = :name", Member.class)
.setParameter("name", name)
.getResultList();
return result.stream().findAny();
}
@Override
public List<Member> findAll() {
// jpql 쿼리 μΈμ΄ ( μν°ν° κ°μ²΄λ₯Ό λμμΌλ‘ λ 리λ 쿼리 )
// 쿼리 κ²°κ³Όλ κ°μ²΄κ° λ¨
return em.createQuery("select m from Member as m", Member.class)
.getResultList();
}
}
Java
볡μ¬
Β μ¬κΈ°μλ μμ JPA λΌμ JPQL μ μ¬μ©ν΄μ 쿼리 λΉμ·ν μΈμ΄λ₯Ό μ¬μ©νμ§λ§ μ€νλ§ λ°μ΄ν° JPA λ₯Ό μ¬μ©νλ©΄ 쿼리문λ μμ±νμ§ μμλ λλ€.
Β select m from Member m ~
1.
select m Member as m ~ μμ as λ₯Ό μλ΅ν κ²°κ³Ό
2.
m μ DB ν
μ΄λΈμ΄ μλλΌ JPA μ μν΄ λ§€νλ μλ° κ°μ²΄λ₯Ό μλ―Έν¨
Member μλΉμ€
MemberService.java
@Transactional // JPA λ₯Ό μ¬μ©ν λͺ¨λ λ°μ΄ν° λ³κ²½μ νΈλμμ
μμμ μ€νλμ΄μΌ ν¨
public class MemberService {
private final MemberRepository memberRepository;
@Autowired // MemberService κ°μ²΄λ₯Ό μμ±ν λ, memberRepository μμ‘΄μ± μ£Όμ
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
// νμκ°μ
public Long join(Member member) {
// κ°μ μ΄λ¦μ΄ μλ μ€λ³΅ νμ κ²μ¦ ν μ€λ³΅ μμΌλ©΄ μμΈμ²λ¦¬
validateDuplicateMember(member);
memberRepository.save(member);
return member.getId();
}
private void validateDuplicateMember(Member member) {
// ifPresent : optional κ°μ²΄ λ©μλ
memberRepository.findByName(member.getName())
.ifPresent(m -> {
throw new IllegalStateException("μ΄λ―Έ μ‘΄μ¬νλ νμμ
λλ€.");
});
}
// νμ μ 체 μ‘°ν
public List<Member> findMembers() {
return memberRepository.findAll();
}
// νμ ν λͺ
μ‘°ν
public Optional<Member> findOne(Long memberId) {
return memberRepository.findById(memberId);
}
}
Java
볡μ¬
Β JPA λ₯Ό μ¬μ©ν λͺ¨λ λ°μ΄ν° λ³κ²½μ νΈλμμ
μμμ μ€νλμ΄μΌ νλ―λ‘, ν΄λμ€ μμ @Transactional μ΄λ
Έν
μ΄μ
μ λ¬μμ€λ€.
ν΅ν©ν μ€νΈ μμ±
β’
λ¨μ ν
μ€νΈ : μμ±ν μ½λ λ΄μμλ§ μλνλμ§ νμΈνλ ν
μ€νΈ ( μμν μλ° μ½λκ° μ μλνλμ§ νμΈνλ ν
μ€νΈ )
β’
ν΅ν© ν
μ€νΈ : μμ±ν μ½λ λΏλ§ μλλΌ μΈλΆ λͺ¨λ(ex. μ€νλ§ λΆνΈ, DB, μ€νλ§ μ»¨ν
μ΄λ) κΉμ§ κ°μ΄ μ€νμμΌμ νμΈνλ ν
μ€νΈ
MemberServiceIntegrationTest.java
@SpringBootTest // 1οΈβ£ μ€νλ§ μ»¨ν
μ΄λκΉμ§ λμ°λ ν΅ν©ν
μ€νΈ
@Transactional // 2οΈβ£ ν
μ€νΈ μ€ν νμ λ‘€λ°±μ ν΄μ€μ κ° ν
μ€νΈκ° λλ νμ DB λ€μ μμ볡ꡬ
public class MemberServiceIntegrationTest {
// 3οΈβ£ νλ κΈ°λ° auto injection λ°μ
@Autowired MemberService memberService;
@Autowired MemberRepository memberRepository;
@Test
// @Commit // 4οΈβ£ @Transactional μ΄λ
Έν
μ΄μ
μ΄ μλλΌλ DBμ 컀λ°κΉμ§ ν΄μ ν
μ€νΈκ° λλλ DBμ λ¨μ
void νμκ°μ
() {
// given (μ£Όμ΄μ§ μν©)
Member member = new Member();
member.setName("hello");
// 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");
// member1 κ³Ό μ€λ³΅λ μ΄λ¦μΌλ‘ μ€μ
Member member2 = new Member();
member2.setName("spring");
// when
memberService.join(member1);
// then
IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));
assertThat(e.getMessage()).isEqualTo("μ΄λ―Έ μ‘΄μ¬νλ νμμ
λλ€.");
/* κ°μ λ‘μ§
try{
memberService.join(member2);
fail();
} catch (IllegalStateException e) {
assertThat(e.getMessage()).isEqualTo("μ΄λ―Έ μ‘΄μ¬νλ νμμ
λλ€.");
}
*/
}
}
Java
볡μ¬
Β @SpringBootTest : μ€νλ§ μ»¨ν
μ΄λκΉμ§ λμ°λ ν΅ν©ν
μ€νΈ
Β @Transactional : ν
μ€νΈ μΌμ΄μ€μ μ΄ μ λ
Έν
μ΄μ
μ΄ μμΌλ©΄, ν
μ€νΈ μμ μ μ νΈλμμ
μ μμνκ³ , ν
μ€νΈ μλ£ νμ νμ λ‘€λ°±νλ€. μ΄λ κ² νλ©΄ DBμ λ°μ΄ν°κ° λ¨μ§ μμΌλ―λ‘ λ€μ ν
μ€νΈμ μν₯μ μ£Όμ§ μλλ€.
β λ°λ³΅μ μΈ ν
μ€νΈ λ©μλ μ€ν κ°λ₯
@Transactional λ₯Ό μ¬μ©νλ©΄ @AfterEach λ‘ DB λ°μ΄ν° μμ νλ λ‘μ§μ μ μ§λ λλ€
Β μ€νλ§ ν΅ν© ν
μ€νΈμ΄κΈ° λλ¬Έμ @Autowired λ₯Ό μ¬μ©ν΄μ μ€νλ§ λΉμ μν΄ μνλ κ°μ²΄λ₯Ό μ£Όμ
λ°μ μ μλ€.
Β @Commit : @Transactional μ΄λ
Έν
μ΄μ
μ΄ μλλΌλ DBμ 컀λ°κΉμ§ ν΄μ ν
μ€νΈκ° λλλ DBμ λ¨μ
Recall
ν΅ν©ν
μ€νΈ : μ€νλ§ μ»¨ν
μ΄λκΉμ§ λμμ§κΈ° λλ¬Έμ μ€νλ§ λΉ μ¬μ© κ°λ₯
μ λν
μ€νΈ(λ μν
μ€νΈ) : μ€νλ§ μ»¨ν
μ΄λκ° λμμ§μ§ μκΈ° λλ¬Έμ μ€νλ§ λΉ μ¬μ© λΆκ°
μ€νλ§ λ°μ΄ν° JPA
μ€νλ§ λ°μ΄ν° JPA νλ μμν¬λ JPA λ₯Ό μ¬μ©νκΈ° μ½κ² λ§λ€μ΄μ£Όλ νλ μμν¬μ΄λ€.
κΈ°λ³Έμ μΈ CRUD λ©μλλ€μ κΈ°λ³Έμ μΌλ‘ μ 곡νλ€.
μ€νλ§λ°μ΄ν°JPA 리ν¬μ§ν 리 ꡬν
SpringDataJpaMemberRepository.java
// μΈν°νμ΄μ€μμ μΈν°νμ΄μ€λ₯Ό λ°μμ¬ λ extends λ₯Ό μ¬μ©
// μΈν°νμ΄μ€λ λ€μ€μμμ΄ κ°λ₯
// @Bean μ€μ μν΄μ€λ μ€νλ§μ΄ μμμ λ±λ‘ν΄μ€
public interface SpringDataJpaMemberRepository extends JpaRepository<Member, Long>, MemberRepository {
// 컀μ€ν
λ©μλ μΆκ°
// μΈν°νμ΄μ€λ§ λ§λ€μ΄μ€λ μ€νλ§ λ°μ΄ν° JPA κ° μμμ ꡬνν΄μ€
// select m from Member as m where m.name = ? JPQL λ‘ λ²μλΌμ μ€νλ¨
@Override
Optional<Member> findByName(String name);
}
Java
볡μ¬
Β JpaRepository<Member, Long>
첫 λ²μ§Έ μΈμ : λ ν¬μ§ν 리 κ°μ²΄ νμ
λ λ²μ§Έ μΈμ : μλ³μ(PK) νμ
Β findByName λ©μλλ κΈ°λ³Έμ μΌλ‘ μ 곡νλ λ©μλκ° μλκΈ° λλ¬Έμ μ§μ μμ±(Override) νλ€.
Β λ΄λΆμ μΌλ‘ findByName λ select m from Member as m where m.name = ? μ JPQL λ‘ λ²μλΌμ μ€νλλ€.
μ€νλ§ λ°μ΄ν° JPA μ리
JpaRepository<T, ID> μΈν°νμ΄μ€λ₯Ό μμλ°κ³ μλ μΈν°νμ΄μ€λ₯Ό μ€νλ§μ΄ μλμΌλ‘ ꡬν체λ₯Ό λ§λ λ€μ beanμΌλ‘ λ±λ‘ν΄μ€λ€.
μ€νλ§ μ€μ λ³κ²½
μ€νλ§λ°μ΄ν°JPA λ₯Ό μν μ€νλ§ μ€μ μ λ³κ²½νλ€.
SpringConfig.java
@Configuration
public class SpringConfig {
private final MemberRepository memberRepository;
// 1οΈβ£ μ€νλ§ λ°μ΄ν° JPA κ° λ±λ‘ν΄μ€ MemberRepository bean μ μ΄μ©ν΄μ DI λ°μ
@Autowired
public SpringConfig(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Bean
public MemberService memberService() {
return new MemberService(memberRepository);
}
}
Java
볡μ¬
Β μ΄ μ½λ μμΌλ‘λ MemberRepository bean μ΄ μλ κ² μ²λΌ 보μ΄μ§λ§, μ€μ λ‘λ μ€νλ§λ°μ΄ν°JPA κ° MemberRepository bean μ μλμΌλ‘ λ±λ‘ν΄μ€¬μ ( JpaRepository μΈν°νμ΄μ€λ₯Ό μμλ°λ κ²½μ°μλ§ )
β μ€νλ§λ°μ΄ν°JPA λ₯Ό μ¬μ©νκ² λλ©΄, 리ν¬μ§ν 리λ λ°λ‘ Bean μΌλ‘ λ±λ‘ν΄μ€ νμκ° μλ€. (μμμ ν΄μ€)
μ€νλ§λ°μ΄ν° JPA κΈ°λ³Έμ§μ λ©μλ
β’
κΈ°λ³Έμ μΈ CRUD λ©μλ μ 곡
β’
findByName(), findByEmail() μ²λΌ λ©μλ μ΄λ¦λ§μΌλ‘ μ‘°ν κΈ°λ₯ μ 곡
β’
νμ΄μ§ κΈ°λ₯ μ 곡