회원의 최신 20경기 만을 관리합니다. 때문에 갱신할 때 MatchList를 항상 최신 경기로 update해야 합니다. 이 update 방식에 대한 고찰을 소개합니다.
기존 MatchList에서 update해야 할 index 범위를 찾고 delete한 후 새로운 Match들을 insert 한다.
장점 : 과정을 떠올리기 단순하고 query도 복잡하게 생각할 필요가 없다.
단점 : delete, insert query가 발생한다.
동일하게 index 범위를 찾은 다음 새로운 Match들로 update 한다. 교체될 객체의 id를 이용해 객체에 접근한 후 update 한다.
장점 : 성능이 좋다.
단점 : index에 순차적으로 접근하는 코드가 추가되며 update query이기 때문에 jpql이 다소 복잡하다.
delte + insert는 쿼리가 두 배로 증가한다. 공부 프로젝트니까 성능을 위한 update 방식을 선택했다.
우선 교체가 필요한 게임 수(새로운 게임 수 )를 계산한다.
public int getCountNewMatch(String puuId, String summonerId) {
String targetMatchId = getMatchService.getMatchIds(puuId, LOL.LastIndex, 1).get(0);
List<Match> Match = matchService.findAllBySummonerId(summonerId);
Integer gameCount = getGameCount(Match, targetMatchId);
return Objects.requireNonNullElse(gameCount, LOL.gameCount);
}
private static @Nullable Integer getGameCount(List<Match> Match, String targetMatchId) {
int result;
if (!Match.isEmpty()) {
result = IntStream.range(0, Match.size())
.filter(i -> targetMatchId.equals(Match.get(i).getMatchId()))
.findFirst()
.orElse(-1); // 찾지 못한 경우 -1 반환
if (result != -1) {
return LOL.gameCount - (result + 1);
}
}
return null;
}
그 다음 교체할 범위의 첫 index를 찾고 개수만큼 반복하여 update 한다.
public void updateMatches(SummonerInfo summonerInfo, int newMatchCount, List<Match> newMatchList) {
List<Match> originMatchList = summonerInfo.getMatchList(); // 기존 매치 리스트
List<Match> updatedMatchList = new ArrayList<>(originMatchList); // 업데이트를 위한 새 리스트 생성
// 새로운 매치 정보로 기존 리스트 업데이트
int updateStartIndex = LOL.gameCount - newMatchCount; // 업데이트 시작할 인덱스
for (int j = 0; j < newMatchCount; j++) {
int updateIndex = updateStartIndex + j;
Match newMatch = newMatchList.get(j);
// 기존 매치 정보 업데이트 (in-place 업데이트로 리스트 크기 유지)
updatedMatchList.set(updateIndex, newMatch);
// 데이터베이스 업데이트 호출
matchService.update(newMatch.getMatchId(), newMatch.getGameStartTimestamp(), newMatch.getKills(),
newMatch.getDeaths(), newMatch.getAssists(), newMatch.getKda(), newMatch.getChampionName(),
newMatch.getMainRune(), newMatch.getSubRune(), newMatch.getItemList(),
newMatch.getSummonerSpellList(), newMatch.getResult(),
originMatchList.get(updateIndex).getMatchId());
}
// 업데이트된 리스트로 소환사 정보 업데이트
summonerInfo.updateMatchList(updatedMatchList);
}
@Modifying
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Query("update Match s SET " +
"s.matchId = :matchId, " +
"s.gameStartTimestamp = :gameStartTimestamp, " +
"s.kills = :kills, " +
"s.deaths = :deaths, " +
"s.assists = :assists, " +
"s.kda = :kda, " +
"s.championName = :championName, " +
"s.mainRune = :mainRune, " +
"s.subRune = :subRune, " +
"s.itemList = :itemList, " +
"s.summonerSpellList = :summonerSpellList, " +
"s.result = :result " +
"WHERE s.matchId = :originMatchId")
void update(@Param("matchId") String matchId,
@Param("gameStartTimestamp") Long gameStartTimestamp,
@Param("kills") Long kills,
@Param("deaths") Long deaths,
@Param("assists") Long assists,
@Param("kda") String kda,
@Param("championName") String championName,
@Param("mainRune") Long mainRune,
@Param("subRune") Long subRune,
@Param("itemList") List<Integer> itemList,
@Param("summonerSpellList") List<Integer> summonerSpellList,
@Param("result") String result,
@Param("originMatchId") String originMatchId);
구조는 단순하지만 업데이트 할 필드가 많아 망설였다. jpa의 save()를 쓰고 싶었는데 내 Match 엔티티의 id는 테이블을 관리하기 위한 DB의 id가 아니라 실제 Match의 id 정보라서 id 수정도 필요했기 때문에 어쩔 수 없이 직접 jpql을 작성했다.(id 예시 : KR65486546)