210 lines
6.8 KiB
Markdown
210 lines
6.8 KiB
Markdown
|
|
# Salesforce 数据拉取模块代码分析报告
|
|||
|
|
|
|||
|
|
## 1. 模块概述
|
|||
|
|
|
|||
|
|
本次分析针对 `datai-salesforce-integration` 模块,重点检查了 `DataiIntegrationDataPullController.java` 及其对应的实现类 `SalesforceDataPullServiceImpl.java`。该模块主要负责从 Salesforce 拉取数据并同步到本地数据库。
|
|||
|
|
|
|||
|
|
## 2. Controller 方法分析
|
|||
|
|
|
|||
|
|
| 方法名 | URL | 请求方式 | 功能描述 | 实现类方法 |
|
|||
|
|
|-------|-----|---------|---------|-----------|
|
|||
|
|
| syncMultipleObjectStructures | /integration/data-pull/sync-structures/batch | POST | 同步多个 Salesforce 对象的表结构 | syncObjectStructure |
|
|||
|
|
| syncMultipleObjectsData | /integration/data-pull/sync-data/multiple | POST | 同步多个 Salesforce 对象的数据 | syncObjectsData |
|
|||
|
|
| syncObjectDataByBatch | /integration/data-pull/sync-data/batch | POST | 同步 Salesforce 对象的指定批次数据 | syncObjectDataByBatch |
|
|||
|
|
|
|||
|
|
## 3. 实现逻辑分析
|
|||
|
|
|
|||
|
|
### 3.1 表结构同步 (syncObjectStructure)
|
|||
|
|
|
|||
|
|
**实现流程:**
|
|||
|
|
1. 获取 Salesforce 连接
|
|||
|
|
2. 遍历对象 API 列表
|
|||
|
|
3. 获取每个对象的详细信息
|
|||
|
|
4. 构建对象元数据并保存
|
|||
|
|
5. 保存对象字段信息
|
|||
|
|
6. 检查对象数据量
|
|||
|
|
7. 根据数据量创建普通表或分区表
|
|||
|
|
|
|||
|
|
**问题与优化建议:**
|
|||
|
|
- **方法命名不一致**:Controller 方法名是 `syncMultipleObjectStructures`,而 Service 方法名是 `syncObjectStructure`,建议统一命名
|
|||
|
|
- **缺少事务管理**:整个同步过程没有事务管理,可能导致部分对象同步失败,部分成功
|
|||
|
|
- **异常处理不完善**:虽然有 try-catch 块,但没有详细的错误信息返回给调用者
|
|||
|
|
- **重复代码**:创建普通表和分区表的逻辑高度重复,建议提取公共方法
|
|||
|
|
|
|||
|
|
### 3.2 数据同步 (syncObjectsData)
|
|||
|
|
|
|||
|
|
**实现流程:**
|
|||
|
|
1. 获取 Salesforce 连接
|
|||
|
|
2. 获取对象字段列表
|
|||
|
|
3. 构建查询参数
|
|||
|
|
4. 执行查询并处理结果
|
|||
|
|
5. 分批获取数据并插入本地数据库
|
|||
|
|
|
|||
|
|
**问题与优化建议:**
|
|||
|
|
- **方法名混淆**:单个对象同步的方法名是 `syncSingleObjectData`,而接口方法名是 `syncObjectsData`(复数形式)
|
|||
|
|
- **缺少大数据量优化**:对于大数据量对象,没有并行处理或更高效的批量插入机制
|
|||
|
|
- **API 调用没有重试机制**:Salesforce API 可能有调用限制,建议添加重试机制
|
|||
|
|
- **缺少进度跟踪**:无法获取同步进度信息
|
|||
|
|
|
|||
|
|
### 3.3 批次数据同步 (syncObjectDataByBatch)
|
|||
|
|
|
|||
|
|
**实现流程:**
|
|||
|
|
1. 获取 Salesforce 连接
|
|||
|
|
2. 获取对象字段列表
|
|||
|
|
3. 构建带批次 ID 的查询参数
|
|||
|
|
4. 执行查询并处理结果
|
|||
|
|
5. 分批获取数据并插入本地数据库
|
|||
|
|
|
|||
|
|
**问题与优化建议:**
|
|||
|
|
- **缺少批次 ID 验证**:没有验证批次 ID 的有效性
|
|||
|
|
- **缺少批次状态记录**:没有记录批次处理的状态和结果
|
|||
|
|
- **缺少批次处理的并发控制**:可能导致同一批次被多次处理
|
|||
|
|
|
|||
|
|
## 4. 代码优化建议
|
|||
|
|
|
|||
|
|
### 4.1 统一方法命名
|
|||
|
|
|
|||
|
|
**优化前:**
|
|||
|
|
```java
|
|||
|
|
// Controller 方法
|
|||
|
|
public Map<String, Boolean> syncMultipleObjectStructures(@RequestBody List<String> objectApis) {
|
|||
|
|
return salesforceDataPullService.syncObjectStructure(objectApis);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Service 方法
|
|||
|
|
@Override
|
|||
|
|
public Map<String, Boolean> syncObjectStructure(List<String> objectApis) {
|
|||
|
|
// 实现逻辑
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**优化后:**
|
|||
|
|
```java
|
|||
|
|
// Controller 方法
|
|||
|
|
public Map<String, Boolean> syncMultipleObjectStructures(@RequestBody List<String> objectApis) {
|
|||
|
|
return salesforceDataPullService.syncMultipleObjectStructures(objectApis);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Service 方法
|
|||
|
|
@Override
|
|||
|
|
public Map<String, Boolean> syncMultipleObjectStructures(List<String> objectApis) {
|
|||
|
|
// 实现逻辑
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.2 添加事务管理
|
|||
|
|
|
|||
|
|
**优化前:**
|
|||
|
|
```java
|
|||
|
|
@Override
|
|||
|
|
public Map<String, Boolean> syncObjectStructure(List<String> objectApis) {
|
|||
|
|
// 实现逻辑,没有事务管理
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**优化后:**
|
|||
|
|
```java
|
|||
|
|
@Override
|
|||
|
|
@Transactional(rollbackFor = Exception.class)
|
|||
|
|
public Map<String, Boolean> syncMultipleObjectStructures(List<String> objectApis) {
|
|||
|
|
// 实现逻辑,有事务管理
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.3 提取重复代码
|
|||
|
|
|
|||
|
|
**优化前:**
|
|||
|
|
```java
|
|||
|
|
// 创建普通表的逻辑
|
|||
|
|
// ... 大量代码 ...
|
|||
|
|
|
|||
|
|
// 创建分区表的逻辑
|
|||
|
|
// ... 大量重复代码 ...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**优化后:**
|
|||
|
|
```java
|
|||
|
|
// 提取公共的表创建逻辑
|
|||
|
|
private void createTableCommon(DataiIntegrationObjectBo objectBo, List<DataiIntegrationFieldBo> migrationFieldBos, boolean isPartitioned) {
|
|||
|
|
// 公共的表创建逻辑
|
|||
|
|
// ...
|
|||
|
|
|
|||
|
|
if (isPartitioned) {
|
|||
|
|
// 创建分区表的特定逻辑
|
|||
|
|
// ...
|
|||
|
|
customMapper.createRangePartitionTable(...);
|
|||
|
|
} else {
|
|||
|
|
// 创建普通表的特定逻辑
|
|||
|
|
customMapper.createTable(...);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.4 添加重试机制
|
|||
|
|
|
|||
|
|
**优化前:**
|
|||
|
|
```java
|
|||
|
|
// 获取连接
|
|||
|
|
PartnerConnection connection = SOAPConnectionFactory.sourceInstance();
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**优化后:**
|
|||
|
|
```java
|
|||
|
|
// 获取连接,添加重试机制
|
|||
|
|
PartnerConnection connection = retryOperation(() -> SOAPConnectionFactory.sourceInstance(), 3, 1000);
|
|||
|
|
|
|||
|
|
// 重试方法
|
|||
|
|
private <T> T retryOperation(Supplier<T> operation, int maxRetries, long delayMs) {
|
|||
|
|
int retries = 0;
|
|||
|
|
while (true) {
|
|||
|
|
try {
|
|||
|
|
return operation.get();
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
retries++;
|
|||
|
|
if (retries >= maxRetries) {
|
|||
|
|
throw e;
|
|||
|
|
}
|
|||
|
|
try {
|
|||
|
|
Thread.sleep(delayMs);
|
|||
|
|
} catch (InterruptedException ie) {
|
|||
|
|
Thread.currentThread().interrupt();
|
|||
|
|
throw new RuntimeException(ie);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.5 完善错误处理和日志记录
|
|||
|
|
|
|||
|
|
**优化前:**
|
|||
|
|
```java
|
|||
|
|
catch (Exception e) {
|
|||
|
|
log.error("处理对象 {} 时出错: {}", objectApi, e.getMessage(), e);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**优化后:**
|
|||
|
|
```java
|
|||
|
|
catch (ConnectionException e) {
|
|||
|
|
log.error("获取对象 {} 的元数据失败: {}", objectApi, e.getMessage(), e);
|
|||
|
|
// 记录详细的错误信息
|
|||
|
|
resultMap.put(objectApi.trim(), false);
|
|||
|
|
errorDetails.put(objectApi.trim(), "连接失败: " + e.getMessage());
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
log.error("处理对象 {} 时出错: {}", objectApi, e.getMessage(), e);
|
|||
|
|
resultMap.put(objectApi.trim(), false);
|
|||
|
|
errorDetails.put(objectApi.trim(), "处理失败: " + e.getMessage());
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 5. 总结
|
|||
|
|
|
|||
|
|
该模块的代码实现了 Salesforce 数据拉取的基本功能,但在方法命名、事务管理、错误处理、性能优化等方面还有提升空间。通过统一命名、添加事务管理、提取重复代码、添加重试机制和完善错误处理,可以提高代码的可维护性、可靠性和性能。
|
|||
|
|
|
|||
|
|
建议在后续开发中,重点关注以下几个方面:
|
|||
|
|
1. 完善事务管理,确保数据一致性
|
|||
|
|
2. 优化大数据量处理,提高同步效率
|
|||
|
|
3. 添加监控和日志记录,便于问题排查
|
|||
|
|
4. 实现重试机制,提高 API 调用成功率
|
|||
|
|
5. 完善错误处理,返回详细的错误信息
|