记录deepseek,抽取能看懂的

一、方案一:分页查询(首选方案)

// 服务提供方
@RestController
public class UserController {
    @GetMapping("/api/users")
    public PageResult<UserDTO> getUsers(
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "20") int size,
            @RequestParam(required = false) String name,
            @RequestParam(required = false) Integer age) {
        
        Pageable pageable = PageRequest.of(page - 1, size);
        Page<User> userPage = userRepository.findByConditions(name, age, pageable);
        
        return new PageResult<>(
            userPage.getContent().stream().map(this::toDTO).collect(Collectors.toList()),
            userPage.getTotalElements(),
            userPage.getTotalPages(),
            page
        );
    }
}

// 服务消费方 - 分批处理
@Service
public class UserService {
    @Autowired
    private UserFeignClient userFeignClient;
    
    public void processAllUsers() {
        int page = 1;
        int size = 1000; // 每批1000条
        boolean hasMore = true;
        
        while (hasMore) {
            PageResult<UserDTO> result = userFeignClient.getUsers(page, size, null, null);
            
            // 处理当前批次数据
            processBatch(result.getData());
            
            // 判断是否还有下一页
            hasMore = page < result.getTotalPages();
            page++;
            
            // 批次间延迟,避免压力过大
            if (hasMore) {
                Thread.sleep(100); // 100ms间隔
            }
        }
    }
    
    private void processBatch(List<UserDTO> batch) {
        // 批量处理逻辑
        batch.forEach(user -> {
            // 处理单个用户
        });
    }
}

二、方案二:消息队列异步处理

// 架构:数据库 → 生产者服务 → 消息队列 → 消费者服务

// 生产者服务(数据提供方)
@Service
public class UserProducerService {
    @Autowired
    private KafkaTemplate<String, UserDTO> kafkaTemplate;
    
    public void produceUsers() {
        int batchSize = 1000;
        int offset = 0;
        
        while (true) {
            List<UserDTO> batch = userRepository.findBatch(offset, batchSize);
            
            if (batch.isEmpty()) {
                break;
            }
            
            // 发送到消息队列
            batch.forEach(user -> {
                kafkaTemplate.send("user-data-topic", user.getId().toString(), user);
            });
            
            offset += batchSize;
            
            // 控制发送速率
            Thread.sleep(100);
        }
        
        // 发送结束标志
        kafkaTemplate.send("user-data-topic", "EOF", new EndOfFileMarker());
    }
}

// 消费者服务(数据消费方)
@Service
public class UserConsumerService {
    @KafkaListener(topics = "user-data-topic", groupId = "user-processor")
    public void consumeUser(UserDTO user) {
        if (user instanceof EndOfFileMarker) {
            // 处理完成
            finishProcessing();
        } else {
            // 处理用户数据
            processUser(user);
        }
    }
}

三、Feign客户端优化配置

# application.yml
feign:
  client:
    config:
      default:
        connectTimeout: 30000    # 连接超时30秒
        readTimeout: 300000      # 读取超时5分钟(长查询需要)
        loggerLevel: basic
        retryer:
          period: 100
          maxPeriod: 1000
          maxAttempts: 3

# 或者为特定服务配置
feign:
  client:
    config:
      user-service:
        connectTimeout: 60000
        readTimeout: 600000      # 10分钟超时
        requestInterceptors:     # 添加请求头
          - com.example.feign.AuthInterceptor
// Feign客户端配置类
@Configuration
public class FeignConfig {
    @Bean
    public Decoder feignDecoder() {
        return new JacksonDecoder(customObjectMapper());
    }
    
    @Bean
    public Encoder feignEncoder() {
        return new JacksonEncoder(customObjectMapper());
    }
    
    @Bean
    public Retryer feignRetryer() {
        return new Retryer.Default(100, 1000, 3);
    }
    
    // 自定义ObjectMapper,优化序列化
    private ObjectMapper customObjectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        return mapper;
    }
}

// 使用HTTP压缩传输
@FeignClient(name = "user-service", configuration = CompressedFeignConfig.class)
public interface UserFeignClient {
    @GetMapping(value = "/api/users", consumes = "application/json")
    @Headers("Accept-Encoding: gzip")
    PageResult<UserDTO> getUsers(@RequestParam int page, @RequestParam int size);
}

@Configuration
class CompressedFeignConfig {
    @Bean
    public Client feignClient() {
        return new Client.Default(new GzipDecompressingClient(), null);
    }
}

四、数据库层面优化

-- 使用覆盖索引减少回表
CREATE INDEX idx_covering ON users(id, name, age, hobby);

-- 查询时只选择需要的字段
SELECT id, name, age FROM users LIMIT 1000;

-- 使用游标避免一次性加载
DECLARE user_cursor CURSOR FOR 
SELECT id, name, age FROM users;

更多推荐