Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion be-submodule
5 changes: 3 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-batch'
// 채팅 웹 소켓
implementation 'org.springframework.boot:spring-boot-starter-websocket'
implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.5'
Expand All @@ -41,7 +42,7 @@ dependencies {
//Flyway
implementation 'org.flywaydb:flyway-core'
implementation 'org.flywaydb:flyway-mysql'

implementation 'com.fasterxml.jackson.core:jackson-databind'
testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1'
compileOnly 'org.projectlombok:lombok'
Expand Down Expand Up @@ -69,4 +70,4 @@ tasks.register('copySecret', Copy) {
from './be-submodule' // 서브 모듈 디렉토리 경로
include "*.properties" // 설정 파일 복사
into 'src/main/resources' // 붙여넣을 위치
}
}
51 changes: 51 additions & 0 deletions src/main/java/com/team/buddyya/job/SeedDataJobConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.team.buddyya.job;

import com.team.buddyya.job.feed.FeedInsertJobConfig;
import com.team.buddyya.job.feed.bookmark.BookmarkInsertJobConfig;
import com.team.buddyya.job.feed.comment.CommentInsertJobConfig;
import com.team.buddyya.job.feed.image.FeedImageInsertJobConfig;
import com.team.buddyya.job.feed.like.FeedLikeInsertJobConfig;
import com.team.buddyya.job.student.StudentInsertJobConfig;
import lombok.RequiredArgsConstructor;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Profile;

@Profile("local")
@Import({StudentInsertJobConfig.class, FeedInsertJobConfig.class, CommentInsertJobConfig.class,
FeedImageInsertJobConfig.class, FeedLikeInsertJobConfig.class, BookmarkInsertJobConfig.class})
@Configuration
@RequiredArgsConstructor
public class SeedDataJobConfig {

public static final int STUDENT_COUNT = 100_000;
public static final int FEED_COUNT = 1_000_000;
public static final int COMMENT_COUNT = 100_000;
public static final int LIKE_COUNT = 500_000;
public static final int BOOKMARK_COUNT = 500_000;

private final JobRepository jobRepository;
private final Step studentInsertStep;
private final Step feedInsertStep;
private final Step commentInsertStep;
private final Step feedImageInsertStep;
private final Step feedLikeInsertStep;
private final Step bookmarkInsertStep;

@Bean
public Job seedDataJob() {
return new JobBuilder("seedDataJob", jobRepository)
.start(studentInsertStep)
.next(feedInsertStep)
.next(commentInsertStep)
.next(feedImageInsertStep)
.next(feedLikeInsertStep)
.next(bookmarkInsertStep)
.build();
}
}
51 changes: 51 additions & 0 deletions src/main/java/com/team/buddyya/job/feed/FeedInsertJobConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.team.buddyya.job.feed;

import static com.team.buddyya.job.SeedDataJobConfig.FEED_COUNT;

import javax.sql.DataSource;
import lombok.RequiredArgsConstructor;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.batch.item.database.builder.JdbcBatchItemWriterBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;

@Configuration
@RequiredArgsConstructor
public class FeedInsertJobConfig {

private final JobRepository jobRepository;
private final PlatformTransactionManager platformTransactionManager;
private final DataSource dataSource;
private static final int CHUNK_SIZE = 1000;

@Bean
public Step feedInsertStep(ItemReader<FeedJobDTO> feedItemReader, JdbcBatchItemWriter<FeedJobDTO> feedItemWriter) {
return new StepBuilder("feedInsertStep", jobRepository)
.<FeedJobDTO, FeedJobDTO>chunk(CHUNK_SIZE, platformTransactionManager)
.reader(feedItemReader)
.writer(feedItemWriter)
.build();
}

@Bean
public ItemReader<FeedJobDTO> feedItemReader() {
return new FeedItemReader(new JdbcTemplate(dataSource), FEED_COUNT);
}

@Bean
public JdbcBatchItemWriter<FeedJobDTO> feedItemWriter() {
String sql = "INSERT INTO feed (title, content, is_profile_visible, student_id, category_id, university_id, like_count, comment_count, view_count, pinned, created_date, updated_date) VALUES (:title, :content, :profileVisible, :studentId, :categoryId, :universityId, 0, 0, 0, false, NOW(), NOW())";
return new JdbcBatchItemWriterBuilder<FeedJobDTO>()
.dataSource(dataSource)
.sql(sql)
.itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
.build();
}
}
60 changes: 60 additions & 0 deletions src/main/java/com/team/buddyya/job/feed/FeedItemReader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.team.buddyya.job.feed;

import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.batch.item.ItemReader;
import org.springframework.jdbc.core.JdbcTemplate;

public class FeedItemReader implements ItemReader<FeedJobDTO> {

private final JdbcTemplate jdbcTemplate;
private final int totalCount;
private final AtomicInteger counter = new AtomicInteger(0);

private Long minStudentId;
private Long maxStudentId;
private Long minUniversityId;
private Long maxUniversityId;

public FeedItemReader(JdbcTemplate jdbcTemplate, int totalCount) {
this.jdbcTemplate = jdbcTemplate;
this.totalCount = totalCount;
}

@Override
public FeedJobDTO read() throws Exception {
if (minStudentId == null) {
// Student, University 테이블의 데이터 존재 여부 및 ID 범위 초기화
if (jdbcTemplate.queryForObject("SELECT COUNT(1) FROM student", Long.class) == 0) {
throw new IllegalStateException("Prerequisite data (Student) is missing.");
}
this.minStudentId = jdbcTemplate.queryForObject("SELECT MIN(id) FROM student", Long.class);
this.maxStudentId = jdbcTemplate.queryForObject("SELECT MAX(id) FROM student", Long.class);
if (jdbcTemplate.queryForObject("SELECT COUNT(1) FROM university", Long.class) == 0) {
throw new IllegalStateException("Prerequisite data (University) is missing.");
}
this.minUniversityId = jdbcTemplate.queryForObject("SELECT MIN(id) FROM university", Long.class);
this.maxUniversityId = jdbcTemplate.queryForObject("SELECT MAX(id) FROM university", Long.class);
}

if (counter.get() >= totalCount) {
return null;
}

int currentCount = counter.incrementAndGet();
long randomStudentId = ThreadLocalRandom.current().nextLong(minStudentId, maxStudentId + 1);
long randomUniversityId = ThreadLocalRandom.current().nextLong(minUniversityId, maxUniversityId + 1);
// Category는 데이터가 적다고 가정하고 SQL로 랜덤 조회, 많아진다면 동일하게 MIN/MAX 방식으로 변경
Long randomCategoryId = jdbcTemplate.queryForObject("SELECT id FROM category ORDER BY RAND() LIMIT 1",
Long.class);

return FeedJobDTO.builder()
.title("피드 제목 " + currentCount)
.content("피드 내용입니다. " + currentCount)
.profileVisible(ThreadLocalRandom.current().nextBoolean())
.studentId(randomStudentId)
.categoryId(randomCategoryId)
.universityId(randomUniversityId)
.build();
}
}
15 changes: 15 additions & 0 deletions src/main/java/com/team/buddyya/job/feed/FeedJobDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.team.buddyya.job.feed;

import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class FeedJobDTO {
private String title;
private String content;
private boolean profileVisible;
private Long studentId;
private Long categoryId;
private Long universityId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.team.buddyya.job.feed.bookmark;

import static com.team.buddyya.job.SeedDataJobConfig.BOOKMARK_COUNT;

import javax.sql.DataSource;
import lombok.RequiredArgsConstructor;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.batch.item.database.builder.JdbcBatchItemWriterBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;

@Configuration
@RequiredArgsConstructor
public class BookmarkInsertJobConfig {

private final JobRepository jobRepository;
private final PlatformTransactionManager platformTransactionManager;
private final DataSource dataSource;
private static final int CHUNK_SIZE = 1000;

@Bean
public Step bookmarkInsertStep(ItemReader<BookmarkJobDTO> bookmarkItemReader,
JdbcBatchItemWriter<BookmarkJobDTO> bookmarkItemWriter) {
return new StepBuilder("bookmarkInsertStep", jobRepository)
.<BookmarkJobDTO, BookmarkJobDTO>chunk(CHUNK_SIZE, platformTransactionManager)
.reader(bookmarkItemReader)
.writer(bookmarkItemWriter)
.build();
}

@Bean
public ItemReader<BookmarkJobDTO> bookmarkItemReader() {
return new BookmarkItemReader(new JdbcTemplate(dataSource), BOOKMARK_COUNT);
}

@Bean
public JdbcBatchItemWriter<BookmarkJobDTO> bookmarkItemWriter() {
String sql = "INSERT IGNORE INTO bookmark (feed_id, student_id, created_date) VALUES (:feedId, :studentId, NOW())";
return new JdbcBatchItemWriterBuilder<BookmarkJobDTO>()
.dataSource(dataSource)
.sql(sql)
.itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
.assertUpdates(false)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.team.buddyya.job.feed.bookmark;

import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.batch.item.ItemReader;
import org.springframework.jdbc.core.JdbcTemplate;

public class BookmarkItemReader implements ItemReader<BookmarkJobDTO> {

private final JdbcTemplate jdbcTemplate;
private final int totalCount;
private final AtomicInteger counter = new AtomicInteger(0);
private final ThreadLocalRandom random = ThreadLocalRandom.current();

private Long minFeedId;
private Long maxFeedId;
private Long minStudentId;
private Long maxStudentId;

public BookmarkItemReader(JdbcTemplate jdbcTemplate, int totalCount) {
this.jdbcTemplate = jdbcTemplate;
this.totalCount = totalCount;
}

@Override
public BookmarkJobDTO read() {
if (minFeedId == null) {
this.minFeedId = jdbcTemplate.queryForObject("SELECT MIN(id) FROM feed", Long.class);
this.maxFeedId = jdbcTemplate.queryForObject("SELECT MAX(id) FROM feed", Long.class);
this.minStudentId = jdbcTemplate.queryForObject("SELECT MIN(id) FROM student", Long.class);
this.maxStudentId = jdbcTemplate.queryForObject("SELECT MAX(id) FROM student", Long.class);
}
if (counter.getAndIncrement() >= totalCount) {
return null;
}
long randomFeedId = random.nextLong(minFeedId, maxFeedId + 1);
long randomStudentId = random.nextLong(minStudentId, maxStudentId + 1);
return BookmarkJobDTO.builder()
.feedId(randomFeedId)
.studentId(randomStudentId)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.team.buddyya.job.feed.bookmark;

import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class BookmarkJobDTO {
private Long feedId;
private Long studentId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.team.buddyya.job.feed.comment;

import static com.team.buddyya.job.SeedDataJobConfig.COMMENT_COUNT;

import javax.sql.DataSource;
import lombok.RequiredArgsConstructor;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.batch.item.database.builder.JdbcBatchItemWriterBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;

@Configuration
@RequiredArgsConstructor
public class CommentInsertJobConfig {

private final JobRepository jobRepository;
private final PlatformTransactionManager platformTransactionManager;
private final DataSource dataSource;
private static final int CHUNK_SIZE = 1000;

@Bean
public Step commentInsertStep(ItemReader<CommentJobDTO> commentItemReader,
JdbcBatchItemWriter<CommentJobDTO> commentItemWriter) {
return new StepBuilder("commentInsertStep", jobRepository)
.<CommentJobDTO, CommentJobDTO>chunk(CHUNK_SIZE, platformTransactionManager)
.reader(commentItemReader)
.writer(commentItemWriter)
.build();
}

@Bean
public ItemReader<CommentJobDTO> commentItemReader() {
return new CommentItemReader(new JdbcTemplate(dataSource), COMMENT_COUNT);
}

@Bean
public JdbcBatchItemWriter<CommentJobDTO> commentItemWriter() {
String sql = "INSERT INTO comment (student_id, feed_id, parent_id, content, like_count, deleted, created_date, updated_date) VALUES (:studentId, :feedId, :parentId, :content, 0, false, NOW(), NOW())";
return new JdbcBatchItemWriterBuilder<CommentJobDTO>()
.dataSource(dataSource)
.sql(sql)
.itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
.build();
}
}
Loading