API可使用SDK調用方式(包括Java SDK和Python SDK)及白名單免密調用方式。其中僅使用私人網關的時候支援白名單方式。本篇API調用樣本為調用模板,您可根據模板配置API的調用樣本。
SDK調用
Java SDK簡介
Dataphin資料服務Java SDK為您提供了快速調用資料服務API的基礎SDK及樣本調用代碼。這裡向您介紹如何使用Dataphin服務Java SDK。
Java SDK的代碼檔案層級結構如下:
JAR包版本可能跟隨SDK的升級而升級。
Java SDK/
demo/
ClientDemo.java提供了同步API的調用樣本和方法。AsyncClientDemo.java提供了非同步API的調用樣本和方法。
lib/
dataphin-sdk-core-java-v5.4.0.jar本SDK的依賴包。dataphin-sdk-core-java-v5.4.0-javadoc.jar上述依賴包的Javadoc。dataphin-sdk-core-java-v5.4.0-jar-with-dependencies.jar上述依賴包的全依賴包。
ApiDocument_v5.4.0.mdAPI介面文檔。LICENSE許可證。
Java SDK擷取方式如下:
在Dataphin首頁的頂部功能表列,選擇服務 > 應用管理。
在左側導覽列單擊調用說明。
單擊API調用說明頁簽,在頁面右上方選擇Java SDK下載,將下載SDK的Jar包添加至pom.xml中。
Java SDK調用同步API流程
在調用API之前,您首先需要初始化用戶端。
若API的回應時間較長,可使用非同步呼叫,在整個等待應答期間,主線程不會被阻塞。
您可以執行個體化
QueryParamRequest對象,並且佈建要求參數滿足不同的查詢需要,詳情請參考調用執行個體中的packRequestParam方法。API請求和返回結果資訊請查看SDK中的
APIDocument.md。若在使用中遇到問題,請諮詢Dataphin支援人員。
步驟一:環境準備
Dataphin服務Java SDK適用於JDK 1.8及以上版本。
您需要準備一對授權識別碼供SDK產生鑒權和簽名資訊,即AppKey和AppSecret。
AppKey和AppSecret可在服務 > 應用管理 > 我的應用程式列表中擷取。
重要AppKey和AppSecret是Dataphin資料服務認證使用者請求的密鑰,這兩個配置如果儲存在用戶端,請妥善加密。
在
pom.xml中添加如下依賴,如果添加dataphin-sdk-core-java報錯請手動添加該JAR檔案,路徑JAVA_SDK/lib/dataphin-sdk-core-java-v5.4.0.jar(即所擷取Java SDK中的JAR包)。說明dataphin-sdk-core-java並不存在於中央Maven倉庫,因此下載該SDK後還需要您上傳至貴公司的Maven倉庫,或者在IDEA、Eclipse中手動引入。<dependency> <groupId>com.alibaba.dt</groupId> <artifactId>dataphin-sdk-core-java</artifactId> <version>v5.4.0</version> </dependency>
步驟二:引入Java SDK的API介面調用類
在服務 > API市場 > API列表中下載對應的API文檔。
匯入ClientDemo.java,修正
ClientDemo.java類的import和package。import java.util.*; import java.util.function.Consumer; import com.alibaba.cloudapi.sdk.constant.SdkConstant; import com.alibaba.cloudapi.sdk.enums.Scheme; import com.alibaba.cloudapi.sdk.model.ApiCallback; import com.alibaba.cloudapi.sdk.model.ApiRequest; import com.alibaba.cloudapi.sdk.model.ApiResponse; import com.alibaba.dt.dataphin.client.ApiClient; import com.alibaba.dt.dataphin.client.ApiClientBuilderParams; import com.alibaba.dt.dataphin.client.sse.SseApiClient; import com.alibaba.dt.dataphin.schema.ManipulationParamRequest; import com.alibaba.dt.dataphin.schema.OrderBy; import com.alibaba.dt.dataphin.schema.QueryParamRequest; import com.alibaba.fastjson.JSON; /** * 同步API樣本 * <p> * 使用方式: * 先配置好 HOST/APP_KEY/APP_SECRET/API_ID, * 再按需設定 getClient() 中的變數以及 packQueryParamRequest() 中的參數值。 * 注意: * getClient() 中的參數可能會因不同的 API 而設定不同的值,可以將 getClient() 改造成帶有入參,以適應不同 API 使用不同的參數。 */ public class ClientDemo { /** * 訪問網域名稱或ip,在資料服務的網路設定中獲得該值 */ private static final String HOST = "xxx"; /** * 應用appKey,即你用哪個APP來調用這個API */ private static final String APP_KEY = "xxx"; /** * 應用appSecret,即你用哪個APP來調用這個API */ private static final String APP_SECRET = "xxx"; /** * 配置調用的API編號 */ private static final String API_ID = "xxx"; public static void main(String[] args) throws Exception { // 同步調用GET類型API syncGet(); // 同步調用LIST類型API syncList(); // 非同步呼叫GET類型API asyncGet(); // 非同步呼叫LIST類型API asyncList(); // 流式調用GET類型API fluxGet(); // 分頁查詢的api,同時擷取查詢總數 syncListWithTotalNum(); // 同步調用Create類型API syncCreate(); // 同步調用Update類型API syncUpdate(); // 同步調用Delete類型API syncDelete(); } private static void syncListWithTotalNum() { ApiClient client = getClient(); // 需要按需修改裡面的返回欄位、查詢條件等 QueryParamRequest queryParamRequest = packRequestParamWithReturnNum(); ApiResponse response = client.listSync(API_ID, queryParamRequest); String resultStr = getResultString(response); // contain totalNum in ResultBody System.out.println(resultStr); } /** * 同步調用GET類型API */ public static void syncGet() { // 擷取 ApiClient 對象 ApiClient client = getClient(); // 需要按需修改裡面的返回欄位、查詢條件等 QueryParamRequest queryParamRequest = packRequestParam(); ApiResponse response = client.getSync(API_ID, queryParamRequest); System.out.println(getResultString(response)); } /** * 同步調用LIST類型API */ public static void syncList() { // 擷取 ApiClient 對象 ApiClient client = getClient(); // 需要按需修改裡面的返回欄位、查詢條件等 QueryParamRequest queryParamRequest = packRequestParam(); ApiResponse response = client.listSync(API_ID, queryParamRequest); System.out.println(getResultString(response)); } /** * 同步調用Create類型API */ public static void syncCreate() { // 擷取 ApiClient 對象 ApiClient client = getClient(); // 按需修改入參資訊 ManipulationParamRequest manipulationParamRequest = packDmlRequestParam(); ApiResponse response = client.createSync(API_ID, manipulationParamRequest); System.out.println(getResultString(response)); } /** * 同步調用Update類型API */ public static void syncUpdate() { // 擷取 ApiClient 對象 ApiClient client = getClient(); // 按需修改入參資訊 ManipulationParamRequest manipulationParamRequest = packDmlRequestParam(); ApiResponse response = client.updateSync(API_ID, manipulationParamRequest); System.out.println(getResultString(response)); } /** * 同步調用Delete類型API */ public static void syncDelete() { // 擷取 ApiClient 對象 ApiClient client = getClient(); // 按需修改入參資訊 ManipulationParamRequest manipulationParamRequest = packDmlRequestParam(); ApiResponse response = client.deleteSync(API_ID, manipulationParamRequest); System.out.println(getResultString(response)); } /** * 非同步呼叫GET類型API * 需要在回調方法中處理響應結果 */ public static void asyncGet() throws Exception { // 擷取 ApiClient 對象 ApiClient client = getClient(); // 需要按需修改裡面的返回欄位、查詢條件等 QueryParamRequest queryParamRequest = packRequestParam(); client.getAsync(API_ID, queryParamRequest, new ApiCallback() { @Override public void onFailure(ApiRequest request, Exception e) { e.printStackTrace(); } @Override public void onResponse(ApiRequest request, ApiResponse response) { try { System.out.println(getResultString(response)); } catch (Exception e) { e.printStackTrace(); } } }); System.out.println("--- main線程提前結束 ---"); } /** * 非同步呼叫LIST類型API * 需要在回調方法中處理響應結果 */ public static void asyncList() throws Exception { // 擷取 ApiClient 對象 ApiClient client = getClient(); // 需要按需修改裡面的返回欄位、查詢條件等 QueryParamRequest queryParamRequest = packRequestParam(); client.listAsync(API_ID, queryParamRequest, new ApiCallback() { @Override public void onFailure(ApiRequest request, Exception e) { e.printStackTrace(); } @Override public void onResponse(ApiRequest request, ApiResponse response) { try { System.out.println(getResultString(response)); } catch (Exception e) { e.printStackTrace(); } } }); System.out.println("--- main線程提前結束 ---"); } /** * 擷取 ApiClient 對象 */ public static ApiClient getClient() { ApiClientBuilderParams params = new ApiClientBuilderParams(); // 應用appKey params.setAppKey(APP_KEY); // 應用appSecret params.setAppSecret(APP_SECRET); // 訪問網域名稱或ip params.setHost(HOST); // 預設為http協議, 可根據API設定https協議 // 注意:Dataphin內建網關不支援https,阿里雲網關支援https params.setScheme(Scheme.HTTP); // 訪問API的資料環境,生產環境:RELEASE,開發環境:PRE params.setStage("RELEASE"); // 如果使用次層網域或未指定環境的獨立網域名稱,需要設定env // 有 PROD 和 PRE 兩種值(如果是basic模式,傳PROD; 如果是Dev-Prod模式,PROD表示查生產環境資料庫,PRE表示查開發環境資料庫) // 如果已經指定了訪問環境的獨立網域名稱,則env參數不會起作用 params.setEnv("PROD"); ApiClient apiClient = new ApiClient(params); // 設定impala資料庫類型的逾時時間以及輪詢間隔(可選,預設逾時時間300s,輪詢間隔800毫秒) // 參數只對impala有作用,調用非impala的API也要設定,保持預設即可 apiClient.setImpalaTimeoutAndInterval(300, 800); return apiClient; } public static SseApiClient getSseClient() { ApiClientBuilderParams params = new ApiClientBuilderParams(); // 應用appKey params.setAppKey(APP_KEY); // 應用appSecret params.setAppSecret(APP_SECRET); // 訪問網域名稱或ip params.setHost(HOST); // 預設為http協議, 可根據API設定https協議 // 注意:Dataphin內建網關不支援https,阿里雲網關支援https params.setScheme(Scheme.HTTP); // 訪問API的資料環境,生產環境:RELEASE,開發環境:PRE params.setStage("RELEASE"); // 如果使用次層網域或未指定環境的獨立網域名稱,需要設定env // 有 PROD 和 PRE 兩種值(如果是basic模式,傳PROD; 如果是Dev-Prod模式,PROD表示查生產環境資料庫,PRE表示查開發環境資料庫) // 如果已經指定了訪問環境的獨立網域名稱,則env參數不會起作用 params.setEnv("PROD"); return new SseApiClient(params); } /** * 調用api包含consumer */ public static void fluxGet() { Consumer<ApiResponse> consumer = r -> System.out.println(new String(r.getBody())); SseApiClient sseApiClient = getSseClient(); // 對於短周期應用, 對於完成後可以將client的線程池關閉,釋放資源 sseApiClient.getFlux(API_ID, packRequestParam()) // 對於臨時運行,完成式需要關閉串連釋放資源 .doOnComplete(sseApiClient::shutdown) .subscribe(consumer); } private static QueryParamRequest packRequestParamWithReturnNum() { QueryParamRequest queryParamRequest = packRequestParam(); queryParamRequest.setReturnTotalNum(true); return queryParamRequest; } /** * 封裝請求對象 */ private static QueryParamRequest packRequestParam() { QueryParamRequest queryParamRequest = new QueryParamRequest(); /********* API相關業務參數設定 begin *********/ /* * 代理帳號類型,非必填 * 注意,若要使用代理模式,需同時滿足以下條件: * 1. 開通行級許可權功能 * 2. 應用申請了代理許可權 * 3. API設定了關聯的行級許可權 * * 當使用代理模式認證時,需要指定代理使用者的帳號類型。 * ACCOUNT_NAME:Dataphin的使用者名稱。 * USER_ID:Dataphin內部的唯一ID。 * SOURCE_USER_ID:源系統帳號ID。 * 僅當設定了DelegationUid時,需要配置此參數。若未填寫此參數,則預設類型為USER_ID。 */ queryParamRequest.setAccountType("USER_ID"); /* * 代理帳號ID,非必填 * 被代理訪問的使用者,需根據所選AccountType的類型,傳入對應帳號ID。 * 設定該參數且API設定了關聯的行級許可權規則,會使用代理模式的認證方式。 */ queryParamRequest.setDelegationUid("abcd"); /* * 請求參數列表,非必填的參數可不傳,必填參數必須傳,否則會報錯 * 其中key為對應的查詢欄位,value為查詢欄位對應的值 * 例如這裡的id為請求欄位名,1為id對應的值,可以設定多個查詢參數 * 注意:如果是 IN 類型的參數,使用 List 封裝參數值 */ Map<String, Object> conditions = new HashMap<>(); conditions.put("id", 1); conditions.put("age", Arrays.asList(10, 20, 30)); queryParamRequest.setConditions(conditions); /* * 返回參數列表,不可為空 * 例如指定返回id和name * 注意:返回參數如果不存在或沒許可權會報錯 */ queryParamRequest.setReturnFields(Arrays.asList("id", "name")); /* * 排序欄位,非必填 * 注意oracle和sqlServer使用分頁需要同時使用排序 * 指定參數升序或者降序,可設定多個欄位進行升序或者降序 * 例如返回結果按id進行升序 */ List<OrderBy> orderList = new ArrayList<>(); orderList.add(new OrderBy("id1", OrderBy.Order.ASC)); orderList.add(new OrderBy("id2", OrderBy.Order.DESC)); queryParamRequest.setOrderBys(orderList); /* * 分頁參數,非必填,僅LIST類型API生效 */ // 從第幾條資料取 queryParamRequest.setPageStart(0); // 每頁取多少條資料 queryParamRequest.setPageSize(10); /* * API版本號碼,非必填,僅開發環境API支援設定 */ // queryParamRequest.setApiVersion("V1"); /********* API相關業務參數設定 end *********/ /********* 功能參數設定 begin *********/ /* * 是否使用模型緩衝 * 開啟會減少同一個服務單元API相同出入參時的解析頻次,提高查詢效率 */ queryParamRequest.setUseModelCache(false); /* * 是否使用結果緩衝 * 開啟則會緩衝同一個API相同條件、相同返回欄位的查詢結果 * 適用於資料不變化的查詢,減少相同SQL的查詢頻次,提高查詢效率 * 緩衝時間長度預設30分鐘,3.5.6 版本後,在API開發頁面可設定緩衝時間長度 * 注意:如果API未開啟結果緩衝,該參數無效 */ queryParamRequest.setUseResultCache(false); /* * 是否保持欄位的大小寫格式 * 如果對大小寫敏感,建議設定為true * 為false時,直連API返回結果的欄位名預設為大寫字母 */ queryParamRequest.setKeepColumnCase(true); /********* 功能參數設定 end *********/ return queryParamRequest; } /** * 封裝DML請求對象 */ private static ManipulationParamRequest packDmlRequestParam() { ManipulationParamRequest manipulationParamRequest = new ManipulationParamRequest(); /* * 請求參數列表,非必填的參數可不傳,必填參數必須傳,否則會報錯 * 其中key為對應的欄位名,value為欄位對應的值 * 例如這裡的id為請求欄位名,1為id對應的值,可以設定多個參數 * 注意:如果是 IN 類型的參數,使用 List 封裝參數值 */ Map<String, Object> conditions = new HashMap<>(); conditions.put("id", 1); conditions.put("age", Arrays.asList(10, 20, 30)); manipulationParamRequest.setConditions(conditions); /* * 如果API的資料量是批量時,需要將入參放入batchConditions中 */ List<Map<String, Object>> batchConditions = new ArrayList<>(); batchConditions.add(conditions); manipulationParamRequest.setBatchConditions(batchConditions); /* * API版本號碼,非必填,僅開發環境API支援設定 */ // manipulationParamRequest.setApiVersion("V1"); return manipulationParamRequest; } /** * 擷取結果字串 */ private static String getResultString(ApiResponse response) { /* * step 1: 擷取HttpResponse中頭部的詳細資料方式 * response.getHeaders().get(key) * 說明:key取值有"date\server\transfer-encoding\keep-alive\vary\connection\content-type\x-ca-request-id\x-ca-error-message\x-ca-error-code" * 如果API調用失敗,Headers會有x-ca-error-message(錯誤資訊描述)和x-ca-error-code(網關錯誤狀態代碼),如果成功則不會存在該資訊, * 但是x-ca-request-id(每次請求的唯一標識)始終會有。 * 推薦:如果返回code不是200,可列印出x-ca-error-message\x-ca-error-code以便排查問題 * 強制:使用中需要列印出x-ca-request-id,便於查看日誌 * * step 2:下面已經列印出response的詳細資料,實際開發中可以根據step1中描述,選擇輸出相關資訊 */ System.out.println("返回結果詳細資料: "+ SdkConstant.CLOUDAPI_LF + JSON.toJSONString(response) + SdkConstant.CLOUDAPI_LF); StringBuilder result = new StringBuilder(); result.append("Response from backend server").append(SdkConstant.CLOUDAPI_LF).append(SdkConstant.CLOUDAPI_LF); result.append("ResultCode:").append(SdkConstant.CLOUDAPI_LF).append(response.getCode()).append(SdkConstant.CLOUDAPI_LF).append(SdkConstant.CLOUDAPI_LF); result.append("RequestId:").append(SdkConstant.CLOUDAPI_LF).append(response.getHeaders().get("x-ca-request-id")).append(SdkConstant.CLOUDAPI_LF).append(SdkConstant.CLOUDAPI_LF); if (200 != response.getCode()) { result.append("ErrorCode:").append(SdkConstant.CLOUDAPI_LF).append(response.getHeaders().get("x-ca-error-code")).append(SdkConstant.CLOUDAPI_LF).append(SdkConstant.CLOUDAPI_LF); result.append("ErrorMessage:").append(SdkConstant.CLOUDAPI_LF).append(response.getHeaders().get("x-ca-error-message")).append(SdkConstant.CLOUDAPI_LF).append(SdkConstant.CLOUDAPI_LF); } result.append("ResultBody:").append(SdkConstant.CLOUDAPI_LF).append(new String(response.getBody(), SdkConstant.CLOUDAPI_ENCODING)); /* * 查看結果 如果狀態代碼不是200,可查看x-ca-error-message報錯資訊排查問題 * 建議使用者儲存x-ca-request-id參數,如有異常請提供該參數以便我們排查問題 */ return result.toString(); } }
步驟三:初始化通訊通道類
要調用API,首先要初始化用戶端。您可以參考ClientDemo.java中getClient方法,使用對應的ApiClientBuilderParams類來進行初始化。其中,您需要將Host、APP_Key和APP_Secret三個變數進行替換。
步驟四:API介面說明
API介面類型
API介面類型分為查詢類型(LIST、GET)和操作類型(CREATE、UPDATE、DELETE)。
LIST支援分頁查詢而GET不支援分頁查詢,請參考
ClientDemo.java中packRequestParam方法,設定QueryParamRequest裡的參數。操作類型API請參考
ClientDemo.java中的packDmlRequestParam方法,設定ManipulationParamRequest裡的參數。
調用API介面
SDK中的LIST和GET方法為Dataphin資料服務的通用方法,SDK中提供同步和非同步調用方法。在調用API之前,您需要根據您在Dataphin資料服務中定義的API填入相關的請求參數。
調試用例中
conditions為查詢類API的業務請求參數,returnFields為API的返回參數,具體參數請參考服務 > 應用管理 > 已授權API服務頁面,單擊目標API操作列下調試,進入調試頁面。操作類API的業務參數需要根據API配置的資料量進行區分,單條的入參通過
conditions進行傳遞,批量的入參需要通過batchConditions進行傳遞。請求參數中的API_ID,請參考服務 > 應用管理 > 已授權API服務頁面API列下的API_ID。
Java SDK調用非同步API流程
在調用API之前,您首先需要初始化用戶端。
若API的回應時間較長,可使用非同步呼叫,在整個等待應答期間,主線程不會被阻塞。
您可以執行個體化
QueryParamRequest對象,並且佈建要求參數滿足不同的查詢需要,詳情請參考調用執行個體中的packRequestParam方法。API請求和返回結果資訊請查看SDK中的
APIDocument.md。若在使用中遇到問題,請諮詢Dataphin支援人員。
步驟一:環境準備
Dataphin服務Java SDK適用於JDK 1.8及以上版本。
您需要準備一對授權識別碼供SDK產生鑒權和簽名資訊,即AppKey和AppSecret。
AppKey和AppSecret可在服務 > 應用管理 > 我的應用程式列表中擷取。
重要AppKey和AppSecret是Dataphin服務認證使用者請求的密鑰,這兩個配置如果儲存在用戶端,請妥善加密。
在
pom.xml中添加如下依賴,如果添加dataphin-sdk-core-java報錯請手動添加該JAR檔案,路徑JAVA_SDK/lib/dataphin-sdk-core-java-v5.4.0.jar(即所擷取Java SDK中的Jar包)。說明dataphin-sdk-core-java並不存在於中央Maven倉庫,因此下載該SDK後還需要您上傳至貴公司的Maven倉庫,或者在IDEA、Eclipse中手動引入。<dependency> <groupId>com.alibaba.dt</groupId> <artifactId>dataphin-sdk-core-java</artifactId> <version>v5.4.0</version> </dependency>
步驟二:引入Java SDK的API介面調用類
在服務 > API市場 > API列表中下載對應的API文檔。
匯入
AsyncClientDemo.java,修正AsyncClientDemo.java類的import和package。package com.alibaba.dt.dataphin; import com.alibaba.cloudapi.sdk.enums.Scheme; import com.alibaba.cloudapi.sdk.model.ApiRequest; import com.alibaba.dt.dataphin.client.ApiClientBuilderParams; import com.alibaba.dt.dataphin.client.DataphinDataServiceException; import com.alibaba.dt.dataphin.client.async.AsyncApiCallBack; import com.alibaba.dt.dataphin.client.async.AsyncApiClient; import com.alibaba.dt.dataphin.client.async.AsyncJobContext; import com.alibaba.dt.dataphin.schema.AsyncQueryResults; import com.alibaba.dt.dataphin.schema.OrderBy; import com.alibaba.dt.dataphin.schema.QueryParamRequest; import com.alibaba.fastjson.JSONObject; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; /** * 非同步API樣本 * <p> * 使用方式: * 先配置好 HOST/APP_KEY/APP_SECRET/API_ID, * 再按需設定 getClient() 中的變數以及 packQueryParamRequest() 中的參數值 * 注意: * getClient() 中的參數可能會因不同的 api 而設定不同的值,可以將 getClient() 改造成帶有入參,以適應不同 api 使用不同的參數。 */ public class AsyncClientDemo { /** * 訪問網域名稱或ip,在資料服務的網路設定中獲得該值 */ private static final String HOST = "xxx"; /** * 應用appKey,即你用哪個APP來調用這個API */ private static final String APP_KEY = "xxx"; /** * 應用appSecret,即你用哪個APP來調用這個API */ private static final String APP_SECRET = "xxx"; /** * 配置調用的API編號 */ private static final String API_ID = "xxx"; /** * 每批次查詢條數,預設1000條 */ private static final Integer FETCH_SIZE = 1000; public static void main(String[] args) throws Exception { // 阻塞式調用 callAsyncApiBlock(); // 非阻塞式調用 callAsyncApiNotBlock(); } /** * 阻塞式調用 */ @SuppressWarnings("all") private static void callAsyncApiBlock() { // 擷取 AsyncApiClient 對象 AsyncApiClient asyncApiClient = getClient(); // 需要按需修改裡面的返回欄位、查詢條件等 QueryParamRequest queryParamRequest = packRequestParam(); try { AsyncQueryResults asyncQueryResults = asyncApiClient.listAsyncWaitFinish(API_ID, queryParamRequest); System.out.println(JSONObject.toJSONString(asyncQueryResults)); } catch (Throwable e) { e.printStackTrace(); } // 關閉用戶端,回收資源 asyncApiClient.shutdown(); } /** * 非阻塞式調用 */ @SuppressWarnings("all") private static void callAsyncApiNotBlock() { // 擷取 AsyncApiClient 對象 AsyncApiClient asyncApiClient = getClient(); // 需要按需修改裡面的返回欄位、查詢條件等 QueryParamRequest queryParamRequest = packRequestParam(); try { AsyncApiCallBack callback = new AsyncApiCallBack() { @Override public void onFailure(ApiRequest request, DataphinDataServiceException e) { System.out.println(e.getMessage()); } @Override public void onResponse(ApiRequest request, AsyncQueryResults results) { System.out.println(JSONObject.toJSONString(results)); } }; AsyncJobContext context = asyncApiClient.listAsync(API_ID, queryParamRequest, callback); // 請求成功會返回本次請求的jobId System.out.printf("jobId: %s", context.getJobId()); // 等待運行結束,真實情境請勿使用sleep方式等待 Thread.sleep(600000); } catch (Exception e) { e.printStackTrace(); } // 關閉用戶端,回收資源 asyncApiClient.shutdown(); } /** * 擷取 AsyncApiClient 對象 */ public static AsyncApiClient getClient() { ApiClientBuilderParams params = new ApiClientBuilderParams(); // 應用appKey params.setAppKey(APP_KEY); // 應用appSecret params.setAppSecret(APP_SECRET); // 訪問網域名稱或ip params.setHost(HOST); // 預設為http協議, 可根據API設定https協議 // 注意:Dataphin內建網關不支援https,阿里雲API Gateway支援https params.setScheme(Scheme.HTTP); // 每批次查詢條數,預設1000條 params.setFetchSize(FETCH_SIZE); // stage環境變數:PRE指定開發環境API、RELEASE指定生產環境API params.setStage("RELEASE"); // 如果使用次層網域或未指定環境的獨立網域名稱,需要設定env // 有 PROD 和 PRE 兩種值(如果是basic模式,傳PROD; 如果是Dev-Prod模式,PROD表示查生產環境資料,PRE表示查開發環境資料) // 如果已經指定了訪問環境的獨立網域名稱,則env參數不會起作用 params.setEnv("PROD"); return new AsyncApiClient(params); } /** * 封裝請求對象 */ private static QueryParamRequest packRequestParam() { QueryParamRequest queryParamRequest = new QueryParamRequest(); /********* API相關業務參數設定 begin *********/ /* * 代理帳號類型,非必填 * 注意,若要使用代理模式,需同時滿足以下條件: * 1. 開通行級許可權功能 * 2. 應用申請了代理許可權 * 3. API設定了關聯的行級許可權 * * 當使用代理模式認證時,需要指定代理使用者的帳號類型。 * ACCOUNT_NAME:Dataphin的使用者名稱。 * USER_ID:Dataphin內部的唯一ID。 * SOURCE_USER_ID:源系統帳號ID。 * 僅當設定了DelegationUid時,需要配置此參數。若未填寫此參數,則預設類型為USER_ID。 */ queryParamRequest.setAccountType("USER_ID"); /* * 代理帳號ID,非必填 * 被代理訪問的使用者,需根據所選AccountType的類型,傳入對應帳號ID。 * 設定該參數且API設定了關聯的行級許可權規則,會使用代理模式的認證方式。 */ queryParamRequest.setDelegationUid("abcd"); /* * 請求參數列表,非必填參數可不傳,必填參數必須傳,否則會報錯 * 其中key為對應的查詢欄位,value為查詢欄位對應的值 * 例如這裡的id為請求欄位名,1為id對應的值,可以設定多個查詢參數 * 注意:如果是 IN 類型的參數,使用 List 封裝參數值,例如這裡的age */ HashMap<String, Object> conditions = new HashMap<>(); conditions.put("id", 1); conditions.put("age", Arrays.asList(10,20,30)); queryParamRequest.setConditions(conditions); /* * 返回參數列表,必填 * 例如指定返回id和name * 注意:返回參數如果不存在或沒許可權會報錯 */ queryParamRequest.setReturnFields(Arrays.asList("id", "name")); /* * 排序欄位,非必填 * 注意oracle和sqlServer使用分頁需要同時使用排序 * 指定參數升序或者降序,可設定多個欄位進行升序或者降序 * 例如返回結果按id進行升序 */ List<OrderBy> orderList = new ArrayList<>(); orderList.add(new OrderBy("id1", OrderBy.Order.ASC)); orderList.add(new OrderBy("id2", OrderBy.Order.DESC)); queryParamRequest.setOrderBys(orderList); /* * API版本號碼,非必填,僅開發環境支援設定 */ queryParamRequest.setApiVersion("V1"); /********* API相關業務參數設定 end *********/ /********* 功能參數設定 begin *********/ /* * 是否保持欄位的大小寫格式,固定傳true */ queryParamRequest.setKeepColumnCase(true); /********* 功能參數設定 end *********/ return queryParamRequest; } }
步驟三:初始化通訊通道類
要調用API,首先要初始化用戶端。您可以參考AsyncClientDemo.java中getClient方法,使用對應的ApiClientBuilderParams類來進行初始化。其中,您需要將Host、APP_Key和APP_Secret三個變數進行替換。
步驟四:API介面說明
API介面類型
API介面類型分為LIST和GET,LIST支援分頁查詢而GET不支援,請參考
AsyncClientDemo.java中的packRequestParam方法,設定QueryParamRequest裡的參數。調用API介面
SDK中的LIST和GET方法為Dataphin資料服務的通用方法,SDK中同時提供同步和非同步調用方法。在調用API之前,您需要根據您在Dataphin資料服務定義的API填寫相關的請求參數。
調試用例中
conditions為業務請求參數,returnFields為API的返回參數,具體參數請參考服務 > 應用管理 > 已授權API服務頁面,單擊目標API操作列下調試,進入調試頁面。請求參數中的API_ID,請參考服務 > 應用管理 > 已授權API服務頁面API列下的API_ID。
Python SDK調用流程
步驟一:環境準備
Python SDK適用於Python3.9及以上版本。
Python SDK擷取方式如下:
在Dataphin首頁的頂部功能表列,選擇服務 > 應用管理。
在左側導覽列單擊調用說明。
單擊API調用樣本頁簽,單擊頁面右上方的python調用樣本下載按鈕,擷取Python SDK core包。
準備一對授權識別碼供SDK產生鑒權和簽名資訊,即AppKey和AppSecret。
重要AppKey和AppSecret是Dataphin服務認證使用者請求的密鑰,這兩個配置如果儲存在用戶端,請妥善加密。
準備一個JSON檔案,格式如下:
{ "host": "API Gateway網域名稱", "port": 80, "impalaConfig": { "pollingTimeout": 300, "pollingInterval": 800 }, "applicationConfig": { "appKey": "敏感性資料自行填充", "appSecret": "敏感性資料自行填充" }, "apiConfig": { "apiNo": 10008, "scheme": "HTTP", "stage": "RELEASE", "env": "PROD", "method": "LIST", // GET、LIST、CREATE、UPDATE、DELETE,區分大小寫 "queryParamRequest": { "conditions": {"id": "1"}, // 請求參數列表,根據參數決定,非必填參數可不傳,必填參數必須傳 "returnFields": ["id", "name", "age"], // 返回參數列表,必填,返回參數如果不存在或沒許可權會報錯 "orderBys": [{"field": "id", "order": "ASC"}], // 排序欄位,非必填 "useModelCache": "false", // 是否使用模型緩衝,開啟會減少同一個服務單元API相同出入參時的解析頻次,提高查詢效率 "useResultCache": "false", // 是否使用結果緩衝,開啟則會緩衝同一個API相同條件、相同返回欄位的查詢結果 "apiVersion": "V1", // API版本號碼,非必填,僅開發環境支援設定 "accountType": "USER_ID", // 代理帳號類型,非必填,使用代理模式時需要配置此參數 "delegationUid": "abcd" // 代理帳號ID,非必填,使用代理模式時需要配置此參數 }, "manipulationParamRequest": { "conditions": {"id": "1"}, // 資料量為“單條”的API的請求參數,非必填參數可不傳,必填參數必須傳 "batchConditions": [ // 資料量為“批量”的API的請求參數,非必填參數可不傳,必填參數必須傳 {"id": "1"}, {"id": "2"} ] } } }
步驟二:部署Python SDK
安裝Python開發工具PyCharm。
開啟Python專案。
在Demo類的啟動參數上配置JSON檔案路徑。
具體調用請參照demo.py。
步驟三:調用API
在JSON檔案中配置調用參數資訊。
Python SDK通過讀取JSON檔案來組裝API調用的基礎參數。
調用
apiClient.callApi方法,具體參照demo.py。# -*- coding: utf-8 -*- import dataapi import sys with open(str(sys.argv[1]), encoding="utf-8") as f: json_obj = eval(f.read().replace('\n\u200b', '')) # This is a JSON file for reading context. If you don't need a JSON file, just fill in the corresponding values directly # Gateway call address host = json_obj["host"] # Gateway call port port = json_obj["port"] # No configuration is required. Only valid for Impala type APIs, polling timeout pollingTimeout = json_obj["impalaConfig"]["pollingTimeout"] # No configuration is required. Only valid for Impala type APIs, polling interval pollingInterval = json_obj["impalaConfig"]["pollingInterval"] # Which app do you use to call this API for app information appKey = json_obj["applicationConfig"]["appKey"] appSecret = json_obj["applicationConfig"]["appSecret"] # Information about API apiId = json_obj["apiConfig"]["apiNo"] # How to call the API? The value is: HTTP or HTTPS. Note that the private gateway only supports HTTP [case sensitive] scheme = json_obj["apiConfig"]["scheme"] # Just write 'RELEASE' stage = json_obj["apiConfig"]["stage"] # There are two values: PROD and PRE (if in basic mode, PROD is passed to death; if in Dev Pro mode, PROD represents checking the production library, and PRE represents checking the development library [case sensitive]) env = json_obj["apiConfig"]["env"] # Query API Request parameters queryParam = json_obj["apiConfig"]["queryParamRequest"] # Manipulation API Request parameters manipulationParam = json_obj["apiConfig"]["manipulationParamRequest"] # Is the API GET/LIST/CREATE/UPDATE/DELETE? Distinguish between uppercase and lowercase letters method = json_obj["apiConfig"]["method"] if (host == None or host == ""): raise Exception("host is missing") if (appKey == None or appKey == ""): raise Exception("appKey is missing") if (appSecret == None or appSecret == ""): raise Exception("appSecret is missing") if (method == None or method == ""): raise Exception("method is missing") if (apiId == None or apiId == ""): raise Exception("apiNo is missing") # impala impalaConfig = dataapi.ImpalaConfig(pollingTimeout=pollingTimeout, pollingInterval=pollingInterval) # app appConfig = dataapi.AppConfig(appKey=appKey, appSecret=appSecret) apiConfig = dataapi.ApiConfig(apiId, scheme, stage, env, queryParam, method) myConfig = dataapi.MyConfig(host, port, impalaConfig, appConfig, apiConfig) apiClient = dataapi.ApiClient(myConfig) # sync query API request resp = apiClient.callApi(queryParam) print(resp) # async query API request asyncResp = apiClient.asyncCallApi(queryParam) print(asyncResp) # flux API request sseClient = dataapi.SseApiClient(myConfig) fluxResp = sseClient.fluxCallApi(queryParam) for item in fluxResp: print(item) # sync manipulation API request resp = apiClient.callApi(manipulationParam) print(resp)
白名單調用方式(僅私人化部署時支援)
通過配置白名單免密方式訪問API的安全性原則,可簡化API調用流程。IP白名單策略為應用層級策略,目前僅私人雲端支援此方式調用。
開發流程
步驟一:後台配置
您需要在資料服務中建立API、應用、應用白名單以及將應用和API進行綁定,才能通過白名單方式訪問API。
建立API:您可在服務 > API開發 > API服務的API頁面,選擇對應的方式建立API,詳情請參見建立API。
建立應用及應用白名單:應用可用於調用生產環境的API,並可為API設定白名單,如何建立應用及白名單,請參見建立及管理我的應用程式。
應用和API綁定:需申請該API的所屬應用許可權才能使用該API,如何申請,請參見管理API許可權。
步驟二:發起請求
請求類型:POST
只支援POST提交的請求,BODY一律使用JSON字串,並且Content-Type設定為
application/octet-stream; charset=utf-8。設定公用入參
參數名
位置
是否必填
樣本
說明
accept
Header
是
application/json; charset=utf-8
響應格式。
host
Header
是
gateway.aliyun.com
API Gateway網域名稱。
x-ca-key
Header
是
敏感性資料自行填充
appkey,調用API的身份標識。
x-ca-stage
Header
是
RELEASE
環境標識。
RELEASE訪問生產環境。
PRE訪問開發環境。
Content-Type
Header
是
application/octet-stream; charset=utf-8
請求格式。
whitelist-flag
Header
是
1
白名單標識(非空),固定傳1。
請求格式
URL:POST [host]/method/apiId?appKey=應用的AppKey&env=PROD
host:API Gateway網域名稱(可在服務 > 服務管理 > 網路設定頁面擷取)。
method:API的操作類型,GET/LIST/CREATE/UPDATE/DELETE(可在服務 > 應用管理> 已授權API服務 > 調試頁面擷取)。
apiId:API的唯一標識(可在服務 > 應用管理> 已授權API服務 > 調試頁面擷取)。
appKey:該API綁定的應用的唯一標識(可在服務 > 應用管理 > 我的應用程式頁面擷取)
env:環境標識,PROD表示訪問生產環境上的API,PRE表示訪問開發環境的API。
請求URL樣本:
gateway.aliyun.com/list/12345?appKey=xxx&env=PROD。
使用PostMan調用樣本
步驟一:請求地址
請求POST地址
[host]/method/apiId?appKey=應用的AppKey&env=PROD。步驟二:填入Header
填入Header,可參考設定公用入參填寫。
Header樣本如下:
accept:application/json;charset=utf-8 x-ca-key:敏感性資料自行填充 host:API Gateway網域名稱 x-ca-stage:RELEASE Content-Type:application/octet-stream;charset=utf-8 whitelist-flag:1步驟三:填入body
說明Content-Type使用
application/octet-stream; charset=utf-8。body樣本:
{ "conditions": {"id": "1"}, // 請求參數列表,根據參數決定,非必填參數可不傳,必填參數必須傳 "batchConditions": [{"id": "1"}], // 資料量為“批量”的操作類API的請求參數,非必填參數可不傳,必填參數必須傳 "returnFields": ["id", "name", "age"], // 返回參數列表,必填,返回參數如果不存在或沒許可權會報錯 "orderBys": [{"field": "id", "order": "ASC"}], // 排序欄位,非必填 "useModelCache": "false", // 是否使用模型緩衝,開啟會減少同一個服務單元API相同出入參時的解析頻次,提高查詢效率 "useResultCache": "false", // 是否使用結果緩衝,開啟則會緩衝同一個API相同條件、相同返回欄位的查詢結果 "apiVersion": "V1", // API版本號碼,非必填,僅開發環境支援設定 "accountType": "USER_ID", // 代理帳號類型,非必填,使用代理模式時需要配置此參數 "delegationUid": "abcd" // 代理帳號ID,非必填,使用代理模式時需要配置此參數 }
錯誤碼
用戶端錯誤
錯誤碼 | HTTP狀態代碼 | 語義 | 解決方案 |
Throttled by APP Flow Control | 403 | 因APP流控被限制 | 調用頻率過高導致被流控,可以聯絡服務提供者放寬限制。 |
Throttled by API Flow Control | 403 | 因API流控被限制 | 調用頻率過高導致被流控,可以聯絡服務提供者放寬限制。 |
Throttled by DOMAIN Flow Control | 403 | 因次層網域流控被限制 | 直接存取次層網域調用API,每天被訪問次數上限1000次。 |
TThrottled by GROUP Flow Control | 403 | 因分組流控被限制 | 調用頻率過高導致被流控,可以聯絡服務提供者放寬限制。 |
Empty Request Body | 400 | body為空白 | 請檢查請求Body內容。 |
Invalid Request Body | 400 | body無效 | 請檢查請求Body。 |
Invalid Param Location | 400 | 參數位置錯誤 | 請求參數位置錯誤。 |
Invalid Url | 400 | URL無效 | 請求的Method、Path或者環境不對。請參照錯誤說明Invalid URL。 |
Invalid Domain | 400 | 網域名稱無效 | 請求網域名稱無效,根據網域名稱找不到API。請聯絡 Dataphin服務團隊。 |
Invalid HttpMethod | 400 | HttpMethod無效 | 輸入的Method不合法。 |
Invalid AppKey | 400 | AppKey無效或不存在 | 請檢查傳入的AppKey。注意左右空格的影響。 |
Invalid AppSecret | 400 | APP的Secret錯誤 | 檢查傳入的AppSecret。注意左右空格的影響。 |
Timestamp Expired | 400 | 時間戳記過時 | 請核對請求系統時間是否為標準時間。 |
Invalid Timestamp | 400 | 時間戳記不合法 | 請參照請求籤名說明文檔。 |
Empty Signature | 404 | 簽名為空白 | 請傳入簽名字串,請參照請求籤名說明文檔。 |
Invalid Signature, Server StringToSign:%s | 400 | 簽名無效 | 簽名無效,參照Invalid Signature錯誤說明。 |
Invalid Content-MD5 | 400 | Content-MD5值不合法 | 請求Body為空白,但傳入了MD5值,或 MD5 值計算錯誤。請參照請求籤名說明文檔。 |
Unauthorized | 403 | 未被授權 | APP未獲得要調用的API的授權。請參照錯誤說明Unauthorized。 |
Nonce Used | 400 | SignatureNonce已被使用 | x-ca-nonce不能被重複使用,重建x-ca-nonce。 |
API Not Found | 400 | 找不到API | 傳入的API請求地址或者HttpMethod不正確,或已下線。 |
伺服器端錯誤(調用 API)
以下為API服務端錯誤。
錯誤碼 | HTTP狀態代碼 | 語義 | 解決方案 |
Internal Error | 500 | 內部錯誤 | 建議重試。 |
Failed To Invoke Backend Service | 500 | 底層服務錯誤 | API底層服務錯誤,建議重試。 |
Service Unavailable | 503 | 服務不可用 | 建議重試。 |
Async Service | 504 | 服務逾時 | 建議重試。 |
伺服器端錯誤(執行SQL語句)
錯誤碼 | 語義 |
DPN-OLTP-COMMON-000 | 成功。 |
DPN.Oltp.Common.Running | 運行中。 |
DPN-OLTP-COMMON-001 | 系統發生未知異常。 |
DPN-OLTP-COMMON-002 | 參數異常。 |
DPN-OLTP-COMMON-003 | 不支援。 |
DPN-OLTP-COMMON-004 | SQL解析異常。 |
DPN-OLTP-COMMON-005 | SQL注入檢測未通過。 |
DPN-OLTP-ENGINE-000 | 查詢逾時。 |
DPN-OLTP-ENGINE-001 | 參數錯誤。 |
DPN-OLTP-ENGINE-002 | 對象找不到。 |
DPN-OLTP-ENGINE-003 | 不支援。 |
DPN-OLTP-ENGINE-004 | 通訊表錯誤。 |
DPN-OLTP-ENGINE-005 | SQL解析失敗。 |
DPN-OLTP-ENGINE-006 | 中繼資料錯誤。 |
DPN-OLTP-ENGINE-007 | 參數處理錯誤。 |
DPN-OLTP-ENGINE-008 | 構建執行模型錯誤。 |
DPN-OLTP-ENGINE-009 | 執行失敗。 |
DPN-OLTP-ENGINE-010 | 資料來源錯誤。 |
DPN-OLTP-ENGINE-011 | HBase引擎不支援。 |
DPN-OLTP-ENGINE-012 | 對象序列化失敗。 |
DPN-OLTP-ENGINE-013 | 許可權校正失敗。 |
DPN-OLTP-ENGINE-014 | Elasticsearch引擎不支援。 |
DPN-OLTP-ENGINE-015 | MongoDB引擎不支援。 |
DPN-OLTP-ENGINE-016 | 欄位類型錯誤。 |
DPN-OLTP-ENGINE-017 | Redis緩衝異常。 |
DPN-OLTP-ENGINE-018 | 跨資料來源不支援。 |
DPN-OLTP-ENGINE-018-01 | 跨資料來源不支援Group by。 |
DPN-OLTP-ENGINE-018-02 | 跨資料來源不支援Order by。 |
DPN-OLTP-ENGINE-018-03 | 跨資料來源不支援沒有where條件。 |
DPN-OLTP-ENGINE-018-04 | 跨資料來源不支援page start不等於0。 |
DPN-OLTP-ENGINE-018-05 | 跨資料來源不支援在where條件中存在or操作。 |
DPN-OLTP-ENGINE-018-06 | 跨資料來源不支援在一個select item中有來自多個物理表的欄位。 |
DPN-OLTP-ENGINE-018-07 | 跨資料來源查詢必須所有的主鍵都在。 |
DPN-OLTP-ENGINE-019 | 資料類型編碼或者參數類型轉換失敗。 |
DPN-OLTP-ENGINE-20 | 熔斷。 |
DPN-OLTP-ENGINE-21 | 限流。 |
DPN-OLTP-ENGINE-22 | 查詢逾時。 |
DPN-OLTP-ENGINE-23 | 組合API的子API異常。 |
DPN-OLTP-ENGINE-24 | 無代理許可權。 |
DPN.Oltp.Auth | 許可權校正失敗。 |
DPN.Oltp.Async.JobNotExists | 非同步API任務不存在。 |
DPN.Oltp.Async.JobStatusNotSupport | 非同步API任務狀態不支援該操作。 |
DPN.Oltp.Async.GetResultError | 非同步API擷取結果失敗。 |
DPN.Oltp.Oltp.JsonContentParseError | JSON內容解析失敗。 |
DPN.Oltp.Oltp.HttpRequestError | HTTP請求失敗。 |
DPN.Oltp.Jdbc.ProjectForbidden | 無權修改該專案下的表。 |
DPN-OLTP-JDBC-001 | 要求標頭丟失Session。 |
DPN-OLTP-JDBC-002 | Session錯誤。 |
DPN-OLTP-JDBC-003 | 無權訪問資料庫。 |
DPN-OLTP-JDBC-004 | 無權訪問資料表。 |
DPN-OLTP-JDBC-005 | AccountId錯誤。 |
DPN-OLTP-JDBC-006 | 終止查詢。 |
DPN-OLTP-OLAP-001 | Olap用戶端查詢資料來源失敗。 |
DPN-OLTP-OLAP-002 | Olap用戶端運行失敗。 |
DPN.Oltp.Olap.SessionError | Olap的Session錯誤。 |
DPN.Oltp.Olap.SessionNotFound | Olap的Session不存在。 |
常見問題
問題1:調用API報404 回答:
如果綁定了獨立網域名稱,請檢查是HTTP協議還是HTTPS協議。
檢查調用的API的操作類型是否和API的一致,因為操作類型會作為URL的一部分,確保根據操作類型調用正確的方法。
檢查API是否發布到對應的環境。
問題2:調用API報400 回答:
請檢查
x-ca-timestamp是否在15分鐘的有效期間內,x-ca-nonce在15分鐘內是否被重複使用,建議每次請求API,x-ca-timestamp取目前時間,x-ca-nonce新產生可以用UUID產生,作為唯一標識,沒有格式要求。檢查使用AppKey、AppSecret是否前後有空格。
檢查調用的API是否已授權,並且授權的APP的AppKey、Secret和參數APP_KEY、APP_SECRET是否一致。
注意檢查用戶端的簽名值是否多加了空格,傳給服務端的沒有加(Invalid Signature),檢查
stringToSign中的值是否有空格,如用戶端簽名Content-Type:application/octet-stream; charset=utf-8有空格,但是傳給服務端的沒有空格Content-Type:application/octet-stream;charset=utf-8,就會報錯Invalid Signature。
問題3:調用API報403
回答:
檢查API配置的調用協議是HTTP還是HTTPS,在代碼中設定為對應的參數。
檢查AppKey和AppSecret是否正確。
檢查調用的API的操作類型是否和API的一致,因為操作類型會作為URL的一部分,確保根據操作類型調用正確的方法。
問題4:調用API報錯:return fields missing in param
回答:在packRequestParam方法中,按下面方式設定參數:
List<String> returnFields = Lists.newArrayList("api的返回欄位1","api的返回欄位2",..."api的返回欄位n");
queryParamRequest.setReturnFields(returnFields);問題5:如何使用operator為IN的參數
回答:在SDK調用時,IN類型的參數需要使用LIST傳遞參數值,例如:
假設參數名為p1,參數類型為String或Date,參數值為a、b、c,則應按下面方式設定參數:
Map<String, Object> conditions = Maps.newHashMap();
conditions.put("p1",Lists.newArrayList("a", "b", "c"));如果是數實值型別,參數值為1、2、3,則應按下面方式設定參數:
Map<String, Object> conditions = Maps.newHashMap();
conditions.put("p1",Lists.newArrayList(1,2,3));問題6:使用SDK分頁擷取資料時,資料總數正確,但存在重複資料
原因:API代碼中未使用排序欄位使每次的排序結果唯一,或資料庫本身不支援排序,導致每次分頁擷取資料時的查詢結果的排序不一致,導致重複擷取資料或遺失資料。
回答:確保返回結果排序的穩定性。若有主鍵,可增加主鍵欄位排序,如果沒有主鍵,使用多個欄位組成聯合主鍵排序,確保每次排序的結果是穩定的。
問題7:使用SDK分頁擷取資料時,如何設定參數返回總數
回答:在packRequestParam方法中,按下面方式設定參數:
// 是否返回總數(用於支援分頁的api查詢)
queryParamRequest.setReturnTotalNum(false);