[์น๊ฐ๋ฐ์ ๋ด, Spring] 2์ฃผ์ฐจ ๊ฐ๋ฐ์ผ์ง(2) - JPA์ CRUD์ Repository
[์น๊ฐ๋ฐ์ ๋ด, Spring] 2์ฃผ์ฐจ ๊ฐ๋ฐ์ผ์ง(1) - RDBMS, H2, SQL
์ด๋ฒ ํฌ์คํ ์์ ์ ๋ฆฌํ ๋ถ๋ถ์ JPA์ Repository์ ๊ดํ ๋ด์ฉ์ด๋ค.
JPA
๐ก JPA๋?
JPA๋ SQL์ ์ฐ์ง ์๊ณ ๋ฐ์ดํฐ๋ฅผ ์์ฑ, ์กฐํ, ์์ , ์ญ์ ํ ์ ์๋๋ก ํด์ฃผ๋ ๋ฒ์ญ๊ธฐ์ด๋ค.
JPA๋ฅผ ์ฌ์ฉํ์ง ์์ผ๋ฉด ์๋ฐ๋ก ์ฝ๋ ์์ฑ์ ํ๋ค๊ฐ ๊ฐ์๊ธฐ SQL์ ์ง๊ณ , ๋ ๊ทธ๊ฑธ ์ ๋ง์ถ์ด ๋ฃ์ด์ผ ํ๋ ๋ณต์กํ ๊ณผ์ ์ด ํ์ํ๋ค. ๋ฐ๋ฉด์ JPA๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฐ๋จํ ์ค์ ๊ณผ ํจ๊ป ๋ช ๋ น๋ ์๋ฐ๋ก ์์ฑํ ์ ์๋ค. ๊ตฟ๊ตฟ~
๐ก JPA ์ฌ์ฉํด๋ณด๊ธฐ
ํ๋ก์ ํธ๋ฅผ ์์ฑํ ๋ Dependencies์ JPA๋ฅผ ์ถ๊ฐํ์ผ๋ฏ๋ก ๋ฐ๋ก ์ค์ ์์ด ๋ฐ๋ก JPA๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
DB์์์ "ํ ์ด๋ธ"์ ์๋ฐ์์ Domain, "SQL"์ Repository๋ผ๊ณ ํ ์ ์๋ค. SQL ์ค์ต ๋, courses๋ผ๋ ํ ์ด๋ธ์ title, tutor๋ผ๋ ์ปฌ๋ผ์ ๋ง๋ค์๋ ๊ฒ์ ์๋ฐ๋ก ํํํ๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ํ๋ฉด ๋๋ค.
1. src > main > java > com.sparta.week02์ domain ์ด๋ผ๋ ํจํค์ง๋ฅผ ๋ง๋ ๋ค.
2. Course.java ํด๋์ค๋ฅผ ๋ง๋ ๋ค.
@NoArgsConstructor // ๊ธฐ๋ณธ์์ฑ์๋ฅผ ๋์ ์์ฑ
@Entity // ํ
์ด๋ธ์์ ๋ํ๋
public class Course {
@Id // ID ๊ฐ, Primary Key๋ก ์ฌ์ฉํ๊ฒ ๋ค๋ ์๋ฏธ
@GeneratedValue(strategy = GenerationType.AUTO) // ์๋ ์ฆ๊ฐ ๋ช
๋ น
private Long id;
@Column(nullable = false) // ์ปฌ๋ผ ๊ฐ์ด๊ณ ๋ฐ๋์ ๊ฐ์ด ์กด์ฌํด์ผ ํจ์ ๋ํ๋
private String title;
@Column(nullable = false)
private String tutor;
public String getTitle() {
return this.title;
}
public String getTutor() {
return this.tutor;
}
public Course(String title, String tutor) {
this.title = title;
this.tutor = tutor;
}
}
3. CourseRepository.java ์ธํฐํ์ด์ค๋ฅผ ๋ง๋ ๋ค.
public interface CourseRepository extends JpaRepository<Course, Long> {
}
์ฐธ๊ณ ) Interface๋?
- JPA๋ Repository๋ฅผ ํตํด์๋ง ์ฌ์ฉํ ์ ์์
- ์ธํฐํ์ด์ค๋ ํด๋์ค์์ ๋ฉค๋ฒ ๋ณ์๊ฐ ๋น ์ง, ๋ฉ์๋ ๋ชจ์์ง์ด๋ผ ํ ์ ์์
4. SQL์ด ๋ณด์ด๋๋ก application.properties๋ฅผ ์ค์ ํ๋ค.
5. Week02Application.java์ main ํจ์ ์๋์ JPA ์คํ ์ฝ๋๋ฅผ ์์ฑํ๋ค.
6. H2 ์น์ฝ์์ ์ ์ํด์ ๋ค์ ๋ช ๋ น์ผ๋ก course ํ ์ด๋ธ์ ํ์ธํฉ๋๋ค.
์์์ ํด๋ณด์
๐ก ์์์ด๋?
"extends"๊ฐ ๋ญ๊น? ์ด๊ฒ์ "ํด๋์ค์ ์์"์ด๋ผ๋ ๊ฐ๋ ์ด๋ค. ์์์ด๋ผ๋ ๊ฒ์ "์ด๋ฏธ ๋ง๋ค์ด๋๊ฑฐ ๊ฐ์ ธ๋ค ์ฐ์!"๋ผ๊ณ ์ ์ธํ๋ ๊ฒ์ด๋ค.
Course ํด๋์ค์ ์์ฑ์ผ์/์์ ์ผ์ ๋ฉค๋ฒ๋ฅผ ์ถ๊ฐํด๋ณด๋ฉฐ ์์์ ์ฐ์ตํด๋ดค๋ค.
1. Timestamped.java ํด๋์ค๋ฅผ ์์ฑํด ๋ค์๊ณผ ๊ฐ์ด ์ฝ๋๋ฅผ ์์ฑํ๋ค.
@MappedSuperclass // ์์ํ์ ๋ ์ปฌ๋ผ์ผ๋ก ์ธ์ํ๊ฒ ํจ
@EntityListeners(AuditingEntityListener.class) // ์์ฑ/์์ ์๊ฐ์ ์๋์ผ๋ก ๋ฐ์ํ๋๋ก ์ค์
public class Timestamped {
@CreatedDate // ์์ฑ์ผ์์์ ๋ํ๋
private LocalDateTime createdAt;
@LastModifiedDate // ๋ง์ง๋ง ์์ ์ผ์์์ ๋ํ๋
private LocalDateTime modifiedAt;
}
2. Course ํด๋์ค๊ฐ Timestamped๋ฅผ ์์๋ฐ๋๋ก ํ๋ค.
class Course extends Timestamped {
3. JPA๊ฐ ์์ ํ ์ ์๋๋ก Week02Application.java ํ์ผ์ ๋ค์๊ณผ ๊ฐ์ด ์์ ํ๋ค.
@EnableJpaAuditing
@SpringBootApplication
public class Week02Application {
4. H2 ์น์ฝ์์์ course๋ฅผ ์กฐํํ ๋ค, ์์ฑ/์์ ์ผ์๊ฐ ์ ๋ค์ด๊ฐ๋์ง ํ์ธํ๋ค.
JPA์ CRUD
๐ก CRUD
CRUD๋ ์ ๋ณด๊ด๋ฆฌ์ ๊ธฐ๋ณธ ๊ธฐ๋ฅ์ผ๋ก, ์์ฑ(Create), ์กฐํ(Read), ๋ณ๊ฒฝ(Update), ์ญ์ (Delete)๋ฅผ ๋งํ๋ค. JPA๋ก CRUD ํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ๋ ๊น?
๐ก Create & Read
Repository์ save์ findAll ๋ฑ์ ๋ฉ์๋๋ฅผ ์ด์ฉํด ๋ฐ์ดํฐ๋ฅผ ์์ฑ ๋ฐ ์กฐํํ ์ ์๋ค.
// ๋ฐ์ดํฐ ์ ์ฅํ๊ธฐ
repository.save(new Course("ํ๋ก ํธ์๋์ ๊ฝ, ๋ฆฌ์กํธ", "์๋ฏผ์"));
// ๋ฐ์ดํฐ ์ ๋ถ ์กฐํํ๊ธฐ
List<Course> courseList = repository.findAll();
for (int i=0; i<courseList.size(); i++) {
Course course = courseList.get(i);
System.out.println(course.getId());
System.out.println(course.getTitle());
System.out.println(course.getTutor());
}
// ๋ฐ์ดํฐ ํ๋ ์กฐํํ๊ธฐ
Course course = repository.findById(1L).orElseThrow(
() -> new IllegalArgumentException("ํด๋น ์์ด๋๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค.")
);
๐ก Service
Update๋ Service ๋ถ๋ถ์ ์์ฑํ๊ธฐ ๋๋ฌธ์ Service์ ๊ฐ๋ ์ ๋จผ์ ์์์ผ ํ๋ค.
์คํ๋ง์ ๊ตฌ์กฐ๋ 3๊ฐ์ง ์์ญ์ผ๋ก ๋๋ ์ ์๋ค.
- Controller: ๊ฐ์ฅ ๋ฐ๊นฅ ๋ถ๋ถ, ์์ฒญ/์๋ต์ ์ฒ๋ฆฌํจ
- Service: ์ค๊ฐ ๋ถ๋ถ, ์ค์ ์ค์ํ ์๋์ด ๋ง์ด ์ผ์ด๋๋ ๋ถ๋ถ
- Repo: ๊ฐ์ฅ ์์ชฝ ๋ถ๋ถ, DB์ ๋ง๋ฟ์ ์์
Update๋ฅผ ์ฌ์ฉํด๋ณด๊ธฐ ์ ์ Service๋ฅผ ๋ง๋ค์ด์ผํ๋ค.
1. Course ํด๋์ค์ update ๋ฉ์๋๋ฅผ ์ถ๊ฐํ๋ค.
2. src > main > java > com.sparta.week02 > service ํจํค์ง ์์ฑํ๋ค.
3. CourseService ํด๋์ค ๋ง๋ ๋ค.
@Service // ์คํ๋ง์๊ฒ ์ด ํด๋์ค๋ ์๋น์ค์์ ๋ช
์ํจ
public class CourseService {
// final: ์๋น์ค์๊ฒ ๊ผญ ํ์ํ ๋
์์์ ๋ช
์ํจ
private final CourseRepository courseRepository;
// ์์ฑ์๋ฅผ ํตํด, Service ํด๋์ค๋ฅผ ๋ง๋ค ๋ ๊ผญ Repository๋ฅผ ๋ฃ์ด์ฃผ๋๋ก
// ์คํ๋ง์๊ฒ ์๋ ค์ค
public CourseService(CourseRepository courseRepository) {
this.courseRepository = courseRepository;
}
@Transactional // SQL ์ฟผ๋ฆฌ๊ฐ ์ผ์ด๋์ผ ํจ์ ์คํ๋ง์๊ฒ ์๋ ค์ค
public Long update(Long id, Course course) {
Course course1 = courseRepository.findById(id).orElseThrow(
() -> new IllegalArgumentException("ํด๋น ์์ด๋๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค.")
);
course1.update(course);
return course1.getId();
}
}
๐ก Update & Delete
Week02Application.java์์ ๋ค์ ์ฝ๋๋ฅผ ์คํ์์ผ update์ delete๋ฅผ ํ์ธํ๋ค.
@Bean
public CommandLineRunner demo(CourseRepository courseRepository, CourseService courseService) {
return (args) -> {
courseRepository.save(new Course("ํ๋ก ํธ์๋์ ๊ฝ, ๋ฆฌ์กํธ", "์๋ฏผ์"));
System.out.println("๋ฐ์ดํฐ ์ธ์");
List<Course> courseList = courseRepository.findAll();
for (int i=0; i<courseList.size(); i++) {
Course course = courseList.get(i);
System.out.println(course.getId());
System.out.println(course.getTitle());
System.out.println(course.getTutor());
}
Course new_course = new Course("์น๊ฐ๋ฐ์ ๋ด, Spring", "์๋ฏผ์");
courseService.update(1L, new_course);
courseList = courseRepository.findAll();
for (int i=0; i<courseList.size(); i++) {
Course course = courseList.get(i);
System.out.println(course.getId());
System.out.println(course.getTitle());
System.out.println(course.getTutor());
}
courseRepository.deleteAll();
};
}
์ฐธ๊ณ ) Repository์ update๊ฐ ์๊ธฐ ๋๋ฌธ์ update๋ service์ ์์ฑํ๋ค๊ณ ํ๋ค.
์ฐธ๊ณ ์๋ฃ: ์คํ๋ฅดํ์ฝ๋ฉํด๋ฝ ์น๊ฐ๋ฐ์ ๋ด, Spring 2์ฃผ์ฐจ ๊ฐ์์๋ฃ