一、核心概念:这是什么?
Bulk API 2.0 Query 是 Salesforce 提供的一种批量数据查询服务,专门用于:
- 处理大量数据:当需要查询百万甚至千万级别的记录时
- 异步执行:查询在后台运行,不会阻塞你的应用程序
- 自动分块处理:系统会自动把大数据查询分解成小任务并行处理
- 结果压缩:返回的数据总是被压缩以减少传输量
简单比喻:就像你要从图书馆(Salesforce数据库)复印100万页资料,不是自己一页页去复印,而是:
- 把需求清单给管理员(提交查询作业)
- 管理员找多个助手同时复印(自动分块并行处理)
- 复印完打包压缩给你(返回压缩结果)
二、主要特点和工作流程
工作流程图示
关键特性详解
-
异步处理:
- 你提交查询后立即得到一个
jobId - 不必等待查询完成,可以去做其他事情
- 定期检查作业状态,完成后下载结果
- 你提交查询后立即得到一个
-
自动分块(PK Chunking) :
三、支持的API端点(URIs和HTTP方法)
文档中列出的6个端点构成了完整的查询作业生命周期管理:
| 操作 | HTTP方法 | 端点路径 | 用途 |
|---|---|---|---|
| 创建作业 | POST | /jobs/query | 发起一个新的查询作业 |
| 列出所有作业 | GET | /jobs/query | 查看组织中所有的查询作业 |
| 查看单个作业 | GET | /jobs/query/{id} | 查看特定作业的详细信息 |
| 获取结果 | GET | /jobs/query/{id}/results | 下载查询结果(压缩格式) |
| 中止作业 | PATCH | /jobs/query/{id} | 停止正在运行的作业 |
| 删除作业 | DELETE | /jobs/query/{id} | 删除作业(包括结果) |
版本要求:需要 API 版本 47.0 或更高。
四、重要限制和注意事项(SOQL考虑因素)
这是最需要注意的部分,因为这些限制会影响查询是否能够成功执行。
1. 禁用PK分块的情况
重要规则:如果在查询中使用 LIMIT 或 ORDER BY,PK分块功能会被禁用!
- 后果:查询变慢,可能超时失败
- 建议:如果遇到超时,首先去掉
ORDER BY或LIMIT子句
2. 完全不支持的SOQL功能
Bulk API 2.0 无法执行包含以下内容的查询:
❌ 不支持 GROUP BY(分组)
❌ 不支持 OFFSET(偏移量)
❌ 不支持 TYPEOF(类型判断)
❌ 不支持 COUNT()等聚合函数
❌ 不支持 GROUP BY中的日期函数
❌ 不支持复合地址字段或地理字段(要查询其单独的子字段)
❌ 不支持父对子关系查询(只支持子对父)
3. 支持的查询示例
-- ✅ 支持的查询示例
SELECT Id, Name, Account.Name, CreatedDate
FROM Contact
WHERE CreatedDate = LAST_N_DAYS:30
AND Account.Industry = 'Technology'
-- ❌ 不支持的查询示例
SELECT COUNT(Id) FROM Contact -- 使用了聚合函数
SELECT Id FROM Contact ORDER BY CreatedDate -- 禁用PK分块
SELECT Id, Name FROM Contact GROUP BY Name -- 使用了GROUP BY
/jobs/query POST 详细步骤解析
1. 请求地址(URI)
/services/data/vXX.X/jobs/query
vXX.X:API版本号,必须是 47.0 或更高/jobs/query:专门用于创建查询作业的端点
2. 认证方式
必须在请求头中提供:
Authorization: Bearer token
3. 请求格式(JSON)
必须发送一个JSON格式的数据包:
{
"operation": "query",
"query": "SELECT Id FROM Account"
}
两个必填参数:
| 参数 | 值 | 说明 |
|---|---|---|
operation | "query" 或 "queryAll" | query:只查询未删除的记录 queryAll:包含已删除和归档的记录 |
query | SOQL查询语句 | 要执行的SQL查询 |
4. 完整的请求示例
简单查询示例
curl -X POST \
https://your-instance.salesforce.com/services/data/v55.0/jobs/query \
-H "Authorization: Bearer 00DC8000000NTCb!AQEAQL..." \
-H "Content-Type: application/json" \
-d '{
"operation": "query",
"query": "SELECT Id, Name, Industry FROM Account WHERE CreatedDate = LAST_N_DAYS:30"
}'
带可选参数的复杂示例
{
"operation": "query",
"query": "SELECT Id, Name FROM Account",
"contentType": "CSV",
"columnDelimiter": "COMMA",
"lineEnding": "CRLF"
}
可选参数详解:
| 参数 | 可选值 | 默认值 | 说明 |
|---|---|---|---|
contentType | "CSV" | "CSV" | 结果格式,目前只支持CSV |
columnDelimiter | "COMMA", "PIPE", "TAB", "CARET", "BACKQUOTE", "SEMICOLON" | "COMMA" | CSV列分隔符 |
lineEnding | "LF", "CRLF" | "LF" | 行结束符(换行符) |
分隔符对照表:
COMMA=,(逗号)PIPE=|(竖线)TAB=\t(制表符)CARET=^(脱字符)BACKQUOTE=`(反引号)SEMICOLON=;(分号)
5. 响应解析
当您成功提交查询后,会得到类似这样的响应:
{
"id": "750R0000000zlh9IAA",
"operation": "query",
"object": "Account",
"createdById": "005R0000000GiwjIAC",
"createdDate": "2018-12-10T17:50:19.000+0000",
"systemModstamp": "2018-12-10T17:50:19.000+0000",
"state": "UploadComplete",
"concurrencyMode": "Parallel",
"contentType": "CSV",
"apiVersion": 46.0,
"lineEnding": "LF",
"columnDelimiter": "COMMA"
}
最重要的响应参数
-
id:"750R0000000zlh9IAA"- 这是最重要的信息! 后续所有操作(检查状态、下载结果)都需要这个ID
- 就像餐厅的取餐号,凭这个号码才能取餐
-
state:"UploadComplete"-
作业的当前状态
-
状态流转:
UploadComplete→InProgress→JobComplete -
可能的状态:
UploadComplete InProgress JobComplete Failed Aborted
-
-
其他关键信息:
object:查询的对象类型(如"Account")createdDate:作业创建时间concurrencyMode:并行模式(目前都是"Parallel")
/jobs/query/{id}/results Get 详细步骤解析
1. 请求地址(URI)
GET /services/data/vXX.X/jobs/query/{queryJobId}/results
前提条件
- 查询作业必须处于 JobComplete 状态
- 必须使用创建查询时相同的 API 版本
2. 关键参数
- queryJobId(必需):查询作业的ID
- locator(可选):用于分页的定位器字符串
- maxRecords(可选):每次请求返回的最大记录数
3. 分页机制
- 首次请求:不使用 locator 参数,获取第一批结果
- 检查响应头:
- Sforce-Locator:下一个结果集的定位器
- Sforce-NumberOfRecords:当前批次返回的记录数
- 后续请求:如果 Sforce-Locator 的值不是 "null",则使用该值作为 locator 参数继续请求
循环直到完成:重复上述步骤,直到 Sforce-Locator 的值为 "null"
4. 响应格式
- 默认为 CSV 格式
- 必须设置
Accept: text/csv请求头 - 从 API 版本 50.0 开始,列的顺序与查询请求的顺序一致