Skip to content

Commit

Permalink
[feat/CK-236] JdbcTemplate을 이용하여 bulk insert를 적용한다 (#198)
Browse files Browse the repository at this point in the history
* refactor: 기존 saveAll, deleteAll을 bulk insert로 개선

* refactor: Dao 대신 Repository 계층에 의존하도록 수정 - JdbcRepository 추상화
  • Loading branch information
miseongk authored Dec 2, 2023
1 parent 2944699 commit f79f929
Show file tree
Hide file tree
Showing 13 changed files with 105 additions and 49 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package co.kirikiri.persistence.goalroom;

import co.kirikiri.domain.goalroom.GoalRoomMember;
import java.util.List;

public interface GoalRoomMemberJdbcRepository {

void saveAllInBatch(final List<GoalRoomMember> goalRoomMembers);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package co.kirikiri.persistence.goalroom;

import co.kirikiri.domain.goalroom.GoalRoomMember;
import java.util.List;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class GoalRoomMemberJdbcRepositoryImpl implements GoalRoomMemberJdbcRepository {

private final JdbcTemplate jdbcTemplate;

public GoalRoomMemberJdbcRepositoryImpl(final JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}

@Override
public void saveAllInBatch(final List<GoalRoomMember> goalRoomMembers) {
final String sql = "INSERT INTO goal_room_member "
+ "(goal_room_id, member_id, role, joined_at, accomplishment_rate) "
+ "VALUES (?, ?, ?, ?, ?)";
jdbcTemplate.batchUpdate(sql, goalRoomMembers, goalRoomMembers.size(), ((ps, goalRoomMember) -> {
ps.setLong(1, goalRoomMember.getGoalRoom().getId());
ps.setLong(2, goalRoomMember.getMember().getId());
ps.setString(3, goalRoomMember.getRole().name());
ps.setObject(4, goalRoomMember.getJoinedAt());
ps.setDouble(5, goalRoomMember.getAccomplishmentRate());
}));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
import co.kirikiri.domain.goalroom.GoalRoom;
import co.kirikiri.domain.goalroom.GoalRoomMember;
import co.kirikiri.domain.member.vo.Identifier;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
import java.util.Optional;

public interface GoalRoomMemberRepository extends JpaRepository<GoalRoomMember, Long>, GoalRoomMemberQueryRepository {
public interface GoalRoomMemberRepository extends JpaRepository<GoalRoomMember, Long>,
GoalRoomMemberQueryRepository, GoalRoomMemberJdbcRepository {

@Query("select gm from GoalRoomMember gm "
+ "inner join fetch gm.goalRoom g "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
import co.kirikiri.domain.goalroom.GoalRoom;
import co.kirikiri.domain.goalroom.GoalRoomPendingMember;
import co.kirikiri.domain.member.vo.Identifier;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
import java.util.Optional;

public interface GoalRoomPendingMemberRepository extends JpaRepository<GoalRoomPendingMember, Long>,
GoalRoomPendingMemberQueryRepository {
Expand All @@ -28,4 +29,8 @@ Optional<GoalRoomPendingMember> findByGoalRoomAndMemberIdentifier(
+ "where g=:goalRoom "
+ "and gp.member = m")
List<GoalRoomPendingMember> findAllByGoalRoom(@Param("goalRoom") final GoalRoom goalRoom);

@Modifying
@Query("DELETE FROM GoalRoomPendingMember gp WHERE gp.id IN :ids")
void deleteAllByIdIn(@Param("ids") final List<Long> ids);
}
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ public List<GoalRoom> findByRoadmap(final Roadmap roadmap) {
@Override
public List<GoalRoom> findAllRecruitingGoalRoomsByStartDateEarlierThan(final LocalDate date) {
return selectFrom(goalRoom)
.innerJoin(goalRoom.goalRoomPendingMembers.values, goalRoomPendingMember)
.fetchJoin()
.where(statusCond(GoalRoomStatus.RECRUITING))
.where(equalOrEarlierStartDateThan(date))
.fetch();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package co.kirikiri.service.scheduler;

import co.kirikiri.domain.BaseEntity;
import co.kirikiri.domain.goalroom.GoalRoom;
import co.kirikiri.domain.goalroom.GoalRoomMember;
import co.kirikiri.domain.goalroom.GoalRoomPendingMember;
import co.kirikiri.persistence.goalroom.GoalRoomMemberRepository;
import co.kirikiri.persistence.goalroom.GoalRoomPendingMemberRepository;
import co.kirikiri.persistence.goalroom.GoalRoomRepository;
import co.kirikiri.service.aop.ExceptionConvert;
import java.time.LocalDate;
Expand All @@ -19,23 +22,25 @@
public class GoalRoomScheduler {

private final GoalRoomRepository goalRoomRepository;
private final GoalRoomPendingMemberRepository goalRoomPendingMemberRepository;
private final GoalRoomMemberRepository goalRoomMemberRepository;

@Scheduled(cron = "0 0 0 * * *")
public void startGoalRooms() {
final List<GoalRoom> goalRoomsToStart = goalRoomRepository.findAllRecruitingGoalRoomsByStartDateEarlierThan(
LocalDate.now());
for (final GoalRoom goalRoom : goalRoomsToStart) {
final List<GoalRoomPendingMember> goalRoomPendingMembers = goalRoom.getGoalRoomPendingMembers().getValues();
saveGoalRoomMemberFromPendingMembers(goalRoomPendingMembers, goalRoom);
saveGoalRoomMemberFromPendingMembers(goalRoomPendingMembers);
goalRoom.start();
}
}

private void saveGoalRoomMemberFromPendingMembers(final List<GoalRoomPendingMember> goalRoomPendingMembers,
final GoalRoom goalRoom) {
private void saveGoalRoomMemberFromPendingMembers(final List<GoalRoomPendingMember> goalRoomPendingMembers) {
final List<GoalRoomMember> goalRoomMembers = makeGoalRoomMembers(goalRoomPendingMembers);
goalRoom.addAllGoalRoomMembers(goalRoomMembers);
goalRoom.deleteAllPendingMembers();
goalRoomMemberRepository.saveAllInBatch(goalRoomMembers);
final List<Long> ids = makeGoalRoomPendingMemberIds(goalRoomPendingMembers);
goalRoomPendingMemberRepository.deleteAllByIdIn(ids);
}

private List<GoalRoomMember> makeGoalRoomMembers(final List<GoalRoomPendingMember> goalRoomPendingMembers) {
Expand All @@ -45,9 +50,14 @@ private List<GoalRoomMember> makeGoalRoomMembers(final List<GoalRoomPendingMembe
}

private GoalRoomMember makeGoalRoomMember(final GoalRoomPendingMember goalRoomPendingMember) {
return new GoalRoomMember(goalRoomPendingMember.getRole(),
goalRoomPendingMember.getJoinedAt(), goalRoomPendingMember.getGoalRoom(),
goalRoomPendingMember.getMember());
return new GoalRoomMember(goalRoomPendingMember.getRole(), goalRoomPendingMember.getJoinedAt(),
goalRoomPendingMember.getGoalRoom(), goalRoomPendingMember.getMember());
}

private List<Long> makeGoalRoomPendingMemberIds(final List<GoalRoomPendingMember> goalRoomPendingMembers) {
return goalRoomPendingMembers.stream()
.map(BaseEntity::getId)
.toList();
}

@Scheduled(cron = "0 0 4 * * *")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,17 @@
import co.kirikiri.integration.helper.InitIntegrationTest;
import co.kirikiri.persistence.goalroom.GoalRoomMemberRepository;
import co.kirikiri.persistence.goalroom.GoalRoomPendingMemberRepository;
import co.kirikiri.service.scheduler.GoalRoomScheduler;
import co.kirikiri.service.dto.auth.request.LoginRequest;
import co.kirikiri.service.dto.goalroom.request.GoalRoomCreateRequest;
import co.kirikiri.service.dto.goalroom.request.GoalRoomRoadmapNodeRequest;
import co.kirikiri.service.dto.member.request.GenderType;
import co.kirikiri.service.dto.member.request.MemberJoinRequest;
import co.kirikiri.service.dto.member.response.MemberGoalRoomResponse;
import co.kirikiri.service.dto.roadmap.response.RoadmapResponse;
import org.junit.jupiter.api.Test;
import co.kirikiri.service.scheduler.GoalRoomScheduler;
import java.io.IOException;
import java.util.List;
import org.junit.jupiter.api.Test;

class GoalRoomSchedulerIntegrationTest extends InitIntegrationTest {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public TestTransactionService(final GoalRoomRepository goalRoomRepository,
}

public void 골룸_멤버를_저장한다(final List<GoalRoomMember> 골룸_멤버_리스트) {
goalRoomMemberRepository.saveAll(골룸_멤버_리스트);
goalRoomMemberRepository.saveAllInBatch(골룸_멤버_리스트);
}

public void 골룸의_상태와_종료날짜를_변경한다(final Long 골룸_아이디, final GoalRoomStatus 골룸_상태, final LocalDate 변경할_종료날짜) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@
import co.kirikiri.persistence.member.MemberRepository;
import co.kirikiri.persistence.roadmap.RoadmapCategoryRepository;
import co.kirikiri.persistence.roadmap.RoadmapRepository;
import org.junit.jupiter.api.Test;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import org.junit.jupiter.api.Test;

@RepositoryTest
class CheckFeedRepositoryTest {
Expand Down Expand Up @@ -86,7 +86,7 @@ public CheckFeedRepositoryTest(final MemberRepository memberRepository,
final GoalRoomMember leader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, creator);
final GoalRoomMember joinedMember = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom,
member);
goalRoomMemberRepository.saveAll(List.of(leader, joinedMember));
goalRoomMemberRepository.saveAllInBatch(List.of(leader, joinedMember));

final GoalRoomRoadmapNode goalRoomRoadmapNode = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0);
인증_피드를_저장한다(goalRoomRoadmapNode, joinedMember);
Expand Down Expand Up @@ -120,7 +120,7 @@ public CheckFeedRepositoryTest(final MemberRepository memberRepository,
final GoalRoomMember leader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, creator);
final GoalRoomMember joinedMember = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom,
member);
goalRoomMemberRepository.saveAll(List.of(leader, joinedMember));
goalRoomMemberRepository.saveAllInBatch(List.of(leader, joinedMember));

final GoalRoomRoadmapNode goalRoomRoadmapNode = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0);
인증_피드를_저장한다(goalRoomRoadmapNode, joinedMember);
Expand Down Expand Up @@ -151,7 +151,7 @@ public CheckFeedRepositoryTest(final MemberRepository memberRepository,
final GoalRoomMember leader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, creator);
final GoalRoomMember joinedMember = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom,
member);
goalRoomMemberRepository.saveAll(List.of(leader, joinedMember));
goalRoomMemberRepository.saveAllInBatch(List.of(leader, joinedMember));

final GoalRoomRoadmapNode goalRoomRoadmapNode1 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0);
final GoalRoomRoadmapNode goalRoomRoadmapNode2 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(1);
Expand Down Expand Up @@ -188,7 +188,7 @@ public CheckFeedRepositoryTest(final MemberRepository memberRepository,
member);
final GoalRoomMember otherLeader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom2,
creator);
goalRoomMemberRepository.saveAll(List.of(leader, joinedMember));
goalRoomMemberRepository.saveAllInBatch(List.of(leader, joinedMember));

final GoalRoomRoadmapNode goalRoomRoadmapNode1 = goalRoom1.getGoalRoomRoadmapNodes().getValues().get(0);
final GoalRoomRoadmapNode goalRoomRoadmapNode2 = goalRoom1.getGoalRoomRoadmapNodes().getValues().get(1);
Expand Down Expand Up @@ -226,7 +226,7 @@ public CheckFeedRepositoryTest(final MemberRepository memberRepository,
final GoalRoomMember leader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, creator);
final GoalRoomMember joinedMember = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom,
member);
goalRoomMemberRepository.saveAll(List.of(leader, joinedMember));
goalRoomMemberRepository.saveAllInBatch(List.of(leader, joinedMember));

final GoalRoomRoadmapNode goalRoomRoadmapNode1 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0);
final GoalRoomRoadmapNode goalRoomRoadmapNode2 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(1);
Expand Down Expand Up @@ -269,7 +269,7 @@ public CheckFeedRepositoryTest(final MemberRepository memberRepository,
final GoalRoomMember leader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, creator);
final GoalRoomMember joinedMember = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom,
member);
goalRoomMemberRepository.saveAll(List.of(leader, joinedMember));
goalRoomMemberRepository.saveAllInBatch(List.of(leader, joinedMember));

final GoalRoomRoadmapNode goalRoomRoadmapNode1 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0);
final GoalRoomRoadmapNode goalRoomRoadmapNode2 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(1);
Expand Down Expand Up @@ -303,7 +303,7 @@ public CheckFeedRepositoryTest(final MemberRepository memberRepository,
final GoalRoomMember leader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, creator);
final GoalRoomMember joinedMember = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom,
member);
goalRoomMemberRepository.saveAll(List.of(leader, joinedMember));
goalRoomMemberRepository.saveAllInBatch(List.of(leader, joinedMember));

final GoalRoomRoadmapNode goalRoomRoadmapNode1 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0);
final GoalRoomRoadmapNode goalRoomRoadmapNode2 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(1);
Expand Down Expand Up @@ -348,7 +348,7 @@ public CheckFeedRepositoryTest(final MemberRepository memberRepository,
final GoalRoomMember leader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, creator);
final GoalRoomMember joinedMember = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom,
member);
goalRoomMemberRepository.saveAll(List.of(leader, joinedMember));
goalRoomMemberRepository.saveAllInBatch(List.of(leader, joinedMember));

final GoalRoomRoadmapNode goalRoomRoadmapNode1 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0);
final GoalRoomRoadmapNode goalRoomRoadmapNode2 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(1);
Expand Down Expand Up @@ -407,7 +407,7 @@ public CheckFeedRepositoryTest(final MemberRepository memberRepository,
final GoalRoomMember leader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, creator);
final GoalRoomMember joinedMember = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom,
member);
goalRoomMemberRepository.saveAll(List.of(leader, joinedMember));
goalRoomMemberRepository.saveAllInBatch(List.of(leader, joinedMember));

final GoalRoomRoadmapNode goalRoomRoadmapNode1 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0);
final GoalRoomRoadmapNode goalRoomRoadmapNode2 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@
import co.kirikiri.persistence.member.MemberRepository;
import co.kirikiri.persistence.roadmap.RoadmapCategoryRepository;
import co.kirikiri.persistence.roadmap.RoadmapRepository;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;

@RepositoryTest
class GoalRoomMemberRepositoryTest {
Expand Down Expand Up @@ -296,11 +296,13 @@ public GoalRoomMemberRepositoryTest(final MemberRepository memberRepository,
private Member 크리에이터를_저장한다() {
final MemberImage memberImage = new MemberImage("originalFileName", "serverFilePath", ImageContentType.JPG);
final MemberProfile memberProfile = new MemberProfile(Gender.MALE, "kirikiri1@email.com");
final Member creator = new Member(1L, new Identifier("cokirikiri"), null, new EncryptedPassword(new Password("password1!")), new Nickname("코끼리"), memberImage, memberProfile);
final Member creator = new Member(1L, new Identifier("cokirikiri"), null,
new EncryptedPassword(new Password("password1!")), new Nickname("코끼리"), memberImage, memberProfile);
return memberRepository.save(creator);
}

private Member 사용자를_생성한다(final String identifier, final String password, final String nickname, final String email) {
private Member 사용자를_생성한다(final String identifier, final String password, final String nickname,
final String email) {
final MemberProfile memberProfile = new MemberProfile(Gender.MALE, email);
final Member member = new Member(new Identifier(identifier),
new EncryptedPassword(new Password(password)), new Nickname(nickname),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@
import co.kirikiri.persistence.member.MemberRepository;
import co.kirikiri.persistence.roadmap.RoadmapCategoryRepository;
import co.kirikiri.persistence.roadmap.RoadmapRepository;
import org.junit.jupiter.api.Test;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import org.junit.jupiter.api.Test;

@RepositoryTest
class GoalRoomToDoCheckRepositoryTest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@
import co.kirikiri.persistence.goalroom.GoalRoomRepository;
import co.kirikiri.persistence.helper.RepositoryTest;
import co.kirikiri.persistence.member.MemberRepository;
import org.junit.jupiter.api.Test;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import org.junit.jupiter.api.Test;

@RepositoryTest
class RoadmapRepositoryTest {
Expand Down Expand Up @@ -249,13 +249,13 @@ public RoadmapRepositoryTest(final MemberRepository memberRepository,
// gameRoadmap2 : 참가인원 1명
final List<GoalRoomMember> gameRoadmap2GoalRoomMembers = List.of(
new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), gameRoadmap2GoalRoom, creator));
goalRoomMemberRepository.saveAll(gameRoadmap2GoalRoomMembers);
goalRoomMemberRepository.saveAllInBatch(gameRoadmap2GoalRoomMembers);

// travelRoadmap : 참가인원 2명
final List<GoalRoomMember> travelRoadmapGoalRoomMembers = List.of(
new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), travelRoadmapGoalRoom, creator),
new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), travelRoadmapGoalRoom, follower));
goalRoomMemberRepository.saveAll(travelRoadmapGoalRoomMembers);
goalRoomMemberRepository.saveAllInBatch(travelRoadmapGoalRoomMembers);

final RoadmapCategory category = null;
final RoadmapOrderType orderType = RoadmapOrderType.PARTICIPANT_COUNT;
Expand Down
Loading

0 comments on commit f79f929

Please sign in to comment.