本文为您介绍如何下载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
三个常用命令。