-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[BE] JPA의 saveAll, deleteAll를 bulk query로 개선 (#273)
* feat(ScheduleBatchRepository): jdbcTemplate를 활용한 batchInsert 구현 * refactor(ScheduleRepository): jpql을 작성하여 delete 쿼리가 n건 나가는 문제 개선 * refactor: PreparedStatement 매개변수 NonNull 어노테이션 추가 * fix: 잘못된 batch size 수정 * refactor(ScheduleRepository): 쿼리 메소드 Transactional 어노테이션 추가 * refactor(ScheduleBatchRepository): 배치 업데이트 로직 개선 * feat(AvailableDateBatchRepository): 약속 생성 시 가능 날짜를 배치 처리하도록 개선 * refactor(ScheduleBatchRepository): 배치 사이즈를 500으로 조정
- Loading branch information
1 parent
fc19455
commit 8431474
Showing
10 changed files
with
306 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
backend/src/main/java/kr/momo/domain/availabledate/AvailableDateBatchRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package kr.momo.domain.availabledate; | ||
|
||
import java.sql.Date; | ||
import java.sql.PreparedStatement; | ||
import java.sql.Timestamp; | ||
import java.time.LocalDateTime; | ||
import java.util.Collection; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
import org.springframework.jdbc.core.ParameterizedPreparedStatementSetter; | ||
import org.springframework.stereotype.Repository; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Repository | ||
@RequiredArgsConstructor | ||
public class AvailableDateBatchRepository { | ||
|
||
private static final int BATCH_SIZE = 30; | ||
|
||
private final JdbcTemplate jdbcTemplate; | ||
|
||
@Transactional | ||
public void batchInsert(Collection<AvailableDate> availableDates) { | ||
String sql = """ | ||
INSERT INTO available_date (date, meeting_id, created_at, modified_at) | ||
VALUES (?, ?, ?, ?); | ||
"""; | ||
|
||
executeBatchUpdate(availableDates, sql); | ||
} | ||
|
||
private void executeBatchUpdate(Collection<AvailableDate> availableDates, String sql) { | ||
LocalDateTime now = LocalDateTime.now(); | ||
Timestamp timestamp = Timestamp.valueOf(now); | ||
|
||
jdbcTemplate.batchUpdate(sql, availableDates, BATCH_SIZE, createPreparedStatementSetter(timestamp)); | ||
} | ||
|
||
private ParameterizedPreparedStatementSetter<AvailableDate> createPreparedStatementSetter(Timestamp timestamp) { | ||
return (PreparedStatement ps, AvailableDate availableDate) -> { | ||
ps.setDate(1, Date.valueOf(availableDate.getDate())); | ||
ps.setLong(2, availableDate.meetingId()); | ||
ps.setTimestamp(3, timestamp); | ||
ps.setTimestamp(4, timestamp); | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
backend/src/main/java/kr/momo/domain/schedule/ScheduleBatchRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package kr.momo.domain.schedule; | ||
|
||
import java.sql.PreparedStatement; | ||
import java.sql.Timestamp; | ||
import java.time.LocalDateTime; | ||
import java.util.Collection; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
import org.springframework.jdbc.core.ParameterizedPreparedStatementSetter; | ||
import org.springframework.stereotype.Repository; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Repository | ||
@RequiredArgsConstructor | ||
public class ScheduleBatchRepository { | ||
|
||
private static final int BATCH_SIZE = 500; | ||
|
||
private final JdbcTemplate jdbcTemplate; | ||
|
||
@Transactional | ||
public void batchInsert(Collection<Schedule> schedules) { | ||
String sql = """ | ||
INSERT INTO schedule (attendee_id, available_date_id, timeslot, created_at, modified_at) | ||
VALUES (?, ?, ?, ?, ?); | ||
"""; | ||
|
||
executeBatchUpdate(schedules, sql); | ||
} | ||
|
||
private void executeBatchUpdate(Collection<Schedule> schedules, String sql) { | ||
LocalDateTime now = LocalDateTime.now(); | ||
Timestamp timestamp = Timestamp.valueOf(now); | ||
|
||
jdbcTemplate.batchUpdate(sql, schedules, BATCH_SIZE, createPreparedStatementSetter(timestamp)); | ||
} | ||
|
||
private ParameterizedPreparedStatementSetter<Schedule> createPreparedStatementSetter(Timestamp timestamp) { | ||
return (PreparedStatement ps, Schedule schedule) -> { | ||
ps.setLong(1, schedule.attendeeId()); | ||
ps.setLong(2, schedule.availableDateId()); | ||
ps.setString(3, schedule.getTimeslot().toString()); | ||
ps.setTimestamp(4, timestamp); | ||
ps.setTimestamp(5, timestamp); | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 51 additions & 0 deletions
51
backend/src/test/java/kr/momo/domain/availabledate/AvailableDateBatchRepositoryTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package kr.momo.domain.availabledate; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
import java.util.List; | ||
import kr.momo.domain.meeting.Meeting; | ||
import kr.momo.domain.meeting.MeetingRepository; | ||
import kr.momo.fixture.AvailableDateFixture; | ||
import kr.momo.fixture.MeetingFixture; | ||
import kr.momo.support.IsolateDatabase; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
|
||
@SpringBootTest | ||
@IsolateDatabase | ||
class AvailableDateBatchRepositoryTest { | ||
|
||
@Autowired | ||
private JdbcTemplate jdbcTemplate; | ||
|
||
@Autowired | ||
private AvailableDateBatchRepository availableDateBatchRepository; | ||
|
||
@Autowired | ||
private MeetingRepository meetingRepository; | ||
|
||
private Meeting meeting; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
meeting = meetingRepository.save(MeetingFixture.COFFEE.create()); | ||
} | ||
|
||
@DisplayName("AvailableDate 리스트를 Batch Insert 한다.") | ||
@Test | ||
void batchInsertTest() { | ||
List<AvailableDate> availableDate = List.of( | ||
AvailableDateFixture.TODAY.create(meeting), | ||
AvailableDateFixture.TOMORROW.create(meeting) | ||
); | ||
|
||
availableDateBatchRepository.batchInsert(availableDate); | ||
|
||
Integer count = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM available_date", Integer.class); | ||
assertThat(count).isEqualTo(availableDate.size()); | ||
} | ||
} |
67 changes: 67 additions & 0 deletions
67
backend/src/test/java/kr/momo/domain/schedule/ScheduleBatchRepositoryTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package kr.momo.domain.schedule; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
import java.util.List; | ||
import kr.momo.domain.attendee.Attendee; | ||
import kr.momo.domain.attendee.AttendeeRepository; | ||
import kr.momo.domain.availabledate.AvailableDate; | ||
import kr.momo.domain.availabledate.AvailableDateRepository; | ||
import kr.momo.domain.meeting.Meeting; | ||
import kr.momo.domain.meeting.MeetingRepository; | ||
import kr.momo.domain.timeslot.Timeslot; | ||
import kr.momo.fixture.AttendeeFixture; | ||
import kr.momo.fixture.AvailableDateFixture; | ||
import kr.momo.fixture.MeetingFixture; | ||
import kr.momo.support.IsolateDatabase; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
|
||
@SpringBootTest | ||
@IsolateDatabase | ||
class ScheduleBatchRepositoryTest { | ||
|
||
@Autowired | ||
private JdbcTemplate jdbcTemplate; | ||
|
||
@Autowired | ||
private ScheduleBatchRepository scheduleBatchRepository; | ||
|
||
@Autowired | ||
private MeetingRepository meetingRepository; | ||
|
||
@Autowired | ||
private AttendeeRepository attendeeRepository; | ||
|
||
@Autowired | ||
private AvailableDateRepository availableDateRepository; | ||
|
||
private Attendee attendee; | ||
private AvailableDate availableDate; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
Meeting meeting = meetingRepository.save(MeetingFixture.COFFEE.create()); | ||
attendee = attendeeRepository.save(AttendeeFixture.HOST_JAZZ.create(meeting)); | ||
availableDate = availableDateRepository.save(AvailableDateFixture.TODAY.create(meeting)); | ||
} | ||
|
||
@DisplayName("Schedule 리스트를 Batch Insert 한다.") | ||
@Test | ||
void batchInsertTest() { | ||
List<Schedule> schedules = List.of( | ||
new Schedule(attendee, availableDate, Timeslot.TIME_0000), | ||
new Schedule(attendee, availableDate, Timeslot.TIME_0130), | ||
new Schedule(attendee, availableDate, Timeslot.TIME_0230) | ||
); | ||
|
||
scheduleBatchRepository.batchInsert(schedules); | ||
|
||
Integer count = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM schedule", Integer.class); | ||
assertThat(count).isEqualTo(schedules.size()); | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
backend/src/test/java/kr/momo/domain/schedule/ScheduleRepositoryTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package kr.momo.domain.schedule; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
import java.util.List; | ||
import kr.momo.domain.attendee.Attendee; | ||
import kr.momo.domain.attendee.AttendeeRepository; | ||
import kr.momo.domain.availabledate.AvailableDate; | ||
import kr.momo.domain.availabledate.AvailableDateRepository; | ||
import kr.momo.domain.meeting.Meeting; | ||
import kr.momo.domain.meeting.MeetingRepository; | ||
import kr.momo.domain.timeslot.Timeslot; | ||
import kr.momo.fixture.AttendeeFixture; | ||
import kr.momo.fixture.AvailableDateFixture; | ||
import kr.momo.fixture.MeetingFixture; | ||
import kr.momo.support.IsolateDatabase; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
|
||
@SpringBootTest | ||
@IsolateDatabase | ||
class ScheduleRepositoryTest { | ||
|
||
@Autowired | ||
private JdbcTemplate jdbcTemplate; | ||
|
||
@Autowired | ||
private ScheduleRepository scheduleRepository; | ||
|
||
@Autowired | ||
private MeetingRepository meetingRepository; | ||
|
||
@Autowired | ||
private AttendeeRepository attendeeRepository; | ||
|
||
@Autowired | ||
private AvailableDateRepository availableDateRepository; | ||
|
||
private Attendee attendee; | ||
private AvailableDate availableDate; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
Meeting meeting = meetingRepository.save(MeetingFixture.COFFEE.create()); | ||
attendee = attendeeRepository.save(AttendeeFixture.HOST_JAZZ.create(meeting)); | ||
availableDate = availableDateRepository.save(AvailableDateFixture.TODAY.create(meeting)); | ||
} | ||
|
||
@DisplayName("참가자의 스케쥴을 한 번에 삭제한다.") | ||
@Test | ||
void batchInsertTest() { | ||
List<Schedule> schedules = List.of( | ||
new Schedule(attendee, availableDate, Timeslot.TIME_0000), | ||
new Schedule(attendee, availableDate, Timeslot.TIME_0130), | ||
new Schedule(attendee, availableDate, Timeslot.TIME_0230) | ||
); | ||
scheduleRepository.saveAll(schedules); | ||
|
||
scheduleRepository.deleteByAttendee(attendee); | ||
|
||
Integer count = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM schedule", Integer.class); | ||
assertThat(count).isEqualTo(0); | ||
} | ||
} |