diff --git a/backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/configs/CopyTradingService.kt b/backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/configs/CopyTradingService.kt index e66e434..e238a3a 100644 --- a/backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/configs/CopyTradingService.kt +++ b/backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/configs/CopyTradingService.kt @@ -14,6 +14,8 @@ import com.wrbug.polymarketbot.util.IllegalBigDecimal import com.wrbug.polymarketbot.util.JsonUtils import com.wrbug.polymarketbot.util.toSafeBigDecimal import org.slf4j.LoggerFactory +import org.springframework.context.ApplicationContext +import org.springframework.context.ApplicationContextAware import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import java.math.BigDecimal @@ -30,10 +32,24 @@ class CopyTradingService( private val monitorService: CopyTradingMonitorService, private val jsonUtils: JsonUtils, private val gson: Gson -) { - +) : ApplicationContextAware { + private val logger = LoggerFactory.getLogger(CopyTradingService::class.java) + private var applicationContext: ApplicationContext? = null + + override fun setApplicationContext(applicationContext: ApplicationContext) { + this.applicationContext = applicationContext + } + + /** + * 获取代理对象,用于解决 @Transactional 自调用问题 + */ + private fun getSelf(): CopyTradingService { + return applicationContext?.getBean(CopyTradingService::class.java) + ?: throw IllegalStateException("ApplicationContext not initialized") + } + /** * 创建跟单配置 * 支持两种方式: @@ -331,7 +347,7 @@ class CopyTradingService( */ @Transactional fun updateCopyTradingStatus(request: CopyTradingUpdateStatusRequest): Result { - return updateCopyTrading( + return getSelf().updateCopyTrading( CopyTradingUpdateRequest( copyTradingId = request.copyTradingId, enabled = request.enabled diff --git a/backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/statistics/CopyOrderTrackingService.kt b/backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/statistics/CopyOrderTrackingService.kt index 5f300bc..49ee84f 100644 --- a/backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/statistics/CopyOrderTrackingService.kt +++ b/backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/statistics/CopyOrderTrackingService.kt @@ -23,6 +23,8 @@ import com.wrbug.polymarketbot.service.common.MarketService import com.wrbug.polymarketbot.service.common.PolymarketClobService import com.wrbug.polymarketbot.service.system.TelegramNotificationService import com.wrbug.polymarketbot.util.CryptoUtils +import org.springframework.context.ApplicationContext +import org.springframework.context.ApplicationContextAware import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import java.math.BigDecimal @@ -51,12 +53,26 @@ open class CopyOrderTrackingService( private val cryptoUtils: CryptoUtils, private val marketService: MarketService, // 市场信息服务 private val telegramNotificationService: TelegramNotificationService? = null // 可选,避免循环依赖 -) { +) : ApplicationContextAware { private val logger = LoggerFactory.getLogger(CopyOrderTrackingService::class.java) // 协程作用域(用于异步发送通知) private val notificationScope = CoroutineScope(Dispatchers.IO + SupervisorJob()) + + private var applicationContext: ApplicationContext? = null + + override fun setApplicationContext(applicationContext: ApplicationContext) { + this.applicationContext = applicationContext + } + + /** + * 获取代理对象,用于解决 @Transactional 自调用问题 + */ + private fun getSelf(): CopyOrderTrackingService { + return applicationContext?.getBean(CopyOrderTrackingService::class.java) + ?: throw IllegalStateException("ApplicationContext not initialized") + } // 使用 Mutex 保证线程安全(按交易ID锁定) private val tradeMutexMap = ConcurrentHashMap() @@ -138,10 +154,11 @@ open class CopyOrderTrackingService( return@withLock Result.success(Unit) } - // 2. 处理交易逻辑 + // 2. 处理交易逻辑(通过代理对象调用,确保 @Transactional 生效) + val self = getSelf() val result = when (trade.side.uppercase()) { - "BUY" -> processBuyTrade(leaderId, trade, source) - "SELL" -> processSellTrade(leaderId, trade) + "BUY" -> self.processBuyTrade(leaderId, trade, source) + "SELL" -> self.processSellTrade(leaderId, trade) else -> { logger.warn("未知的交易方向: ${trade.side}") Result.failure(IllegalArgumentException("未知的交易方向: ${trade.side}"))