Prechádzať zdrojové kódy

Merge remote-tracking branch 'origin/master'

zhujing 3 týždňov pred
rodič
commit
652b633c99
36 zmenil súbory, kde vykonal 244 pridanie a 73 odobranie
  1. 4 4
      java/storlead-api/src/main/resources/application-dev.yml
  2. 1 0
      java/storlead-api/src/main/resources/application.yml
  3. 36 11
      java/storlead-framework/storlead-mybatis/src/main/java/com/storlead/framework/mybatis/datasource/ModuleDefaultDataSourceAspect.java
  4. 0 4
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/controller/CustomerAiAnalysisController.java
  5. 0 6
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/controller/MarketingCampaignSopDetailController.java
  6. 0 4
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/controller/MarketingController.java
  7. 6 0
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/entity/CustomerBaseEntity.java
  8. 3 2
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/CustomerAnalysisResultEntityMapper.java
  9. 3 2
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/CustomerBaseEntityMapper.java
  10. 3 2
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/CustomerCompanyEntityMapper.java
  11. 3 2
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/CustomerEntityMapper.java
  12. 3 2
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/LiaisonEntityMapper.java
  13. 3 2
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/MarketingCampaignEntityMapper.java
  14. 2 2
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/MarketingCampaignSopDetailMapper.java
  15. 2 2
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/SopDetailMapper.java
  16. 2 2
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/SopMapper.java
  17. 3 2
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/TagEntityMapper.java
  18. 3 2
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/TemplateEntityMapper.java
  19. 3 2
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/TemplateTagEntityMapper.java
  20. 12 0
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/support/TradeBaseMapper.java
  21. 4 0
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/CustomerAiAnalysisServiceImpl.java
  22. 4 0
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/CustomerAnalysisDispatchServiceImpl.java
  23. 6 2
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/CustomerAnalysisResultEntityServiceImpl.java
  24. 6 2
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/CustomerBaseEntityServiceImpl.java
  25. 4 0
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/CustomerCompanyEntityServiceImpl.java
  26. 4 0
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/CustomerEntityServiceImpl.java
  27. 4 0
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/LiaisonEntityServiceImpl.java
  28. 29 12
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/MarketingCampaignEntityServiceImpl.java
  29. 5 2
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/MarketingCampaignSopDetailServiceImpl.java
  30. 7 2
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/SopDetailServiceImpl.java
  31. 4 0
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/SopServiceImpl.java
  32. 4 0
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/TagEntityServiceImpl.java
  33. 4 0
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/TempalteEntityServiceImpl.java
  34. 4 0
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/TempalteTagEntityServiceImpl.java
  35. 4 0
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/TradeMessageAssembleServiceImpl.java
  36. 59 0
      java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/support/TradeDataSourceServiceImpl.java

+ 4 - 4
java/storlead-api/src/main/resources/application-dev.yml

@@ -95,10 +95,10 @@ spring:
           password: rCgRgLjH99Xvg5BN
           driver-class-name: com.mysql.jdbc.Driver
         trade:
-            url: jdbc:mysql://mysql.test.storlead.com:39091/sp_trade_platform_test?useSSL=false&useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true
-            username: root
-            password: rCgRgLjH99Xvg5BN
-            driver-class-name: com.mysql.jdbc.Driver
+          url: jdbc:mysql://mysql.test.storlead.com:39091/sp_trade_platform_test?useSSL=false&useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true
+          username: root
+          password: rCgRgLjH99Xvg5BN
+          driver-class-name: com.mysql.jdbc.Driver
         sales:
           driver-class-name: com.mysql.jdbc.Driver
           url: jdbc:mysql://mysql.test.storlead.com:39091/sp_sales_test?useSSL=false&useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true

+ 1 - 0
java/storlead-api/src/main/resources/application.yml

@@ -91,6 +91,7 @@ storlead:
       - packages:
           - com.storlead.trade.service
           - com.storlead.trade.mapper
+          - com.storlead.trade.task
         datasource: trade
       - packages:
           - com.storlead.sales.service

+ 36 - 11
java/storlead-framework/storlead-mybatis/src/main/java/com/storlead/framework/mybatis/datasource/ModuleDefaultDataSourceAspect.java

@@ -17,7 +17,10 @@ import org.springframework.util.StringUtils;
 import java.lang.reflect.Method;
 
 /**
- * 子模块默认数据源:按配置包前缀 push 数据源;若目标已标注 {@link DS} 则跳过,由官方 {@code @DS} 切面处理。
+ * 子模块默认数据源:按配置包前缀 push 数据源。
+ * <p>
+ * 若目标已标注 {@link DS},由本切面直接 push 其 value(不再仅“跳过”依赖官方切面,
+ * 避免官方 @DS 未织入时落到 primary/master)。
  */
 @Slf4j
 @Aspect
@@ -37,17 +40,17 @@ public class ModuleDefaultDataSourceAspect {
         if (!properties.isModuleDefaultEnabled()) {
             return joinPoint.proceed();
         }
-        if (hasDsAnnotation(joinPoint)) {
-            return joinPoint.proceed();
+        String datasource = resolveExplicitDs(joinPoint);
+        if (!StringUtils.hasText(datasource)) {
+            datasource = resolveDatasource(joinPoint);
         }
-        String datasource = resolveDatasource(joinPoint);
         if (!StringUtils.hasText(datasource)) {
             return joinPoint.proceed();
         }
         DynamicDataSourceContextHolder.push(datasource);
         try {
             if (log.isDebugEnabled()) {
-                log.debug("module default datasource [{}] -> {}", datasource, joinPoint.getSignature().toShortString());
+                log.debug("module datasource [{}] -> {}", datasource, joinPoint.getSignature().toShortString());
             }
             return joinPoint.proceed();
         } finally {
@@ -55,17 +58,39 @@ public class ModuleDefaultDataSourceAspect {
         }
     }
 
-    private boolean hasDsAnnotation(ProceedingJoinPoint joinPoint) {
+    /**
+     * 方法 / 声明类 / 实际目标类上的 @DS 优先
+     */
+    private String resolveExplicitDs(ProceedingJoinPoint joinPoint) {
         MethodSignature signature = (MethodSignature) joinPoint.getSignature();
         Method method = signature.getMethod();
+        DS ds = AnnotatedElementUtils.findMergedAnnotation(method, DS.class);
+        if (ds != null && StringUtils.hasText(ds.value())) {
+            return ds.value();
+        }
         Class<?> declaringType = signature.getDeclaringType();
-        if (AnnotatedElementUtils.hasAnnotation(method, DS.class)) {
-            return true;
+        if (declaringType != null) {
+            ds = AnnotatedElementUtils.findMergedAnnotation(declaringType, DS.class);
+            if (ds != null && StringUtils.hasText(ds.value())) {
+                return ds.value();
+            }
         }
-        if (declaringType != null && AnnotatedElementUtils.hasAnnotation(declaringType, DS.class)) {
-            return true;
+        Class<?> targetClass = joinPoint.getTarget() != null ? joinPoint.getTarget().getClass() : null;
+        if (targetClass != null) {
+            ds = AnnotatedElementUtils.findMergedAnnotation(targetClass, DS.class);
+            if (ds != null && StringUtils.hasText(ds.value())) {
+                return ds.value();
+            }
+            // CGLIB 代理取父类
+            Class<?> superclass = targetClass.getSuperclass();
+            if (superclass != null && superclass != Object.class) {
+                ds = AnnotatedElementUtils.findMergedAnnotation(superclass, DS.class);
+                if (ds != null && StringUtils.hasText(ds.value())) {
+                    return ds.value();
+                }
+            }
         }
-        return AnnotatedElementUtils.hasAnnotation(joinPoint.getTarget().getClass(), DS.class);
+        return null;
     }
 
     /**

+ 0 - 4
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/controller/CustomerAiAnalysisController.java

@@ -14,7 +14,6 @@ import com.storlead.trade.service.CustomerAnalysisResultEntityService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.BeanUtils;
-import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.ObjectUtils;
 import org.springframework.web.bind.annotation.*;
@@ -83,7 +82,6 @@ public class CustomerAiAnalysisController {
 
     @PostMapping(value = "/add")
     @ApiOperation(value = "客户AI分析结果添加", notes = "客户AI分析结果添加")
-    @Transactional(rollbackFor = Throwable.class)
     public Result<?> add(@RequestBody CustomerAnalysisResultDTO dto) {
         CustomerAnalysisResultEntity entity = new CustomerAnalysisResultEntity();
         BeanUtils.copyProperties(dto, entity);
@@ -96,7 +94,6 @@ public class CustomerAiAnalysisController {
 
     @PostMapping(value = "/edit")
     @ApiOperation(value = "客户AI分析结果修改", notes = "客户AI分析结果修改")
-    @Transactional(rollbackFor = Throwable.class)
     public Result<?> edit(@RequestBody CustomerAnalysisResultDTO dto) {
         if (ObjectUtils.isEmpty(dto.getId())) {
             return Result.error("id不能为空");
@@ -112,7 +109,6 @@ public class CustomerAiAnalysisController {
 
     @PostMapping(value = "/delete")
     @ApiOperation(value = "客户AI分析结果删除", notes = "客户AI分析结果删除")
-    @Transactional(rollbackFor = Throwable.class)
     public Result<?> delete(@RequestBody CustomerAnalysisResultDTO dto) {
         boolean isOk = false;
         Long id = dto.getId();

+ 0 - 6
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/controller/MarketingCampaignSopDetailController.java

@@ -16,7 +16,6 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.BeanUtils;
 import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.ObjectUtils;
 import org.springframework.web.bind.annotation.*;
@@ -105,7 +104,6 @@ public class MarketingCampaignSopDetailController {
      */
     @PostMapping("/add")
     @ApiOperation(value = "新增营销活动SOP明细", notes = "支持单条新增")
-    @Transactional(rollbackFor = Throwable.class)
     public Result<?> add(@RequestBody MarketingCampaignSopDetailDTO dto) {
         if (ObjectUtils.isEmpty(dto.getMarketingCampaignId())) {
             return Result.error("营销活动id不能为空");
@@ -125,7 +123,6 @@ public class MarketingCampaignSopDetailController {
 
     @PostMapping("/add-confirm")
     @ApiOperation(value = "确认创建/编辑营销活动", notes = "根据智能调度类型生成待发送邮件")
-    @Transactional(rollbackFor = Throwable.class)
     public Result<?> addConfirm(@RequestBody MarketingCampaignSopDetailDTO dto) {
         if (ObjectUtils.isEmpty(dto.getMarketingCampaignId())) {
             return Result.error("营销活动id不能为空");
@@ -348,7 +345,6 @@ public class MarketingCampaignSopDetailController {
      */
     @PostMapping("/add/batch")
     @ApiOperation(value = "批量新增营销活动SOP明细", notes = "支持批量新增")
-    @Transactional(rollbackFor = Throwable.class)
     public Result<?> addBatch(@RequestBody List<MarketingCampaignSopDetailDTO> dtoList) {
         if (CollectionUtils.isEmpty(dtoList)) {
             return Result.error("数据不能为空");
@@ -371,7 +367,6 @@ public class MarketingCampaignSopDetailController {
      */
     @PostMapping("/edit")
     @ApiOperation(value = "编辑营销活动SOP明细", notes = "编辑营销活动SOP明细")
-    @Transactional(rollbackFor = Throwable.class)
     public Result<?> edit(@RequestBody MarketingCampaignSopDetailDTO dto) {
         if (ObjectUtils.isEmpty(dto.getId())) {
             return Result.error("id不能为空");
@@ -390,7 +385,6 @@ public class MarketingCampaignSopDetailController {
      */
     @PostMapping("/delete")
     @ApiOperation(value = "删除营销活动SOP明细", notes = "支持单条id或批量idList删除")
-    @Transactional(rollbackFor = Throwable.class)
     public Result<?> delete(@RequestBody MarketingCampaignSopDetailDTO dto) {
         boolean isOk = false;
         Long id = dto.getId();

+ 0 - 4
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/controller/MarketingController.java

@@ -7,7 +7,6 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.ObjectUtils;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -34,7 +33,6 @@ public class MarketingController {
 
     @PostMapping(value = "/add")
     @ApiOperation(value = "营销: 营销活动添加", notes = "营销: 营销活动添加简报")
-    @Transactional(rollbackFor = Throwable.class)
     public Result<?> add(@RequestBody MarketingCampaignDTO marketingCampaignDTO) {
         Result<Object> result = marketingService.addMarket(marketingCampaignDTO);
         return Result.result(result);
@@ -42,7 +40,6 @@ public class MarketingController {
 
     @PostMapping(value = "/edit")
     @ApiOperation(value = "营销: 营销活动修改", notes = "营销: 营销活动修改")
-    @Transactional(rollbackFor = Throwable.class)
     public Result<?> edit(@RequestBody MarketingCampaignDTO marketingCampaignDTO) {
         Result<Object> result = marketingService.editMarket(marketingCampaignDTO);
         return Result.result(result);
@@ -50,7 +47,6 @@ public class MarketingController {
 
     @PostMapping(value = "/delete")
     @ApiOperation(value = "营销: 营销活动修改", notes = "营销: 营销活动修改")
-    @Transactional(rollbackFor = Throwable.class)
     public Result<?> delete(@RequestBody MarketingCampaignDTO marketingCampaignDTO) {
         boolean isOk = false;
         Long id = marketingCampaignDTO.getId();

+ 6 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/entity/CustomerBaseEntity.java

@@ -1,6 +1,8 @@
 package com.storlead.trade.entity;
 
+import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.storlead.framework.mybatis.entity.SysBaseField;
 import io.swagger.annotations.ApiModelProperty;
@@ -10,6 +12,10 @@ import lombok.Data;
 @TableName("customer_base")
 public class CustomerBaseEntity extends SysBaseField {
 
+    @ApiModelProperty(value = "主键id")
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
     @ApiModelProperty(value = "客户id")
     @TableField("customer_analysis_id")
     private Long customerAnalysisId;

+ 3 - 2
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/CustomerAnalysisResultEntityMapper.java

@@ -1,7 +1,8 @@
 package com.storlead.trade.mapper;
 
+import com.storlead.trade.mapper.support.TradeBaseMapper;
+
 import com.storlead.trade.entity.CustomerAnalysisResultEntity;
-import com.storlead.framework.mybatis.mapper.MyBaseMapper;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
@@ -10,7 +11,7 @@ import java.util.List;
 import java.util.Map;
 
 @Mapper
-public interface CustomerAnalysisResultEntityMapper extends MyBaseMapper<CustomerAnalysisResultEntity> {
+public interface CustomerAnalysisResultEntityMapper extends TradeBaseMapper<CustomerAnalysisResultEntity> {
 
     /**
      * 按客户等级分组统计

+ 3 - 2
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/CustomerBaseEntityMapper.java

@@ -1,16 +1,17 @@
 package com.storlead.trade.mapper;
 
+import com.storlead.trade.mapper.support.TradeBaseMapper;
+
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.storlead.trade.dto.MarketingCampaignCustomerDTO;
 import com.storlead.trade.entity.CustomerBaseEntity;
-import com.storlead.framework.mybatis.mapper.MyBaseMapper;
 import com.storlead.trade.vo.MarketingCampaignCustomerVO;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
 @Mapper
-public interface CustomerBaseEntityMapper extends MyBaseMapper<CustomerBaseEntity> {
+public interface CustomerBaseEntityMapper extends TradeBaseMapper<CustomerBaseEntity> {
 
     /**
      * 查询营销活动关联的客户列表

+ 3 - 2
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/CustomerCompanyEntityMapper.java

@@ -1,9 +1,10 @@
 package com.storlead.trade.mapper;
 
+import com.storlead.trade.mapper.support.TradeBaseMapper;
+
 import com.storlead.trade.entity.CustomerCompanyEntity;
-import com.storlead.framework.mybatis.mapper.MyBaseMapper;
 import org.apache.ibatis.annotations.Mapper;
 
 @Mapper
-public interface CustomerCompanyEntityMapper extends MyBaseMapper<CustomerCompanyEntity> {
+public interface CustomerCompanyEntityMapper extends TradeBaseMapper<CustomerCompanyEntity> {
 }

+ 3 - 2
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/CustomerEntityMapper.java

@@ -1,9 +1,10 @@
 package com.storlead.trade.mapper;
 
+import com.storlead.trade.mapper.support.TradeBaseMapper;
+
 import com.storlead.trade.entity.CustomerEntity;
-import com.storlead.framework.mybatis.mapper.MyBaseMapper;
 import org.apache.ibatis.annotations.Mapper;
 
 @Mapper
-public interface CustomerEntityMapper extends MyBaseMapper<CustomerEntity> {
+public interface CustomerEntityMapper extends TradeBaseMapper<CustomerEntity> {
 }

+ 3 - 2
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/LiaisonEntityMapper.java

@@ -1,9 +1,10 @@
 package com.storlead.trade.mapper;
 
+import com.storlead.trade.mapper.support.TradeBaseMapper;
+
 import com.storlead.trade.entity.LiaisonEntity;
-import com.storlead.framework.mybatis.mapper.MyBaseMapper;
 import org.apache.ibatis.annotations.Mapper;
 
 @Mapper
-public interface LiaisonEntityMapper extends MyBaseMapper<LiaisonEntity> {
+public interface LiaisonEntityMapper extends TradeBaseMapper<LiaisonEntity> {
 }

+ 3 - 2
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/MarketingCampaignEntityMapper.java

@@ -1,9 +1,10 @@
 package com.storlead.trade.mapper;
 
+import com.storlead.trade.mapper.support.TradeBaseMapper;
+
 import com.storlead.trade.entity.MarketingCampaignEntity;
-import com.storlead.framework.mybatis.mapper.MyBaseMapper;
 import org.apache.ibatis.annotations.Mapper;
 
 @Mapper
-public interface MarketingCampaignEntityMapper extends MyBaseMapper<MarketingCampaignEntity> {
+public interface MarketingCampaignEntityMapper extends TradeBaseMapper<MarketingCampaignEntity> {
 }

+ 2 - 2
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/MarketingCampaignSopDetailMapper.java

@@ -1,12 +1,12 @@
 package com.storlead.trade.mapper;
 
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.storlead.trade.entity.MarketingCampaignSopDetailEntity;
+import com.storlead.trade.mapper.support.TradeBaseMapper;
 import org.apache.ibatis.annotations.Mapper;
 
 /**
  * 营销活动SOP明细 Mapper接口
  */
 @Mapper
-public interface MarketingCampaignSopDetailMapper extends BaseMapper<MarketingCampaignSopDetailEntity> {
+public interface MarketingCampaignSopDetailMapper extends TradeBaseMapper<MarketingCampaignSopDetailEntity> {
 }

+ 2 - 2
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/SopDetailMapper.java

@@ -1,12 +1,12 @@
 package com.storlead.trade.mapper;
 
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.storlead.trade.entity.SopDetailEntity;
+import com.storlead.trade.mapper.support.TradeBaseMapper;
 import org.apache.ibatis.annotations.Mapper;
 
 /**
  * SOP明细 Mapper接口
  */
 @Mapper
-public interface SopDetailMapper extends BaseMapper<SopDetailEntity> {
+public interface SopDetailMapper extends TradeBaseMapper<SopDetailEntity> {
 }

+ 2 - 2
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/SopMapper.java

@@ -1,12 +1,12 @@
 package com.storlead.trade.mapper;
 
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.storlead.trade.entity.SopEntity;
+import com.storlead.trade.mapper.support.TradeBaseMapper;
 import org.apache.ibatis.annotations.Mapper;
 
 /**
  * SOP Mapper接口
  */
 @Mapper
-public interface SopMapper extends BaseMapper<SopEntity> {
+public interface SopMapper extends TradeBaseMapper<SopEntity> {
 }

+ 3 - 2
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/TagEntityMapper.java

@@ -1,9 +1,10 @@
 package com.storlead.trade.mapper;
 
+import com.storlead.trade.mapper.support.TradeBaseMapper;
+
 import com.storlead.trade.entity.TagEntity;
-import com.storlead.framework.mybatis.mapper.MyBaseMapper;
 import org.apache.ibatis.annotations.Mapper;
 
 @Mapper
-public interface TagEntityMapper extends MyBaseMapper<TagEntity> {
+public interface TagEntityMapper extends TradeBaseMapper<TagEntity> {
 }

+ 3 - 2
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/TemplateEntityMapper.java

@@ -1,9 +1,10 @@
 package com.storlead.trade.mapper;
 
+import com.storlead.trade.mapper.support.TradeBaseMapper;
+
 import com.storlead.trade.entity.TemplateEntity;
-import com.storlead.framework.mybatis.mapper.MyBaseMapper;
 import org.apache.ibatis.annotations.Mapper;
 
 @Mapper
-public interface TemplateEntityMapper extends MyBaseMapper<TemplateEntity> {
+public interface TemplateEntityMapper extends TradeBaseMapper<TemplateEntity> {
 }

+ 3 - 2
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/TemplateTagEntityMapper.java

@@ -1,9 +1,10 @@
 package com.storlead.trade.mapper;
 
+import com.storlead.trade.mapper.support.TradeBaseMapper;
+
 import com.storlead.trade.entity.TemplateTagEntity;
-import com.storlead.framework.mybatis.mapper.MyBaseMapper;
 import org.apache.ibatis.annotations.Mapper;
 
 @Mapper
-public interface TemplateTagEntityMapper extends MyBaseMapper<TemplateTagEntity> {
+public interface TemplateTagEntityMapper extends TradeBaseMapper<TemplateTagEntity> {
 }

+ 12 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/mapper/support/TradeBaseMapper.java

@@ -0,0 +1,12 @@
+package com.storlead.trade.mapper.support;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.storlead.framework.common.constant.DSConstants;
+import com.storlead.framework.mybatis.mapper.MyBaseMapper;
+
+/**
+ * trade 库 Mapper 基类,统一路由到 spring.datasource.dynamic.datasource.trade。
+ */
+@DS(DSConstants.DATASOURCE_TRADE)
+public interface TradeBaseMapper<T> extends MyBaseMapper<T> {
+}

+ 4 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/CustomerAiAnalysisServiceImpl.java

@@ -1,5 +1,8 @@
 package com.storlead.trade.service.impl;
 
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.storlead.framework.common.constant.DSConstants;
+
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.storlead.trade.entity.CustomerAnalysisResultEntity;
 import com.storlead.trade.entity.CustomerCompanyEntity;
@@ -14,6 +17,7 @@ import javax.annotation.Resource;
 import java.util.*;
 
 @Service
+@DS(DSConstants.DATASOURCE_TRADE)
 public class CustomerAiAnalysisServiceImpl implements CustomerAiAnalysisService {
 
     private static final String AI_ANALYSIS_URL = "http://127.0.0.1:18080/mock/ai/customer/analyze";

+ 4 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/CustomerAnalysisDispatchServiceImpl.java

@@ -1,5 +1,8 @@
 package com.storlead.trade.service.impl;
 
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.storlead.framework.common.constant.DSConstants;
+
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.storlead.framework.common.constant.CommonConstant;
 import com.storlead.trade.constant.CustomerAnalysisConstants;
@@ -25,6 +28,7 @@ import java.util.stream.Collectors;
 
 @Slf4j
 @Service
+@DS(DSConstants.DATASOURCE_TRADE)
 public class CustomerAnalysisDispatchServiceImpl implements CustomerAnalysisDispatchService {
 
     private static final DateTimeFormatter BATCH_NO_FMT = DateTimeFormatter.BASIC_ISO_DATE;

+ 6 - 2
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/CustomerAnalysisResultEntityServiceImpl.java

@@ -1,17 +1,21 @@
 package com.storlead.trade.service.impl;
 
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.storlead.framework.common.constant.DSConstants;
+
 import com.storlead.trade.entity.CustomerAnalysisResultEntity;
 import com.storlead.trade.mapper.CustomerAnalysisResultEntityMapper;
 import com.storlead.trade.service.CustomerAnalysisResultEntityService;
-import com.storlead.framework.mybatis.service.impl.MyBaseServiceImpl;
+import com.storlead.trade.service.impl.support.TradeDataSourceServiceImpl;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
 import java.util.Map;
 
 @Service
+@DS(DSConstants.DATASOURCE_TRADE)
 public class CustomerAnalysisResultEntityServiceImpl
-        extends MyBaseServiceImpl<CustomerAnalysisResultEntityMapper, CustomerAnalysisResultEntity>
+        extends TradeDataSourceServiceImpl<CustomerAnalysisResultEntityMapper, CustomerAnalysisResultEntity>
         implements CustomerAnalysisResultEntityService {
 
     @Override

+ 6 - 2
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/CustomerBaseEntityServiceImpl.java

@@ -1,5 +1,8 @@
 package com.storlead.trade.service.impl;
 
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.storlead.framework.common.constant.DSConstants;
+
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.storlead.trade.dto.MarketingCampaignCustomerDTO;
@@ -7,14 +10,15 @@ import com.storlead.trade.entity.CustomerBaseEntity;
 import com.storlead.trade.mapper.CustomerBaseEntityMapper;
 import com.storlead.trade.service.CustomerBaseEntityService;
 import com.storlead.trade.vo.MarketingCampaignCustomerVO;
-import com.storlead.framework.mybatis.service.impl.MyBaseServiceImpl;
+import com.storlead.trade.service.impl.support.TradeDataSourceServiceImpl;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
 
 @Service
+@DS(DSConstants.DATASOURCE_TRADE)
 public class CustomerBaseEntityServiceImpl
-        extends MyBaseServiceImpl<CustomerBaseEntityMapper, CustomerBaseEntity>
+        extends TradeDataSourceServiceImpl<CustomerBaseEntityMapper, CustomerBaseEntity>
         implements CustomerBaseEntityService {
 
     @Resource

+ 4 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/CustomerCompanyEntityServiceImpl.java

@@ -1,5 +1,8 @@
 package com.storlead.trade.service.impl;
 
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.storlead.framework.common.constant.DSConstants;
+
 import com.storlead.trade.entity.CustomerCompanyEntity;
 import com.storlead.trade.mapper.CustomerCompanyEntityMapper;
 import com.storlead.trade.service.CustomerCompanyEntityService;
@@ -7,6 +10,7 @@ import com.storlead.framework.mybatis.service.impl.MyBaseServiceImpl;
 import org.springframework.stereotype.Service;
 
 @Service
+@DS(DSConstants.DATASOURCE_TRADE)
 public class CustomerCompanyEntityServiceImpl
         extends MyBaseServiceImpl<CustomerCompanyEntityMapper, CustomerCompanyEntity>
         implements CustomerCompanyEntityService {

+ 4 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/CustomerEntityServiceImpl.java

@@ -1,5 +1,8 @@
 package com.storlead.trade.service.impl;
 
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.storlead.framework.common.constant.DSConstants;
+
 import com.storlead.trade.entity.CustomerEntity;
 import com.storlead.trade.mapper.CustomerEntityMapper;
 import com.storlead.trade.service.CustomerEntityService;
@@ -7,5 +10,6 @@ import com.storlead.framework.mybatis.service.impl.MyBaseServiceImpl;
 import org.springframework.stereotype.Service;
 
 @Service
+@DS(DSConstants.DATASOURCE_TRADE)
 public class CustomerEntityServiceImpl extends MyBaseServiceImpl<CustomerEntityMapper, CustomerEntity> implements CustomerEntityService {
 }

+ 4 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/LiaisonEntityServiceImpl.java

@@ -1,5 +1,8 @@
 package com.storlead.trade.service.impl;
 
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.storlead.framework.common.constant.DSConstants;
+
 import com.storlead.trade.entity.LiaisonEntity;
 import com.storlead.trade.mapper.LiaisonEntityMapper;
 import com.storlead.trade.service.LiaisonEntityService;
@@ -7,5 +10,6 @@ import com.storlead.framework.mybatis.service.impl.MyBaseServiceImpl;
 import org.springframework.stereotype.Service;
 
 @Service
+@DS(DSConstants.DATASOURCE_TRADE)
 public class LiaisonEntityServiceImpl extends MyBaseServiceImpl<LiaisonEntityMapper, LiaisonEntity> implements LiaisonEntityService {
 }

+ 29 - 12
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/MarketingCampaignEntityServiceImpl.java

@@ -1,5 +1,8 @@
 package com.storlead.trade.service.impl;
 
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.storlead.framework.common.constant.DSConstants;
+
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -14,9 +17,10 @@ import com.storlead.trade.service.*;
 import com.storlead.trade.vo.MarketingCampaignVO;
 import com.storlead.framework.common.constant.CommonConstant;
 import com.storlead.framework.common.result.Result;
-import com.storlead.framework.mybatis.service.impl.MyBaseServiceImpl;
+import com.storlead.trade.service.impl.support.TradeDataSourceServiceImpl;
 import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.StringUtils;
 
@@ -27,8 +31,9 @@ import java.util.List;
 import java.util.stream.Collectors;
 
 @Service
+@DS(DSConstants.DATASOURCE_TRADE)
 public class MarketingCampaignEntityServiceImpl
-        extends MyBaseServiceImpl<MarketingCampaignEntityMapper, MarketingCampaignEntity>
+        extends TradeDataSourceServiceImpl<MarketingCampaignEntityMapper, MarketingCampaignEntity>
         implements MarketingCampaignEntityService {
 
     @Resource
@@ -82,9 +87,19 @@ public class MarketingCampaignEntityServiceImpl
 
         for (int i = 0; i < marketingCampaignVOList.size(); i++) {
             int finalI = i;
-            List<CustomerBaseEntity> customerBaseList = customerBaseEntityList.stream().filter(customerBaseEntity -> customerBaseEntity.getCustomerAnalysisId().equals(customerAnalysisResultEntityList.get(finalI).getId())).collect(Collectors.toList());
-            List<Long> customerAnalysisResultIdList = customerBaseList.stream().filter(e -> e.getMarketingCampaignId().equals(marketingCampaignVOList.get(finalI).getId())).map(CustomerBaseEntity::getCustomerAnalysisId).collect(Collectors.toList());
-            List<CustomerAnalysisResultEntity> customerAnalysisResultEntityListI = customerAnalysisResultEntityList.stream().filter(customerAnalysisResultEntity -> customerAnalysisResultIdList.contains(customerAnalysisResultEntity.getId())).collect(Collectors.toList());
+            List<CustomerBaseEntity> customerBaseList = customerBaseEntityList.stream()
+                    .filter(customerBaseEntity -> customerBaseEntity.getMarketingCampaignId().equals(marketingCampaignVOList.get(finalI).getId()))
+                    .collect(Collectors.toList());
+            List<Long> customerAnalysisResultIdList = customerBaseList.stream()
+                    .map(CustomerBaseEntity::getCustomerAnalysisId)
+                    .collect(Collectors.toList());
+            if (CollectionUtils.isEmpty(customerAnalysisResultIdList)) {
+                marketingCampaignVOList.get(i).setCustomerList(new ArrayList<>());
+                continue;
+            }
+            List<CustomerAnalysisResultEntity> customerAnalysisResultEntityListI = customerAnalysisResultEntityList.stream()
+                    .filter(customerAnalysisResultEntity -> customerAnalysisResultIdList.contains(customerAnalysisResultEntity.getId()))
+                    .collect(Collectors.toList());
             marketingCampaignVOList.get(i).setCustomerList(customerAnalysisResultEntityListI);
         }
 
@@ -92,6 +107,7 @@ public class MarketingCampaignEntityServiceImpl
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public Result<Object> addMarket(MarketingCampaignDTO marketingCampaignDTO) {
         MarketingCampaignEntity marketingCampaignEntity = new MarketingCampaignEntity();
         BeanUtils.copyProperties(marketingCampaignDTO, marketingCampaignEntity);
@@ -103,16 +119,16 @@ public class MarketingCampaignEntityServiceImpl
         //添加关联客户
         List<Long> customerIdList = marketingCampaignDTO.getCustomerAnalysisIdList();
         if (!CollectionUtils.isEmpty(customerIdList)) {
-            List<CustomerBaseEntity> customerBaseEntityList = new ArrayList<>();
-            for (Long customerId : customerIdList) {
+            // 去重,避免主键冲突
+            List<Long> distinctCustomerIds = customerIdList.stream().distinct().collect(Collectors.toList());
+            for (Long customerId : distinctCustomerIds) {
                 CustomerBaseEntity customerBaseEntity = new CustomerBaseEntity();
                 customerBaseEntity.setCustomerAnalysisId(customerId);
                 customerBaseEntity.setMarketingCampaignId(marketingCampaignEntity.getId());
-                customerBaseEntityList.add(customerBaseEntity);
-            }
-            boolean saveOk =customerBaseEntityService.saveBatch(customerBaseEntityList);
-            if (!saveOk){
-                return Result.error("添加失败");
+                boolean saveOk = customerBaseEntityService.save(customerBaseEntity);
+                if (!saveOk) {
+                    return Result.error("添加关联客户失败");
+                }
             }
         }
         //添加关联sopDetailIdList,并调取ai生成邮件内容
@@ -149,6 +165,7 @@ public class MarketingCampaignEntityServiceImpl
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public Result<Object> editMarket(MarketingCampaignDTO marketingCampaignDTO) {
         MarketingCampaignEntity marketingCampaignEntity = new MarketingCampaignEntity();
         BeanUtils.copyProperties(marketingCampaignDTO, marketingCampaignEntity);

+ 5 - 2
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/MarketingCampaignSopDetailServiceImpl.java

@@ -1,16 +1,19 @@
 package com.storlead.trade.service.impl;
 
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.storlead.framework.common.constant.DSConstants;
 import com.storlead.trade.entity.MarketingCampaignSopDetailEntity;
 import com.storlead.trade.mapper.MarketingCampaignSopDetailMapper;
 import com.storlead.trade.service.MarketingCampaignSopDetailService;
+import com.storlead.trade.service.impl.support.TradeDataSourceServiceImpl;
 import org.springframework.stereotype.Service;
 
 /**
  * 营销活动SOP明细 Service实现
  */
 @Service
+@DS(DSConstants.DATASOURCE_TRADE)
 public class MarketingCampaignSopDetailServiceImpl
-        extends ServiceImpl<MarketingCampaignSopDetailMapper, MarketingCampaignSopDetailEntity>
+        extends TradeDataSourceServiceImpl<MarketingCampaignSopDetailMapper, MarketingCampaignSopDetailEntity>
         implements MarketingCampaignSopDetailService {
 }

+ 7 - 2
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/SopDetailServiceImpl.java

@@ -1,9 +1,11 @@
 package com.storlead.trade.service.impl;
 
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.storlead.framework.common.constant.DSConstants;
 import com.storlead.trade.entity.SopDetailEntity;
 import com.storlead.trade.mapper.SopDetailMapper;
 import com.storlead.trade.service.SopDetailService;
+import com.storlead.trade.service.impl.support.TradeDataSourceServiceImpl;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
@@ -12,5 +14,8 @@ import org.springframework.stereotype.Service;
  */
 @Slf4j
 @Service
-public class SopDetailServiceImpl extends ServiceImpl<SopDetailMapper, SopDetailEntity> implements SopDetailService {
+@DS(DSConstants.DATASOURCE_TRADE)
+public class SopDetailServiceImpl
+        extends TradeDataSourceServiceImpl<SopDetailMapper, SopDetailEntity>
+        implements SopDetailService {
 }

+ 4 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/SopServiceImpl.java

@@ -1,5 +1,8 @@
 package com.storlead.trade.service.impl;
 
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.storlead.framework.common.constant.DSConstants;
+
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -29,6 +32,7 @@ import java.util.stream.Collectors;
  */
 @Slf4j
 @Service
+@DS(DSConstants.DATASOURCE_TRADE)
 public class SopServiceImpl extends ServiceImpl<SopMapper, SopEntity> implements SopService {
 
     @Resource

+ 4 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/TagEntityServiceImpl.java

@@ -1,5 +1,8 @@
 package com.storlead.trade.service.impl;
 
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.storlead.framework.common.constant.DSConstants;
+
 
 import com.storlead.trade.entity.TagEntity;
 import com.storlead.trade.mapper.TagEntityMapper;
@@ -8,6 +11,7 @@ import com.storlead.framework.mybatis.service.impl.MyBaseServiceImpl;
 import org.springframework.stereotype.Service;
 
 @Service
+@DS(DSConstants.DATASOURCE_TRADE)
 public class TagEntityServiceImpl
         extends MyBaseServiceImpl<TagEntityMapper, TagEntity>
         implements TagEntityService {

+ 4 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/TempalteEntityServiceImpl.java

@@ -1,5 +1,8 @@
 package com.storlead.trade.service.impl;
 
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.storlead.framework.common.constant.DSConstants;
+
 
 import com.storlead.trade.entity.TemplateEntity;
 import com.storlead.trade.mapper.TemplateEntityMapper;
@@ -8,6 +11,7 @@ import com.storlead.framework.mybatis.service.impl.MyBaseServiceImpl;
 import org.springframework.stereotype.Service;
 
 @Service
+@DS(DSConstants.DATASOURCE_TRADE)
 public class TempalteEntityServiceImpl
         extends MyBaseServiceImpl<TemplateEntityMapper, TemplateEntity>
         implements TemplateEntityService {

+ 4 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/TempalteTagEntityServiceImpl.java

@@ -1,5 +1,8 @@
 package com.storlead.trade.service.impl;
 
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.storlead.framework.common.constant.DSConstants;
+
 
 import com.storlead.trade.entity.TemplateTagEntity;
 import com.storlead.trade.mapper.TemplateTagEntityMapper;
@@ -8,6 +11,7 @@ import com.storlead.framework.mybatis.service.impl.MyBaseServiceImpl;
 import org.springframework.stereotype.Service;
 
 @Service
+@DS(DSConstants.DATASOURCE_TRADE)
 public class TempalteTagEntityServiceImpl
         extends MyBaseServiceImpl<TemplateTagEntityMapper, TemplateTagEntity>
         implements TemplateTagEntityService {

+ 4 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/TradeMessageAssembleServiceImpl.java

@@ -1,5 +1,8 @@
 package com.storlead.trade.service.impl;
 
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.storlead.framework.common.constant.DSConstants;
+
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.util.StrUtil;
 import com.storlead.message.service.impl.MessageService;
@@ -18,6 +21,7 @@ import java.util.Set;
  */
 @Log4j2
 @Service
+@DS(DSConstants.DATASOURCE_TRADE)
 public class TradeMessageAssembleServiceImpl implements TradeMessageAssembleService {
 
     private static final String[] DEFAULT_CHANNELS = {"site", "wecom", "sms", "mail"};

+ 59 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/support/TradeDataSourceServiceImpl.java

@@ -0,0 +1,59 @@
+package com.storlead.trade.service.impl.support;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
+import com.storlead.framework.common.constant.DSConstants;
+import com.storlead.framework.mybatis.entity.SysBaseField;
+import com.storlead.framework.mybatis.mapper.MyBaseMapper;
+import com.storlead.framework.mybatis.service.impl.MyBaseServiceImpl;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Collection;
+
+/**
+ * trade 库 Service 基类。
+ * <p>
+ * MyBatis-Plus 的 {@code saveBatch}/{@code updateBatchById} 走 SqlSession 批量执行,
+ * 不会经过 Mapper 代理上的 @DS;且 Controller 层若先开 @Transactional 会绑定 primary(master)。
+ * 这里在批量方法上强制 push trade,保证批量写入落到 trade 库。
+ */
+@DS(DSConstants.DATASOURCE_TRADE)
+public abstract class TradeDataSourceServiceImpl<M extends MyBaseMapper<T>, T extends SysBaseField>
+        extends MyBaseServiceImpl<M, T> {
+
+    @Override
+    @DS(DSConstants.DATASOURCE_TRADE)
+    @Transactional(rollbackFor = Exception.class)
+    public boolean saveBatch(Collection<T> entityList, int batchSize) {
+        DynamicDataSourceContextHolder.push(DSConstants.DATASOURCE_TRADE);
+        try {
+            return super.saveBatch(entityList, batchSize);
+        } finally {
+            DynamicDataSourceContextHolder.poll();
+        }
+    }
+
+    @Override
+    @DS(DSConstants.DATASOURCE_TRADE)
+    @Transactional(rollbackFor = Exception.class)
+    public boolean updateBatchById(Collection<T> entityList, int batchSize) {
+        DynamicDataSourceContextHolder.push(DSConstants.DATASOURCE_TRADE);
+        try {
+            return super.updateBatchById(entityList, batchSize);
+        } finally {
+            DynamicDataSourceContextHolder.poll();
+        }
+    }
+
+    @Override
+    @DS(DSConstants.DATASOURCE_TRADE)
+    @Transactional(rollbackFor = Exception.class)
+    public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize) {
+        DynamicDataSourceContextHolder.push(DSConstants.DATASOURCE_TRADE);
+        try {
+            return super.saveOrUpdateBatch(entityList, batchSize);
+        } finally {
+            DynamicDataSourceContextHolder.poll();
+        }
+    }
+}