本文為您介紹如何下載JDBC和串連MaxCompute,並提供範例程式碼。
注意事項
通過MaxCompute JDBC驅動執行SQL並擷取結果,需要執行帳號滿足以下要求:
是專案空間的成員。
有專案空間的CreateInstance許可權。
有目標表的Select和Download許可權。
說明1.9及之前版本的MaxCompute JDBC驅動對每個查詢都會建立暫存資料表,並通過Tunnel從暫存資料表擷取結果。您使用這些版本的JDBC需要具備CreateTable許可權。
2.2及之後版本的MaxCompute JDBC驅動不再建立暫存資料表,直接通過Instance Tunnel擷取查詢結果,沒有CreateTable許可權要求限制。
MaxCompute許可權詳情請參見MaxCompute許可權。
MaxCompute提供了資料保護功能。當資料保護模式開啟時,您無法將資料轉移到專案空間之外。2.4之前版本的JDBC無法擷取
result set
。2.4及之後版本的JDBC可以獲得不超過READ_TABLE_MAX_ROW所定義行數的資料,詳情請參見專案空間操作。資料保護功能詳情請參見資料保護機制。MaxCompute 2.0資料類型版本支援較多資料類型,例如TINYINT、SMALLINT、DATETIME、TIMESTAMP、ARRAY、MAP和STRUCT等。您如果需要使用這些新類型,在執行SQL之前需要執行以下語句,開啟MaxCompute 2.0資料類型開關。詳情請參見資料類型版本說明。
set odps.sql.type.system.odps2=true
JDBC下載
您可以通過OSS、GitHub或Maven庫擷取MaxCompute各版本的JAR包。推薦您下載包含完整依賴jar-with-dependencies的JAR包。
通過Maven方式使用MaxCompute JDBC的專案物件模型POM(Project Object Model)的樣本如下。
<dependency>
<groupId>com.aliyun.odps</groupId>
<artifactId>odps-jdbc</artifactId>
<version>3.3.6</version>
<classifier>jar-with-dependencies</classifier>
</dependency>
MaxCompute JDBC驅動是開原始碼專案,專案地址為aliyun-odps-jdbc。
MaxCompute歡迎您參與JDBC驅動的開發和改進工作。您可以在該專案的Issues頁面反饋問題,或通過Pull requests頁面對原始碼進行改進。使用Issues及Pull requests時,請您遵循開源專案的模板要求。
JDBC參數說明
JDBC可以通過URL參數和Properties參數進行配置,其中Properties參數的優先順序高於URL參數。
如果URL key中包含odps_config=config_file
,則會讀取config_file
作為Properties參數。
基本參數。
URL key
Property Key
是否必選
描述
project
project_name
是
MaxCompute專案名稱。
accessId
access_id
是
阿里雲帳號的AccessKey ID。
您可以進入AccessKey管理頁面擷取AccessKey ID。
accessKey
access_key
是
阿里雲帳號的AccessKey Secret。
您可以進入AccessKey管理頁面擷取AccessKey Secret。
logview
logview_host
否
MaxCompute Logview地址。固定取值為:
http://logview.odps.aliyun.com
。tunnelEndpoint
tunnel_endpoint
否
MaxCompute Tunnel服務的Endpoint。
各地區及網路對應的Tunnel Endpoint值,請參見Endpoint。
日誌配置參數。
URL key
Property Key
是否必選
描述
enableOdpsLogger
enable_odps_logger
否
是否啟用MaxCompute JDBC Logger。取值說明:
False(預設值):不啟用,JDBC將不記錄日誌到檔案中。
True:啟用,將會在JDBC的jar包所在目錄
jdbc.log
檔案中記錄日誌。
logConfFile
log_conf_file
否
可以額外指定SLF4J設定檔,靈活配置日誌輸出(比如指定輸出檔案、輸出logLevel 等)。這種方式需要在專案的
pom.xml
檔案中添加依賴:<dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency>
配置樣本,請參見設定檔樣本。
logLevel
log_level
否
輸出的記錄層級,預設值為:INFO。
其他參數
URL key
Property Key
是否必選
描述
stsToken
sts_token
否
阿里雲STS令牌。
charset
charset
否
輸入和輸出的字元集,預設值為:UTF-8。
useProjectTimeZone
use_project_time_zone
否
是否使用project的
odps.sql.timezone
Property。取值說明:False(預設值):不使用。
True:使用。
說明Statement中也可以通過
set odps.sql.timezone=xxx
來指定,優先順序順序為Statement > project > null。
disableConnectinosSetting
disable_connection_setting
否
是否允許設定一個 Connection的SQL參數。取值說明:
False(預設值):不允許。
True:允許。
如果允許,在Statement中執行
set xxx
命令時,會同時設定對應Statement和Connection的SQL參數。否則,只會設定對應Statement的參數。settings
settings
否
全域預設
sql setting
,使用JSON格式傳入,例如{"key":"value"}
。tableList
table_list
否
MaxCompute中表名稱。格式為:
projectname.tablename,projectname1.tablename1
。connectTimeout
connect_timeout
否
底層網路建立串連的逾時時間,預設為:10秒(s)。
readTimeout
read_timeout
否
底層網路連接讀取資料的逾時時間,預設為:120秒(s)。
說明RESTful API每次請求的連線逾時時間為connectTimeout和readTimeout之和,即預設是130秒(s),預設重試次數是3次。
想要調整RESTful API連線逾時時間,修改readTimeout參數即可。
enableCommandApi
enable_command_api
否
是否使用commandAPI。取值說明:
False(預設值):不使用。
True:使用。
如果使用,則可以在JDBC中執行一些僅在odpscmd中執行的命令。
httpsCheck
https_check
否
是否進行HTTPS認證驗證。取值說明:
False(預設值):不驗證。
True:驗證。
tunnelConnectTimeout
tunnel_connect_timeout
否
使用tunnel下載資料時,tunnel的連線逾時時間,預設為:180秒(s)。
tunnelReadTimeout
tunnel_read_timeout
否
使用tunnel下載資料時,tunnel的讀取資料逾時時間,預設為:300秒(s)。
Non-MCQA 相關參數(僅離線模式生效)
URL key
Property Key
是否必選
描述
autoLimitFallback
auto_limit_fallback
否
自動限制回退。取值說明:
False(預設值):不回退。
True:回退,在離線模式下,tunnel報
no download permission
異常時自動回退,限制下載數為10000。
MCQA相關(僅MCQA生效)
基本配置
False(預設值):不開啟。
True:開啟。
Limit相關參數
URL key
Property Key
是否必選
描述
instanceTunnelMaxRecord
instance_tunnel_max_record
否
結果集的最大記錄數。
說明只有當enableLimit參數設定為False時,該參數才會生效。
instanceTunnelMaxSize
instance_tunnel_max_size
否
結果集的最大大小,單位:位元組(Byte)。
autoSelectLimit
auto_select_limit
否
自動查詢限制。
阿里公用雲端的彈性計算環境,預設查詢最多100萬行,若您需要查看更多資料時,可以配置此參數。
說明只有當enableLimit參數設定為False時,該參數才會生效。
JDBC v3.2.29版本後,設定 autoSelectLimit參數後,enableLimit會自動化佈建為False。
您可以在SQL setting中,添加
odps.sql.select.auto.limit
,SQL作業執行時,該參數會預設生效。
enableLimit
enable_limit
否
是否啟用限制。取值說明:
False:不啟用。
True(預設值):啟用。
啟用後下載許可權將不被檢查,並且結果記錄數量預設最大限制為10000條。
Fallback相關參數
URL key
Property Key
是否必選
描述
fallbackForUnknownError
fallback_for_unknownerror
否
發生未知錯誤時是否回退到離線模式。取值說明:
False:不回退。
True(預設值):回退。
fallbackForResourceNotEnough
fallback_for_resourcenotenough
否
資源不足時是否回退到離線模式。取值說明:
False:不回退。
True(預設值):回退。
fallbackForUpgrading
fallback_for_upgrading
否
升級期間是否回退到離線模式。取值說明:
False:不回退。
True(預設值):回退。
fallbackForRunningTimeout
fallback_for_runningtimeout
否
執行操作命令逾時時是否回退到離線模式。取值說明:
False:不回退。
True(預設值):回退。
fallbackForUnsupportedFeature
fallbackForUnsupportedFeature
否
遇到MCQA不支援的情境時是否回退到離線模式。取值說明:
False:不回退。
True(預設值):回退。
alwaysFallback
always_fallback
否
在以上幾種情境下,是否全部回退到離線模式。取值說明:
False(預設值):不回退。
True:回退。
說明該參數僅在JDBC v3.2.3及以上版本有效。
disableFallback
disable_fallback
否
在以上幾種情境下,是否均不回退到離線模式。取值說明:
False(預設值):回退。
True:不回退。
fallbackQuota
fallback_quota
否
MCQA作業回退時選擇的Quota名稱,不配置使用MaxCompute專案預設Quota。
URL key
Property Key
是否必選
描述
interactiveMode
interactive_mode
否
是否開啟MCQA。取值說明:
executeProject
execute_project_name
否
實際執行SQL任務的MaxCompute專案名稱。
tunnelRetryTime
tunnel_retry_time
否
SQLExecutor設定tunnel重試次數,預設為6次。
attachTimeout
attach_timeout
否
建立MCQA串連的逾時時間,預設為60秒(s)。
fallbackQuota
fallback_quota
否
MCQA作業回退時選擇的Quota,不配置使用MaxCompute專案的預設Quota。
串連MaxCompute
載入MaxCompute JDBC驅動。
Class.forName("com.aliyun.odps.jdbc.OdpsDriver");
通過DriverManager建立Connection。
Connection cnct = DriverManager.getConnection(url, accessId, accessKey);
url:格式為
jdbc:odps:<maxcompute_endpoint>?project=<maxcompute_project_name>[&useProjectTimeZone={true|false}]
。其中:<maxcompute_endpoint>:MaxCompute服務所在地區的Endpoint。例如,華東1(杭州)地區的外網Endpoint為
http://service.cn-hangzhou.maxcompute.aliyun.com/api
。Endpoint的配置資訊詳情請參見Endpoint。<maxcompute_project_name>:MaxCompute專案空間名稱。
useProjectTimeZone:是否使用MaxCompute專案空間的時區。
命令樣本如下。
jdbc:odps:http://service.cn-hangzhou.maxcompute.aliyun.com/api?project=test_project&useProjectTimeZone=true;
accessId:建立專案空間的AccessKey ID。
accessKey:建立專案空間的AccessKey ID對應的AccessKey Secret。
說明AccessKey ID和AccessKey Secret的建立和查看,請參見準備阿里雲帳號。
執行查詢。
Statement stmt = cnct.createStatement(); ResultSet rset = stmt.executeQuery("SELECT foo FROM bar"); while (rset.next()) { // process the results } rset.close(); stmt.close(); cnct.close();
範例程式碼
刪除表、建立表和擷取Metadata
說明如果專案中使用了JDBC依賴,則不需要指定SDK依賴,設定了JDBC依賴後,會自動引入SDK。否則程式可能會因為版本不統一導致運行報錯。
import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class Main { private static final String DRIVER_NAME = "com.aliyun.odps.jdbc.OdpsDriver"; // 阿里雲帳號AccessKey擁有所有API的存取權限,風險很高。強烈建議您建立並使用RAM使用者進行API訪問或日常營運,請登入RAM控制台建立RAM使用者 // 此處以把AccessKey和AccessKeySecret儲存在環境變數為例說明。您也可以根據業務需要,儲存到設定檔裡 // 強烈建議不要把AccessKey和AccessKeySecret儲存到代碼裡,會存在密鑰泄漏風險 private static String accessId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"); private static String accessKey = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"); public static void main(String[] args) throws SQLException { try { Class.forName(DRIVER_NAME); } catch (ClassNotFoundException e) { e.printStackTrace(); System.exit(1); } Connection conn = DriverManager.getConnection( "jdbc:odps:<maxcompute_endpoint>?project=<maxcompute_project>", Main.accessId, Main.accessKey); // create a table Statement stmt = conn.createStatement(); final String tableName = "jdbc_test"; stmt.execute("DROP TABLE IF EXISTS " + tableName); stmt.execute("CREATE TABLE " + tableName + " (key BIGINT, value STRING)"); // get meta data DatabaseMetaData metaData = conn.getMetaData(); System.out.println("product = " + metaData.getDatabaseProductName()); System.out.println("jdbc version = " + metaData.getDriverMajorVersion() + ", " + metaData.getDriverMinorVersion()); ResultSet tables = metaData.getTables(null, null, tableName, null); while (tables.next()) { String name = tables.getString("TABLE_NAME"); System.out.println("inspecting table: " + name); ResultSet columns = metaData.getColumns(null, null, name, null); while (columns.next()) { System.out.println( columns.getString("COLUMN_NAME") + "\t" + columns.getString("TYPE_NAME") + "(" + columns.getInt("DATA_TYPE") + ")"); } columns.close(); } tables.close(); stmt.close(); conn.close(); } }
返回結果樣本如下。
product = MaxCompute/ODPS jdbc version = 3, 0 inspecting table: jdbc_test key BIGINT(-5) value STRING(12)
更新表
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; public class Main { private static final String DRIVER_NAME = "com.aliyun.odps.jdbc.OdpsDriver"; // 阿里雲帳號AccessKey擁有所有API的存取權限,風險很高。強烈建議您建立並使用RAM使用者進行API訪問或日常營運,請登入RAM控制台建立RAM使用者 // 此處以把AccessKey和AccessKeySecret儲存在環境變數為例說明。您也可以根據業務需要,儲存到設定檔裡 // 強烈建議不要把AccessKey和AccessKeySecret儲存到代碼裡,會存在密鑰泄漏風險 private static String accessId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"); private static String accessKey = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"); public static void main(String[] args) throws SQLException { try { Class.forName(DRIVER_NAME); } catch (ClassNotFoundException e) { e.printStackTrace(); System.exit(1); } Connection conn = DriverManager.getConnection( "jdbc:odps:<maxcompute_endpoint>?project=<maxcompute_project>", Main.accessId, Main.accessKey); Statement stmt = conn.createStatement(); // The following DML also works //String dml = "INSERT INTO jdbc_test SELECT 1, \"foo\""; String dml = "INSERT INTO jdbc_test VALUES(1, \"foo\")"; int ret = stmt.executeUpdate(dml); assert ret == 1; stmt.close(); conn.close(); } }
批次更新表
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; public class Main { private static final String DRIVER_NAME = "com.aliyun.odps.jdbc.OdpsDriver"; // 阿里雲帳號AccessKey擁有所有API的存取權限,風險很高。強烈建議您建立並使用RAM使用者進行API訪問或日常營運,請登入RAM控制台建立RAM使用者 // 此處以把AccessKey 和 AccessKeySecret 儲存在環境變數為例說明。您也可以根據業務需要,儲存到設定檔裡 // 強烈建議不要把 AccessKey 和 AccessKeySecret 儲存到代碼裡,會存在密鑰泄漏風險 private static String accessId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"); private static String accessKey = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"); public static void main(String[] args) throws SQLException { try { Class.forName(DRIVER_NAME); } catch (ClassNotFoundException e) { e.printStackTrace(); System.exit(1); } Connection conn = DriverManager.getConnection( "jdbc:odps:<maxcompute endpoint>?project=<maxcompute project>", Main.accessId, Main.accessKey); PreparedStatement pstmt = conn.prepareStatement("INSERT INTO jdbc_test VALUES(?, ?)"); pstmt.setLong(1, 1L); pstmt.setString(2, "foo"); pstmt.addBatch(); pstmt.setLong(1, 2L); pstmt.setString(2, "bar"); pstmt.addBatch(); int[] ret = pstmt.executeBatch(); assert ret[0] == 1; assert ret[1] == 1; pstmt.close(); conn.close(); } }
說明executeBatch方法不適用於Cluster表的批量資料寫入,例如Transaction Table2.0表。
若對普通分區表進行批量資料寫入,需要在INSERT INTO語句中指定分區。樣本如下:
-- 分區表sale_detail的建表語句如下。 create table if not exists sale_detail ( shop_name string, customer_id string, total_price double ) partitioned by (sale_date string, region string); -- 假設已有分區sale_date='20240219', region='hangzhou',則對分區表進行批量資料寫入時,INSERT INTO語句如下。 INSERT INTO sale_detail PARTITION(sale_date='20240219', region='hangzhou') VALUES(?, ?, ?)
查詢表
import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class Main { private static final String DRIVER_NAME = "com.aliyun.odps.jdbc.OdpsDriver"; // 阿里雲帳號AccessKey擁有所有API的存取權限,風險很高。強烈建議您建立並使用RAM使用者進行API訪問或日常營運,請登入RAM控制台建立RAM使用者 // 此處以把AccessKey 和 AccessKeySecret 儲存在環境變數為例說明。您也可以根據業務需要,儲存到設定檔裡 // 強烈建議不要把 AccessKey 和 AccessKeySecret 儲存到代碼裡,會存在密鑰泄漏風險 private static String accessId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"); private static String accessKey = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"); public static void main(String[] args) throws SQLException { try { Class.forName(DRIVER_NAME); } catch (ClassNotFoundException e) { e.printStackTrace(); System.exit(1); } Connection conn = DriverManager.getConnection( "jdbc:odps:<maxcompute endpoint>?project=<maxcompute project>", Main.accessId, Main.accessKey); ResultSet rs; Statement stmt = conn.createStatement(); String sql = "SELECT * FROM JDBC_TEST"; stmt.executeQuery(sql); ResultSet rset = stmt.getResultSet(); while (rset.next()) { System.out.println(String.valueOf(rset.getInt(1)) + "\t" + rset.getString(2)); } } }
說明OdpsStatement支援
execute(sql)
、executeQuery(sql)
和executeUpdate(sql)
三個方法。其中execute(sql)
和executeQuery(sql)
方法支援desc table
、show tables
和show partitions
三個常用命令。