使用说明

本文为您介绍如何下载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下载

您可以通过OSSGitHubMaven库获取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页面对源代码进行改进。使用IssuesPull 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.timezoneProperty。取值说明:

    • 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每次请求的连接超时时间为connectTimeoutreadTimeout之和,即默认是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生效)

    • 基本配置

    • URL key

      Property Key

      是否必选

      描述

      interactiveMode

      interactive_mode

      是否开启MCQA。取值说明:

      • False(默认值):不开启。

      • True:开启。

      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。

    • 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。

连接MaxCompute

  1. 加载MaxCompute JDBC驱动。

    Class.forName("com.aliyun.odps.jdbc.OdpsDriver");
  2. 通过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的创建和查看,请参见准备阿里云账号

  3. 执行查询。

    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 tableshow tablesshow partitions三个常用命令。