本文為您介紹如何下載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
三個常用命令。