Skip to content

Commit

Permalink
feat: 파일에서 DB 저장 bulk insert 최적화 및 불필요한 csv 파일 생성 차단
Browse files Browse the repository at this point in the history
  • Loading branch information
juno-junho committed May 20, 2024
1 parent ea45b52 commit 58fca5f
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 14 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.spaceclub.global.annotation.profanity.domain.repository;

import com.spaceclub.global.annotation.profanity.domain.Profanity;

import java.util.List;

public interface ProfanityCustomRepository {

void bulkInsert(List<Profanity> profanities);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.spaceclub.global.annotation.profanity.domain.repository;

import com.spaceclub.global.annotation.profanity.domain.Profanity;
import lombok.RequiredArgsConstructor;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.List;

@RequiredArgsConstructor
public class ProfanityCustomRepositoryImpl implements ProfanityCustomRepository {

private final JdbcTemplate jdbcTemplate;

@Override
public void bulkInsert(List<Profanity> profanities) {
String sql = "INSERT INTO profanity (ban_word, use_count, created_at, last_modified_at) " +
"VALUES (?, ?, ?, ?)";
LocalDateTime now = LocalDateTime.now();

jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {

@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
Profanity profanity = profanities.get(i);
ps.setString(1, profanity.getBanWord());
ps.setLong(2, profanity.getUseCount());
ps.setObject(3, now); // created date
ps.setObject(4, now); // last modified date
}

@Override
public int getBatchSize() {
return profanities.size();
}

});
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.spaceclub.global.annotation.profanity.domain.repository;

import com.spaceclub.global.annotation.profanity.domain.Profanity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.time.LocalDateTime;

public interface ProfanityRepository extends JpaRepository<Profanity, Long>, ProfanityCustomRepository {

@Query("SELECT MAX(p.lastModifiedAt) FROM Profanity p")
LocalDateTime findLatestModifiedDate();

boolean existsByBanWord(String word);

Profanity findByBanWord(String banWord);

void deleteByBanWord(String word);

}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.spaceclub.global.annotation.profanity.service;

import com.spaceclub.global.annotation.profanity.domain.Profanity;
import com.spaceclub.global.annotation.profanity.domain.ProfanityRepository;
import com.spaceclub.global.annotation.profanity.domain.repository.ProfanityRepository;
import com.spaceclub.global.aws.s3.S3FileUploader;
import com.spaceclub.global.timer.StopWatch;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.springframework.stereotype.Service;
Expand All @@ -14,27 +16,33 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.time.LocalDateTime;
import java.util.List;

import static com.spaceclub.global.annotation.profanity.ProfanityExceptionMessage.BAD_WORD_ALREADY_EXISTS;
import static com.spaceclub.global.annotation.profanity.ProfanityExceptionMessage.FAILED_TO_CREATE_CSV;
import static com.spaceclub.global.annotation.profanity.ProfanityExceptionMessage.FAILED_TO_SAVE;

@Slf4j
@Service
@RequiredArgsConstructor
public class ProfanityService {

private final ProfanityRepository profanityRepository;
private final S3FileUploader s3FileUploader;

private String downloadUrl;
private LocalDateTime downloadDate = LocalDateTime.now();

@StopWatch
public void saveProfanitiesFromFile(MultipartFile file) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(file.getInputStream()))) {
List<Profanity> profanities = reader.lines()
.distinct()
.map(Profanity::new)
.toList();

profanityRepository.saveAllAndFlush(profanities); // 트랜잭션 원자화
profanityRepository.bulkInsert(profanities);
} catch (IOException e) {
throw new IllegalStateException(FAILED_TO_SAVE.getMessage());
}
Expand All @@ -56,6 +64,10 @@ public void deleteProfanity(String word) {

public String createCsvFile() {
// 여기에 csv 파일 생성 여부 추가
if (downloadUrl != null && profanityRepository.findLatestModifiedDate().isBefore(downloadDate)) {
return downloadUrl;
}

List<Profanity> profanities = profanityRepository.findAll();

CSVFormat csvFormat = CSVFormat.DEFAULT.builder()
Expand All @@ -70,10 +82,18 @@ public String createCsvFile() {
}
printer.flush();

return s3FileUploader.uploadProfanityInfo(writer.toString());
String filePath = s3FileUploader.uploadProfanityInfo(writer.toString());
writeIMemory(filePath);

return filePath;
} catch (IOException e) {
throw new IllegalStateException(FAILED_TO_CREATE_CSV.getMessage());
}
}

private void writeIMemory(String filePath) {
downloadDate = LocalDateTime.now();
downloadUrl = filePath;
}

}

0 comments on commit 58fca5f

Please sign in to comment.