Skip to content

Commit d3aff47

Browse files
committed
update: post improve, cursor and batch insert NO JPA - 1m4s192ms
1 parent dabbb93 commit d3aff47

File tree

6 files changed

+120
-60
lines changed

6 files changed

+120
-60
lines changed

src/main/kotlin/gogo/gogobetting/infra/batch/config/BettingBatchJobConfig.kt

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
package gogo.gogobetting.infra.batch.config
22

3-
import gogo.gogobetting.domain.betting.result.persistence.BettingResult
4-
import gogo.gogobetting.domain.betting.root.persistence.Betting
5-
import gogo.gogobetting.infra.batch.listener.BatchExecutionListener
6-
import gogo.gogobetting.infra.batch.service.BettingProcessor
3+
import gogo.gogobetting.infra.batch.service.BettingResultWriter
74
import gogo.gogobetting.infra.batch.service.BettingReader
8-
import gogo.gogobetting.infra.batch.service.BettingWriter
5+
import gogo.gogobetting.infra.batch.dto.BettingRow
6+
import gogo.gogobetting.infra.batch.listener.BatchExecutionListener
97
import org.springframework.batch.core.job.builder.JobBuilder
108
import org.springframework.batch.core.Job
119
import org.springframework.batch.core.Step
@@ -15,14 +13,15 @@ import org.springframework.batch.core.step.builder.StepBuilder
1513
import org.springframework.context.annotation.Bean
1614
import org.springframework.context.annotation.Configuration
1715
import org.springframework.transaction.PlatformTransactionManager
16+
import javax.sql.DataSource
1817

1918
@Configuration
2019
@EnableBatchProcessing
2120
class BettingBatchJobConfig(
22-
private val bettingProcessor: BettingProcessor,
23-
private val bettingWriter: BettingWriter,
21+
private val bettingResultWriter: BettingResultWriter,
2422
private val batchExecutionListener: BatchExecutionListener,
2523
private val bettingReader: BettingReader,
24+
private val dateSource: DataSource,
2625
) {
2726

2827
@Bean
@@ -42,11 +41,10 @@ class BettingBatchJobConfig(
4241
transactionManager: PlatformTransactionManager,
4342
): Step {
4443
return StepBuilder("bettingStep", jobRepository)
45-
.chunk<Betting, BettingResult>(1000)
44+
.chunk<BettingRow, BettingRow>(1000)
4645
.transactionManager(transactionManager)
47-
.reader(bettingReader.bettingReader(null))
48-
.processor(bettingProcessor)
49-
.writer(bettingWriter)
46+
.reader(bettingReader.jdbcBettingReader(null, dateSource))
47+
.writer(bettingResultWriter)
5048
.build()
5149
}
5250
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package gogo.gogobetting.infra.batch.dto
2+
3+
data class BettingResultJdbcDto(
4+
val bettingId: Long,
5+
val earnedPoint: Long,
6+
val isPredicted: Boolean,
7+
)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package gogo.gogobetting.infra.batch.dto
2+
3+
data class BettingRow(
4+
val id: Long,
5+
val matchId: Long,
6+
val studentId: Long,
7+
val point: Long,
8+
val predictedWinTeamId: Long,
9+
)
Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,42 @@
11
package gogo.gogobetting.infra.batch.service
22

3-
import gogo.gogobetting.domain.betting.root.persistence.Betting
4-
import gogo.gogobetting.domain.betting.root.persistence.type.BettingStatus
5-
import jakarta.persistence.EntityManagerFactory
3+
import gogo.gogobetting.infra.batch.dto.BettingRow
64
import org.springframework.batch.core.configuration.annotation.StepScope
7-
import org.springframework.batch.item.database.JpaPagingItemReader
5+
import org.springframework.batch.item.database.JdbcCursorItemReader
86
import org.springframework.beans.factory.annotation.Value
97
import org.springframework.context.annotation.Bean
108
import org.springframework.context.annotation.Configuration
9+
import javax.sql.DataSource
1110

1211
@Configuration("springBatchBettingReader")
13-
class BettingReader(
14-
private val entityManagerFactory: EntityManagerFactory
15-
) {
12+
class BettingReader {
1613

17-
@Bean("batchBettingReader")
14+
@Bean
1815
@StepScope
19-
fun bettingReader(
20-
@Value("#{jobParameters['matchId']}") matchId: Long?
21-
): JpaPagingItemReader<Betting> {
16+
fun jdbcBettingReader(
17+
@Value("#{jobParameters['matchId']}") matchId: Long?,
18+
dataSource: DataSource
19+
): JdbcCursorItemReader<BettingRow> {
2220
val validMatchId = matchId ?: throw IllegalArgumentException("matchId is required")
23-
return JpaPagingItemReader<Betting>().apply {
24-
setEntityManagerFactory(entityManagerFactory)
25-
setQueryString("SELECT b FROM Betting b WHERE b.matchId = :matchId AND b.status = :status ORDER BY b.id")
26-
setParameterValues(mapOf("matchId" to validMatchId, "status" to BettingStatus.CONFIRMED))
27-
pageSize = 1000
21+
22+
return JdbcCursorItemReader<BettingRow>().apply {
23+
setDataSource(dataSource)
24+
setSql("""
25+
SELECT id, match_id, student_id, point, predicted_win_team_id
26+
FROM tbl_betting
27+
WHERE match_id = ? AND status = 'CONFIRMED'
28+
ORDER BY id
29+
""".trimIndent())
30+
setPreparedStatementSetter { ps -> ps.setLong(1, validMatchId) }
31+
setRowMapper { rs, _ ->
32+
BettingRow(
33+
id = rs.getLong("id"),
34+
matchId = rs.getLong("match_id"),
35+
studentId = rs.getLong("student_id"),
36+
point = rs.getLong("point"),
37+
predictedWinTeamId = rs.getLong("predicted_win_team_id")
38+
)
39+
}
2840
}
2941
}
30-
3142
}

src/main/kotlin/gogo/gogobetting/infra/batch/service/BettingWriter.kt renamed to src/main/kotlin/gogo/gogobetting/infra/batch/service/BettingResultWriter.kt

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,56 +5,62 @@ import gogo.gogobetting.domain.batch.detail.persistence.BatchDetailRepository
55
import gogo.gogobetting.domain.batch.root.event.MatchBatchEvent
66
import gogo.gogobetting.domain.batch.root.event.StudentBettingDto
77
import gogo.gogobetting.domain.batch.root.persistence.BatchRepository
8-
import gogo.gogobetting.domain.betting.result.persistence.BettingResult
9-
import gogo.gogobetting.domain.betting.result.persistence.BettingResultRepository
108
import gogo.gogobetting.domain.betting.root.persistence.BettingRepository
119
import gogo.gogobetting.global.kafka.publisher.BatchPublisher
10+
import gogo.gogobetting.infra.batch.dto.BettingResultJdbcDto
11+
import gogo.gogobetting.infra.batch.dto.BettingRow
1212
import org.slf4j.LoggerFactory
1313
import org.springframework.batch.core.StepExecution
1414
import org.springframework.batch.core.annotation.AfterStep
1515
import org.springframework.batch.core.annotation.BeforeStep
1616
import org.springframework.batch.core.configuration.annotation.StepScope
1717
import org.springframework.batch.item.Chunk
1818
import org.springframework.batch.item.ItemWriter
19+
import org.springframework.batch.item.database.JdbcBatchItemWriter
1920
import org.springframework.beans.factory.annotation.Value
20-
import org.springframework.context.ApplicationEventPublisher
2121
import org.springframework.data.repository.findByIdOrNull
2222
import org.springframework.stereotype.Component
23-
import java.util.*
23+
import java.util.UUID
24+
import kotlin.math.ceil
2425

2526
@Component("springBatchBettingWriter")
2627
@StepScope
27-
class BettingWriter(
28-
private val bettingResultRepository: BettingResultRepository,
28+
class BettingResultWriter(
29+
private val jdbcWriter: JdbcBatchItemWriter<BettingResultJdbcDto>,
2930
private val batchDetailRepository: BatchDetailRepository,
3031
private val batchRepository: BatchRepository,
3132
private val bettingRepository: BettingRepository,
32-
private val applicationEventPublisher: ApplicationEventPublisher,
3333
private val batchPublisher: BatchPublisher,
34-
) : ItemWriter<BettingResult> {
35-
36-
@Value("#{jobParameters['matchId']}")
37-
private val matchId: Long = 0
38-
39-
@Value("#{jobParameters['winTeamId']}")
40-
private val winTeamId: Long = 0
41-
42-
@Value("#{jobParameters['aTeamScore']}")
43-
private val aTeamScore: Int = 0
44-
45-
@Value("#{jobParameters['bTeamScore']}")
46-
private val bTeamScore: Int = 0
34+
@Value("#{jobParameters['winTeamId']}") private val winTeamId: Long,
35+
@Value("#{jobParameters['bettingOdds']}") private val bettingOdds: Double,
36+
@Value("#{jobParameters['matchId']}") private val matchId: Long,
37+
@Value("#{jobParameters['aTeamScore']}") private val aTeamScore: Int,
38+
@Value("#{jobParameters['bTeamScore']}") private val bTeamScore: Int
39+
) : ItemWriter<BettingRow> {
4740

4841
private var batchId: Long = 0
49-
private val accumulatedItems = mutableListOf<BettingResult>()
50-
51-
private val log = LoggerFactory.getLogger(this::class.java.simpleName)
42+
private val accumulated = mutableListOf<BettingResultJdbcDto>()
43+
private val log = LoggerFactory.getLogger(this::class.java)
5244

5345
@BeforeStep
5446
fun beforeStep(stepExecution: StepExecution) {
55-
val jobExecution = stepExecution.jobExecution
56-
accumulatedItems.clear()
57-
batchId = jobExecution.executionContext["batchId"]!! as Long
47+
batchId = stepExecution.jobExecution.executionContext["batchId"] as Long
48+
accumulated.clear()
49+
}
50+
51+
override fun write(items: Chunk<out BettingRow>) {
52+
val dtoList = items.map { row ->
53+
val isPredicted = row.predictedWinTeamId == winTeamId
54+
val earnedPoint = if (isPredicted) ceil(row.point * bettingOdds).toLong() + row.point else 0L
55+
BettingResultJdbcDto(
56+
bettingId = row.id,
57+
earnedPoint = earnedPoint,
58+
isPredicted = isPredicted,
59+
)
60+
}
61+
62+
jdbcWriter.write(Chunk(dtoList))
63+
accumulated.addAll(dtoList)
5864
}
5965

6066
@AfterStep
@@ -70,7 +76,7 @@ class BettingWriter(
7076
)
7177
)
7278

73-
// val successList = accumulatedItems.filter { it.isPredicted }
79+
// val successList = accumulated.filter { it.isPredicted }
7480
// .map {
7581
// val studentId = bettingRepository.findByIdOrNull(it.bettingId)!!.studentId
7682
// StudentBettingDto(studentId, it.earnedPoint)
@@ -89,9 +95,4 @@ class BettingWriter(
8995
// log.info("published betting batch application event: {}", event.id)
9096
// batchPublisher.publishBettingBatchEvent(event)
9197
}
92-
93-
override fun write(items: Chunk<out BettingResult>) {
94-
bettingResultRepository.saveAll(items)
95-
accumulatedItems.addAll(items)
96-
}
9798
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package gogo.gogobetting.infra.batch.service
2+
3+
import gogo.gogobetting.infra.batch.dto.BettingResultJdbcDto
4+
import org.springframework.batch.core.configuration.annotation.StepScope
5+
import org.springframework.batch.item.database.JdbcBatchItemWriter
6+
import org.springframework.context.annotation.Bean
7+
import org.springframework.context.annotation.Configuration
8+
import javax.sql.DataSource
9+
10+
@Configuration
11+
class BettingWriterConfig {
12+
13+
@Bean
14+
@StepScope
15+
fun bettingResultJdbcWriter(
16+
dataSource: DataSource
17+
): JdbcBatchItemWriter<BettingResultJdbcDto> {
18+
return JdbcBatchItemWriter<BettingResultJdbcDto>().apply {
19+
setDataSource(dataSource)
20+
setSql("""
21+
INSERT INTO tbl_betting_result (betting_id, earned_point, is_cancelled, is_predicted)
22+
VALUES (?, ?, ?, ?)
23+
""".trimIndent())
24+
setItemPreparedStatementSetter { item, ps ->
25+
ps.setLong(1, item.bettingId)
26+
ps.setLong(2, item.earnedPoint)
27+
ps.setBoolean(3, false)
28+
ps.setBoolean(4, item.isPredicted)
29+
}
30+
afterPropertiesSet()
31+
}
32+
}
33+
34+
}

0 commit comments

Comments
 (0)