-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
GETP-324 feat: 프로젝트 테이블 인덱스 설계를 위한 배치 프로그램 작성 (#181)
* GETP-324 feat: 프로젝트 배치 삽입 기능 구현 * GETP-324 feat: 프로젝트 배치 삽입 기능을 ExecutorService을 이용해 약 3.17배 개선 * GETP-324 feat: 프로젝트 해시태그, 첨부 파일 배치 삽입 기능 구현 및 속도 약 24.34배 개선 * GETP-324 feat: 프로젝트 지원 배치 삽입 기능 구현
- Loading branch information
Showing
27 changed files
with
967 additions
and
37 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
dependencies { | ||
implementation(project(":get-p-domain")) | ||
implementation(project(":get-p-persistence")) | ||
implementation(testFixtures(project(":get-p-domain"))) | ||
testImplementation(testFixtures(project(':get-p-domain'))) | ||
|
||
// Spring Data | ||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa:3.3.5' | ||
|
||
// Flyway | ||
implementation 'org.flywaydb:flyway-core:9.16.3' | ||
implementation 'org.flywaydb:flyway-mysql:9.16.3' | ||
|
||
// JDBC MySQL 드라이버 | ||
runtimeOnly 'com.mysql:mysql-connector-j:9.0.0' | ||
} | ||
|
||
bootJar { | ||
enabled = true | ||
} | ||
|
||
jar { | ||
enabled = false | ||
} |
12 changes: 12 additions & 0 deletions
12
get-p-batch/src/main/java/es/princip/getp/batch/BatchInsertionException.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,12 @@ | ||
package es.princip.getp.batch; | ||
|
||
public class BatchInsertionException extends RuntimeException { | ||
|
||
public BatchInsertionException(final String message) { | ||
super(message); | ||
} | ||
|
||
public BatchInsertionException(final String message, final Throwable cause) { | ||
super(message, cause); | ||
} | ||
} |
34 changes: 34 additions & 0 deletions
34
get-p-batch/src/main/java/es/princip/getp/batch/GetpBatchApplication.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,34 @@ | ||
package es.princip.getp.batch; | ||
|
||
import es.princip.getp.batch.project.commission.BatchDeleteProjectService; | ||
import es.princip.getp.batch.project.commission.ParallelBatchInsertProjectService; | ||
import es.princip.getp.batch.project.apply.BatchDeleteProjectApplicationService; | ||
import es.princip.getp.batch.project.apply.BatchInsertProjectApplicationService; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.CommandLineRunner; | ||
import org.springframework.boot.SpringApplication; | ||
import org.springframework.boot.autoconfigure.SpringBootApplication; | ||
|
||
@SpringBootApplication | ||
public class GetpBatchApplication implements CommandLineRunner { | ||
|
||
@Autowired private BatchDeleteProjectApplicationService batchDeleteProjectApplicationService; | ||
@Autowired private BatchDeleteProjectService batchDeleteProjectService; | ||
|
||
@Autowired private BatchInsertProjectApplicationService batchInsertProjectApplicationService; | ||
@Autowired private ParallelBatchInsertProjectService batchInsertProjectService; | ||
|
||
public static void main(String[] args) { | ||
SpringApplication.run(GetpBatchApplication.class, args); | ||
} | ||
|
||
private static final int PROJECT_SIZE = 100_000; | ||
@Override | ||
public void run(final String... args) { | ||
batchDeleteProjectApplicationService.delete(); | ||
batchDeleteProjectService.delete(); | ||
|
||
batchInsertProjectService.insert(PROJECT_SIZE); | ||
batchInsertProjectApplicationService.insert(PROJECT_SIZE); | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
get-p-batch/src/main/java/es/princip/getp/batch/UniqueLongGenerator.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,11 @@ | ||
package es.princip.getp.batch; | ||
|
||
import java.util.concurrent.atomic.AtomicLong; | ||
|
||
public class UniqueLongGenerator { | ||
private static final AtomicLong counter = new AtomicLong(); | ||
|
||
public static long generateUniqueLong() { | ||
return counter.incrementAndGet(); | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
get-p-batch/src/main/java/es/princip/getp/batch/config/ExecutionTimer.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,30 @@ | ||
package es.princip.getp.batch.config; | ||
|
||
import lombok.extern.slf4j.Slf4j; | ||
import org.aspectj.lang.ProceedingJoinPoint; | ||
import org.aspectj.lang.annotation.Around; | ||
import org.aspectj.lang.annotation.Aspect; | ||
import org.aspectj.lang.annotation.Pointcut; | ||
import org.springframework.stereotype.Component; | ||
|
||
@Slf4j | ||
@Aspect | ||
@Component | ||
public class ExecutionTimer { | ||
|
||
@Pointcut("@annotation(es.princip.getp.batch.config.ExtendsWithExecutionTimer)") | ||
private void timer() {} | ||
|
||
@Around("timer()") | ||
public Object AssumeExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable { | ||
final long start = System.currentTimeMillis(); | ||
try { | ||
return joinPoint.proceed(); | ||
} finally { | ||
final long finish = System.currentTimeMillis(); | ||
final long executionTime = finish - start; | ||
final String signature = joinPoint.getSignature().toShortString(); | ||
log.info("execution time of {}: {}ms", signature, executionTime); | ||
} | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
get-p-batch/src/main/java/es/princip/getp/batch/config/ExtendsWithExecutionTimer.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,11 @@ | ||
package es.princip.getp.batch.config; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
public @interface ExtendsWithExecutionTimer { | ||
} |
51 changes: 51 additions & 0 deletions
51
get-p-batch/src/main/java/es/princip/getp/batch/parallel/ParallelBatchInsertService.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 es.princip.getp.batch.parallel; | ||
|
||
import es.princip.getp.batch.BatchInsertionException; | ||
import lombok.Getter; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.stereotype.Service; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.concurrent.CompletableFuture; | ||
import java.util.concurrent.ExecutorService; | ||
import java.util.concurrent.Executors; | ||
|
||
@Slf4j | ||
@Service | ||
public class ParallelBatchInsertService { | ||
|
||
@Getter | ||
private final int numThreads = Runtime.getRuntime().availableProcessors(); | ||
|
||
public void insert(final int size, final ParallelBatchInserter batchInserter) { | ||
final ExecutorService executorService = Executors.newFixedThreadPool(numThreads); | ||
final List<CompletableFuture<Void>> futures = new ArrayList<>(); | ||
final int batchSize = size / numThreads; | ||
for (int i = 0; i < numThreads; i++) { | ||
final int start = i * batchSize + 1; | ||
final int end = (i == numThreads - 1) ? size : start + batchSize - 1; | ||
final CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { | ||
final String threadName = Thread.currentThread().getName(); | ||
log.info("Thread {} is inserting projects from {} to {}", threadName, start, end); | ||
try { | ||
batchInserter.insert(start, end); | ||
} catch (final Exception exception) { | ||
throw new BatchInsertionException( | ||
String.format( | ||
"Thread %s encountered an error during batch insert for range %d to %d: ", | ||
threadName, | ||
start, | ||
end | ||
), | ||
exception | ||
); | ||
} | ||
}, executorService); | ||
futures.add(future); | ||
} | ||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); | ||
executorService.shutdown(); | ||
log.info("All threads completed. Executor service shutdown."); | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
get-p-batch/src/main/java/es/princip/getp/batch/parallel/ParallelBatchInserter.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,6 @@ | ||
package es.princip.getp.batch.parallel; | ||
|
||
@FunctionalInterface | ||
public interface ParallelBatchInserter { | ||
void insert(int start, int end); | ||
} |
27 changes: 27 additions & 0 deletions
27
...c/main/java/es/princip/getp/batch/project/apply/BatchDeleteProjectApplicationService.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,27 @@ | ||
package es.princip.getp.batch.project.apply; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
import org.springframework.stereotype.Service; | ||
|
||
@Slf4j | ||
@Service | ||
@RequiredArgsConstructor | ||
public class BatchDeleteProjectApplicationService { | ||
|
||
private final JdbcTemplate jdbcTemplate; | ||
|
||
public void delete() { | ||
jdbcTemplate.execute("delete from team_project_application_teammate"); | ||
jdbcTemplate.execute("delete from team_project_application"); | ||
jdbcTemplate.execute("delete from individual_project_application"); | ||
jdbcTemplate.execute("delete from project_application_attachment_file"); | ||
jdbcTemplate.execute("delete from project_application"); | ||
log.info("Table \"team_project_application_teammate\" is dropped"); | ||
log.info("Table \"team_project_application\" is dropped"); | ||
log.info("Table \"individual_project_application\" is dropped"); | ||
log.info("Table \"project_application_attachment_file\" is dropped"); | ||
log.info("Table \"project_application\" is dropped"); | ||
} | ||
} |
45 changes: 45 additions & 0 deletions
45
.../princip/getp/batch/project/apply/BatchInsertIndividualProjectApplicationJdbcService.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,45 @@ | ||
package es.princip.getp.batch.project.apply; | ||
|
||
import es.princip.getp.domain.project.apply.model.IndividualProjectApplication; | ||
import es.princip.getp.domain.project.apply.model.ProjectApplication; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.jdbc.core.BatchPreparedStatementSetter; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
import org.springframework.stereotype.Service; | ||
|
||
import java.sql.PreparedStatement; | ||
import java.sql.SQLException; | ||
import java.util.List; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
class BatchInsertIndividualProjectApplicationJdbcService { | ||
|
||
private final JdbcTemplate jdbcTemplate; | ||
private static final String sql = | ||
""" | ||
insert into individual_project_application ( | ||
project_application_id | ||
) values (?); | ||
"""; | ||
|
||
public void batchUpdate(final List<ProjectApplication> applications) { | ||
final List<IndividualProjectApplication> individuals = applications.stream() | ||
.filter(IndividualProjectApplication.class::isInstance) | ||
.map(IndividualProjectApplication.class::cast) | ||
.toList(); | ||
|
||
jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() { | ||
@Override | ||
public void setValues(final PreparedStatement ps, final int i) throws SQLException { | ||
final IndividualProjectApplication application = individuals.get(i); | ||
ps.setLong(1, application.getId().getValue()); | ||
} | ||
|
||
@Override | ||
public int getBatchSize() { | ||
return individuals.size(); | ||
} | ||
}); | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
...ncip/getp/batch/project/apply/BatchInsertProjectApplicationAttachmentFileJdbcService.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,58 @@ | ||
package es.princip.getp.batch.project.apply; | ||
|
||
import es.princip.getp.domain.common.model.AttachmentFile; | ||
import es.princip.getp.domain.project.apply.model.ProjectApplication; | ||
import es.princip.getp.domain.project.apply.model.ProjectApplicationId; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.jdbc.core.BatchPreparedStatementSetter; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
import org.springframework.stereotype.Service; | ||
|
||
import java.sql.PreparedStatement; | ||
import java.sql.SQLException; | ||
import java.util.List; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
class BatchInsertProjectApplicationAttachmentFileJdbcService { | ||
|
||
private record ProjectApplicationIdAttachmentFile( | ||
ProjectApplicationId applicationId, | ||
AttachmentFile attachmentFile | ||
) { | ||
} | ||
|
||
private final JdbcTemplate jdbcTemplate; | ||
private static final String sql = | ||
""" | ||
insert into project_application_attachment_file( | ||
project_application_id, | ||
attachment_files | ||
) values (?, ?); | ||
"""; | ||
|
||
public void batchUpdate(final List<ProjectApplication> applications) { | ||
final List<ProjectApplicationIdAttachmentFile> attachmentFiles = applications.stream() | ||
.flatMap(application -> application.getAttachmentFiles().stream() | ||
.map(attachmentFile -> new ProjectApplicationIdAttachmentFile( | ||
application.getId(), | ||
attachmentFile | ||
))) | ||
.toList(); | ||
|
||
jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() { | ||
@Override | ||
public void setValues(final PreparedStatement ps, final int i) throws SQLException { | ||
final ProjectApplicationId applicationId = attachmentFiles.get(i).applicationId(); | ||
final AttachmentFile attachmentFile = attachmentFiles.get(i).attachmentFile(); | ||
ps.setLong(1, applicationId.getValue()); | ||
ps.setString(2, attachmentFile.getUrl().getValue()); | ||
} | ||
|
||
@Override | ||
public int getBatchSize() { | ||
return attachmentFiles.size(); | ||
} | ||
}); | ||
} | ||
} |
65 changes: 65 additions & 0 deletions
65
...in/java/es/princip/getp/batch/project/apply/BatchInsertProjectApplicationJdbcService.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,65 @@ | ||
package es.princip.getp.batch.project.apply; | ||
|
||
import es.princip.getp.domain.project.apply.model.IndividualProjectApplication; | ||
import es.princip.getp.domain.project.apply.model.ProjectApplication; | ||
import es.princip.getp.domain.project.apply.model.TeamProjectApplication; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.jdbc.core.BatchPreparedStatementSetter; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
import org.springframework.stereotype.Service; | ||
|
||
import java.sql.Date; | ||
import java.sql.PreparedStatement; | ||
import java.sql.SQLException; | ||
import java.util.List; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
class BatchInsertProjectApplicationJdbcService { | ||
|
||
private final BatchInsertProjectApplicationAttachmentFileJdbcService attachmentFileJdbcService; | ||
private final BatchInsertTeamProjectApplicationJdbcService teamJdbcService; | ||
private final BatchInsertIndividualProjectApplicationJdbcService individualJdbcService; | ||
private final JdbcTemplate jdbcTemplate; | ||
private static final String sql = | ||
""" | ||
insert into project_application ( | ||
project_application_id, | ||
expected_end_date, | ||
expected_start_date, | ||
description, | ||
status, | ||
people_id, | ||
project_id, | ||
dtype | ||
) values (?, ?, ?, ?, ?, ?, ?, ?); | ||
"""; | ||
|
||
public void batchUpdate(final List<ProjectApplication> applications) { | ||
jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() { | ||
@Override | ||
public void setValues(final PreparedStatement ps, final int i) throws SQLException { | ||
final ProjectApplication application = applications.get(i); | ||
final String dtype = (application instanceof TeamProjectApplication) ? | ||
TeamProjectApplication.TYPE : IndividualProjectApplication.TYPE; | ||
ps.setLong(1, application.getId().getValue()); | ||
ps.setDate(2, Date.valueOf(application.getExpectedDuration().getEndDate())); | ||
ps.setDate(3, Date.valueOf(application.getExpectedDuration().getStartDate())); | ||
ps.setString(4, application.getDescription()); | ||
ps.setString(5, application.getStatus().toString()); | ||
ps.setLong(6, application.getApplicantId().getValue()); | ||
ps.setLong(7, application.getProjectId().getValue()); | ||
ps.setString(8,dtype); | ||
} | ||
|
||
@Override | ||
public int getBatchSize() { | ||
return applications.size(); | ||
} | ||
}); | ||
|
||
attachmentFileJdbcService.batchUpdate(applications); | ||
individualJdbcService.batchUpdate(applications); | ||
teamJdbcService.batchUpdate(applications); | ||
} | ||
} |
Oops, something went wrong.