ํด๋น ๊ธ์ ๋ฐฐ์๋ณด์ Spring Data JPA ์๋ฆฌ์ฆ ์ ๋๋ค.
ํด๋น ์๋ฆฌ์ฆ์ ๋ด์ฉ์ด ์ด์ด์ง๋ ํํ์ด๋ฏ๋ก ๊ธ์ ๋ด์ฉ ์ค์ ์๋ต๋๋ ๋ง๋ค์ด ์์ ์ ์์ผ๋, ์์ธํ ์ฌํญ์ ์๋ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํด์ฃผ์ธ์!
- Spring Data JPA์ ๊ธฐ๋ณธ๊ณผ ํ๋ก์ ํธ ์์ฑ :: ์๋ฆฌ์ฆ ํ์ต ํ๊ฒฝ ์ค๋น
- JPA์ ๊ธฐ๋ณธ๊ณผ Spring Data JPA
- Springboot project ์์ JPA ์ค์ ํ๊ธฐ
- JPA์ ๊ธฐ๋ณธ ์ด๋
ธํ
์ด์
๋ค :: JPA์ ์์๊ณผ ๋์์ ๋
- ์ํฐํฐ์ ํ ์ด๋ธ ๋งคํ
- ํ๋์ ์ปฌ๋ผ ๋งคํ
- ๋งคํ ํ
์ด๋ธ๊ณผ ์ฐ๊ด๊ด๊ณ ๋งคํํ๊ธฐ :: RDB์ ๊ฝ, ์ฐ๊ด ๊ด๊ณ
- ์ฐ๊ด๊ด๊ณ๋?, ์ธ๋ ํค๋?, ๋งคํ ํ ์ด๋ธ์ด๋?
- ์ผ๋์ผ, ์ผ๋๋ค, ๋ค๋์ผ ์ฐ๊ด๊ด๊ณ
- ๊ณตํต ์ธํฐํ์ด์ค ๊ธฐ๋ฅ :: ์ด๋ป๊ฒ Data JPA ๋ ๋์ํ ๊น?
- ๋จ๊ฑด ์กฐํ ๋ฐํ ํ์
- ์ปฌ๋ ์ ์กฐํ ๋ฐํ ํ์
- ์ฌ์ฉ์ ์ ์ ์ฟผ๋ฆฌ ์ด์ฉํ๋ ๋ฐฉ๋ฒ :: ๋ด๊ฐ ์ํ๋ ์ฟผ๋ฆฌ๋ฅผ JPA ์์ ๋ง๋ค์ด๋ณด์!
- ๋ฉ์๋ ์ด๋ฆ์ผ๋ก ์ฟผ๋ฆฌ ์์ฑํ๊ธฐ
@Query
๋ฅผ ์ด์ฉํ์ฌ ๋ฉ์๋์ ์ ์ ์ฟผ๋ฆฌ ์์ฑํ๊ธฐ
- ํ์ด์ง๊ณผ ์ ๋ ฌ :: ๊ฒ์ํ๊ณผ ๊ฐ์ ํ์ด์ง๊ฐ ์๋ ์๋น์ค์์ ๋น์ ๋ฐํ๋ JPA ํ์ด์ง!
- Data JPA์ ํ์ด์ง๊ณผ ์ ๋ ฌ
- Web MVC ์์ JPA ํ์ด์ง๊ณผ ์ ๋ ฌ
- Auditing :: ๋ชจ๋ ์์ฒญ๊ณผ ์๋ต์
๋๊ฐ, ์ธ์
์ ๊ทผํ๋์ง ํ๋์ ์ํฐํฐ๋ก ๊ด๋ฆฌํ์.- ์์ JPA์ Auditing
- Spring Data JPA์ Auditing
- ๋ฐฐ์๋ณด์ Spring Data JPA ์๋ฆฌ์ฆ๋ฅผ ๋ง์น๋ฉฐ...
- ์๋ฆฌ์ฆ๋ฅผ ๋ง์น๋ฉฐ ๋๋์
- ๋ด๊ฐ ์ ๋ณด๋ฅผ ์ป์ ๊ณณ
- ํด๋น ์๋ฆฌ์ฆ๋ฅผ ์์ฃผํ์ จ๋์?
์ค๋์ JPA ์ ๋ํ ๊ธฐ๋ณธ๊ณผ Spring Data JPA ์ ๋ํด์ ์์๋ณผ ๊ฒ์ด๋ค.
์ฐ์ Spring์ ํตํด์ JPA๋ฅผ ์ ํ ์ฌ๋์๊ฒ๋ ์๋ก์ธ ์ ์๋๋ฐ, Spring์์ ์ฌ์ฉํ๋ JPA์ JPA๋ฅผ ์ด์ฉํ์ฌ Spring ์ด ๋ง๋ ํ๋ก์ ํธ์ด๋ค.
๋ฌด์จ ์ฐจ์ด์ผ๊น?
์ฐ์ JPA์ ๋ํด์ ๋จผ์ ์์๋ณด์.
JPA
JPA๋ ORM ํ์ค์ธ๋ฐ, ORM์ ๋ฌด์์ผ๊น?
๊ฐ์ฒด ๊ด๊ณ ๋งคํ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด ๊ฐ์ ํธํ๋์ง ์๋ ๋ฐ์ดํฐ๋ฅผ ๋ณํํ๋ ํ๋ก๊ทธ๋๋ฐ ๊ธฐ๋ฒ์ด๋ค.
๊ฐ์ฒด ์งํฅ ์ธ์ด์์ ์ฌ์ฉํ ์ ์๋ "๊ฐ์" ๊ฐ์ฒด ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๊ตฌ์ถํ๋ ๋ฐฉ๋ฒ์ด๋ค.
JPA์ ORM์ ์ดํดํ๊ธฐ ์ํด์๋ ์ฐ์ ๋ถํธํ ๊ณผ๊ฑฐ๋ฅผ ๋ด์ผ ํ๋ค.
๊ณผ๊ฑฐ์๋ SQL ์ค์ฌ์ ์ธ ํ๋ก๊ทธ๋๋ฐ์ ํ๋ ์๋์๋ค.
๊ฑฐ๊ธฐ์ ๋ ๊ฐ์ง ๋ถํธํจ์ด ์กด์ฌํ๋๋ฐ,
- SQL์ ์์กด์ ์ธ ํ๋ก๊ทธ๋๋ฐ
- SQL๊ณผ ๊ฐ์ฒด ์ฌ์ด์ ์ํผ๋์ค ๋ถ์ผ์น
๋ผ๋ ๋ฌธ์ ๋ค์ด ์์๋ค.
SQL์ ์์กด์ ์ธ ํ๋ก๊ทธ๋๋ฐ
JDBC API๋ฅผ ์ด์ฉํ์ฌ db์ ์ ์ฅํ๋ ์ฌ๋ฌ ์ฟผ๋ฆฌ๋ค์ ๋๋ถ๋ถ SQL์ ์์กด์ ์ด๋ค๋ผ๊ณ ํํํ๋ค.
์ ๊ทธ๋ด๊น?
๋ค์๊ณผ ๊ฐ์ ์์์ ํด๋ณด์.
์ฐ๋ฆฌ๊ฐ User ํ ์ด๋ธ์ ์ด๋ค ํ๋๋ฅผ ๋ง๋ค๊ณ ์ด๋ฅผ JDBC API๋ฅผ ์ด์ฉํ์ฌ ์ฟผ๋ฆฌ๋ฅผ ๋ ๋ฆฐ๋ค.
๊ทธ๋ผ ํด๋น ์ฟผ๋ฆฌ์ ๋ง๊ฒ ResultSet์ ๊ฐ๊ฐ์ ๊ธฐ๋ฅ๋ง๋ค ์ธํ ํด์ผํ๋ค.
ํ์ง๋ง ์ฌ๊ธฐ์ ์ํฐํฐ์ ์๋ก์ด ํ๋๊ฐ ๋ค์ด๊ฐ๊ฒ ๋๋ค๋ฉด?
๊ทธ๋ผ CRUD์ ๊ด๋ จ๋ ๋ชจ๋ JDBC API์ ResultSet์ ์์ ํด์ ๋งคํ์ ํด์ผํ๋ค.
์ด๋ฅผ ๋๊ณ SQL ์ ์์กด์ ์ด๋ค ๋ผ๊ณ ํ๋ ๊ฒ์ด๋ค.
SQL๊ณผ ๊ฐ์ฒด ์ฌ์ด์ ์ํผ๋์ค ๋ถ์ผ์น
User table์ด ์กด์ฌํ๋ค๊ณ ํด๋ณด์.
๊ทธ๋ฆฌ๊ณ ํด๋น User ํ ์ด๋ธ์๋ Team ํ ์ด๋ธ๊ณผ ์ธ๋ ํค๋ก ๋งคํ๋์ด์๋ค๊ณ ํ์๋, User A๊ฐ ์ด๋ค ํ์ ์ํด์๋์ง ์๊ธฐ ์ํด์๋ ์๋ฐ์์ ์ด๋ป๊ฒ ํ ๊น?
public static void main(String[] args) {
DBConnection connection = new DBConnection();
User user = connection.findUser("jang")
Team team = user.getTeam();
System.out.println(team.getName());
}
๊ทธ๋ผ SQL, ์ฆ RDB ์์๋ ์ด๋ป๊ฒ ํด์ผํ ๊น?
SELECT T.name
FROM user U
INNER JOIN team T
ON T.id = T.id
WHERE U.name = "jang";
์ด๋ฐ ์์ผ๋ก ํ๋ ค๋?
๊ฐ์ ๊ธฐ๋ฅ (A๊ฐ ์ด๋ค ํ์ ์ํด์๋์ง ์๊ธฐ ์ํด์๋)์ ํ๋๋ฐ, SQL๊ณผ Java ์ฌ์ด์์๋ ๋ง์ ๋ค๋ฅธ ์ ๋ค์ด ์๋ค.
์ด๋ฅผ ํจ๋ฌ๋ค์, ์ํผ๋์ค ๋ถ์ผ์น๋ผ๊ณ ๋ถ๋ฅธ๋ค.
์ด๋ฐ ์ด์ ์ JPA๊ฐ ๋ฑ์ฅํ๊ณ ์ด๋ค์ ํด๊ฒฐํ๊ธฐ ์์ํ๋ค.
์์ธํ ์ด๋ค ๋ฌธ์ ์์ ์ด๋ป๊ฒ ํด๊ฒฐํ๋์ง๋ ์ง๊ธ ์ค์ํ์ง ์์ผ๋ ๋์ด๊ฐ๋๋ก ํ๊ฒ ๋ค.
Spring Data JPA๋?
JPA๋ ORM Framework ์ด๋ค.
์ฆ, ๋ ๋ฆฝ์ ์ธ ํ๋์ ํ๋ ์์ํฌ์ธ ๊ฒ์ด๋ค.
ํ์ง๋ง ์์ ๋ง ํ๋ฏ Spring์ ํตํด JPA๋ฅผ ๋ฐฐ์ด ์ฌ๋๋ค์๊ฒ๋ JPA๋ Spring์ด ๋ง๋ ๊ฒ ์ฏค์ผ๋ก ์๊ณ ์๋ ๊ฒฝ์ฐ๊ฐ ์๋ค.
Spring Data JPA๋ Spring์ด JPA๋ฅผ Spring์์ ๋ ์ฝ๊ณ ๊ฐํธํ๊ฒ ์ฌ์ฉํ๊ธฐ ์ํด์ ๋ง๋ Spring Data์ ํ๋ก์ ํธ ์ค ํ๋ ์ด๋ค.
Spring ๊ณต์ ๋ฌธ์์์ Spring Data ํ๋ก์ ํธ๋ฅผ ํ์ธํ๋ฉด ๋ง์ Data ํ๋ก์ ํธ๋ค์ด ์กด์ฌํ๋ค.
Spring Data JPA ์ฌ์ฉํ๊ธฐ
Spring Data JPA๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ๋น์ฐํ๊ฒ ๊ทธ์ ๋ง๋ ์์กด์ฑ์ ์ค์นํด์ผ ํ๋ค.
Maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.4.4</version>
</dependency>
Gradle
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: '2.4.4'
Spring Data JPA์ ์ค์ ๊ณผ DB ์ฐ๊ฒฐ
Springboot ํ๋ก์ ํธ์์ Data JPA๋ฅผ ์ด์ฉํ๊ธฐ ์ํด์๋ ์ธ ๊ฐ์ง๊ฐ ํ์ํ๋ค.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ง
- JPA ์ค์
- Lombok ์ค์
๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ง
ํด๋น ์๋ฆฌ์ฆ์์ ์ฌ์ฉํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ง์ H2 Database์ด๋ค.
H2๋ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ฐ์ ์ฝ์๋ชจ๋๋ฅผ ์ด์ฉํ ์ ์๊ณ , ๋ณ๋์ ์ค์น๊ณผ์ ์ด ์์ด ์ฉ๋๋ 2MB์ดํ๋ก ๋งค์ฐ ์ ์ฉ๋์ด๋ค.
๊ฐ๋ณ๊ธฐ ๋๋ฌธ์ ๋น ๋ฅด๋ฉฐ ํ ์คํธ ์ฉ๋๋ก ์์ฃผ ์ฌ์ฉํ๋ฏ๋ก ์ด๋ฒ ๊ธฐํ์ ์์๋๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด๋ค.
์์ธํ ์ค์น๋ ์๋ตํ๊ณ Knowledge Repository ๋์ ๋ธ๋ก๊ทธ h2 ์ค์น ์์ ํ์ธํ ์ ์๋ค.
JPA ์ค์
jpa ์ค์ ์ application.properties
์์ ํ๋ค.
์ฐ๋ฆฌ๋ yml์ ์ด์ฉํด์ ์ค์ ์ ํด๋ณด์.
resources ์๋์ application.yml
ํ์ผ์ ์์ฑํ๊ณ ์๋์ ๊ฐ์ด ์ ์ด๋ณด์.
spring:
datasource:
url: jdbc:h2:tcp://localhost/~/dbname # ๋ณธ์ธ์ db connection url
username: name # ๋ณธ์ธ์ db username
password: pw # ๋ณธ์ธ์ db password
driver-class-name: org.h2.Driver
jpa:
hibernate:
ddl-auto: create
properties:
show_sql: true
format_sql: true
์์ ๋ช ๋ น์ด๋ค์ ์์๋ณด์.
datasource
datasource
: ๋ฐ์ดํฐ ์์ค์ ๋ํ ์ ๋ณด ๋ธ๋ก์ด๋ค.hibernate
- jpa ์ ๊ตฌํ์ฒด์ธ hibernate๋ฅผ ์ฌ์ฉํ ๊ฒ์ด๋ฏ๋ก hibernate ์ค์ ์ ๋ฐ๊ฟ ์ ์๋ค.
ddl-auto
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๊ธฐํ ์ ๋ต์ด๋ค. 5๊ฐ์ง ์ ๋ต์ด ์กด์ฌํ๋ค.
- none : ์๋ฌด๊ฒ๋ ์คํํ์ง ์์
- create : SessionFactory๊ฐ ์์๋ ๋ ๊ธฐ์กด์ ํ ์ด๋ธ ์ญ์ ํ ์ฌ์์ฑ
- create-drop : SessionFactory ๊ฐ ์ข ๋ฃ๋๋ค๋ฉด drop
- update : ๋ณ๊ฒฝ๋ ์คํค๋ง๋ง ์ ์ฉ
- validate : ์ํฐํฐ์ ํ ์ด๋ธ์ด ์ ์ ๋งคํ ๋์๋์ง๋ง ํ์ธ
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๊ธฐํ ์ ๋ต์ด๋ค. 5๊ฐ์ง ์ ๋ต์ด ์กด์ฌํ๋ค.
jpa
: jpa ์ ๋ํ ์ ๋ณด ๋ธ๋ก์ด๋ค.properties
- hibernate ๊ธฐ๋ณธ ์ค์ ์ด๋ค.
show_sql
- JPA๊ฐ ์์ฑํ๋ ์ฟผ๋ฆฌ๋ฅผ ์ฝ์๋ก ์ถ๋ ฅํ๋ค.
format_sql
- ์ฝ์๋ก ์ฟผ๋ฆฌ๊ฐ ์ถ๋ ฅ๋ ๋ ์ด์๊ฒ ํฌ๋งคํ ๋๋ค.
์์ธํ ์ฌํญ์ hibernate ์ฐธ์กฐํ๋ฉด ์ ์ ์๋ค.
Lombok ์ค์
๋กฌ๋ณต์ Getter/Setter, Constructor, ToString, Builder ๋ฑ ๋ค์ํ ๊ธฐ๋ฅ์ ์ปดํ์ผ ์์ ์ ์ฌ์ฉํ ์ ์๊ฒ ํด์ฃผ๋ ํ๋ฌ๊ทธ์ธ์ธ๋ฐ, ์์ธํ ์ฌํญ์ ๊ฒ์์ ํด๋ณด๊ธธ ๋ฐ๋๋ค.
์ฐ๋ฆฌ ์์ ์์๋ Lombok ์ ์ด์ฉํ ์์ ์ด๋ค.
JPA ์ฌ์ฉํด๋ณด๊ธฐ
๋ค์ ์๊ฐ์ ์ ๋๋ก ์ฌ์ฉํด ๋ณผ ์์ ์ธ๋ฐ, ์ฐ์ db ์ค์ ์ด ์ ์ ์ฉ ๋์๋์ง ํ ์คํธ๋ฅผ ํด๋ณด์.
๋ค์ 3๊ฐ์ ํ์ผ์ ๋ง๋ค์.
Member
MemberRepository
MemberRepositoryTest
Member ํด๋์ค
@Entity
@Getter @Setter @Builder
public class Member {
@Id @GeneratedValue
private Long id;
private String username;
private int age;
}
MemberRepository ์ธํฐํ์ด์ค
public interface MemberRepository extends JpaRepository<Member, Long> {
}
MemberRepositoryTest ํด๋์ค
@SpringBootTest
@Transactional
@Rollback(false)
public class MemberRepositoryTest {
@Autowired
MemberRepository memberRepository;
@Test
public void saveMemberTest() {
// given
long id = 2L;
String username = "Member B";
int age = 21;
// when
Member member = Member.builder()
.username(username)
.age(age)
.build();
Member saveMember = memberRepository.save(member);
// then
Assertions.assertEquals(saveMember.getAge(), age);
Assertions.assertEquals(saveMember.getUsername(), username);
}
}
๊ทธ๋ผ ์ ์์ ์ผ๋ก ๋์ํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
๋๊ธ