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

您可以通过GitHubMaven库获取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参数说明

建议使用 java.net.URLEncoder#encode(java.lang.String)对URL中的键和值进行编码。

  • 基本参数。
    URLProperties描述是否必选默认值
    endpointend_pointMaxCompute服务的Endpoint。
    projectproject_nameMaxCompute项目名称。
    accessIdaccess_id阿里云账号的AccessKey ID。
    accessKeyaccess_key阿里云账号的AccessKey Secret。
    interactiveModeinteractive_mode启用MCQA。False
    logviewlogview_hostMaxCompute Logview的Endpoint。由MaxCompute提供
    tunnelEndpointtunnel_endpointMaxCompute Tunnel服务的Endpoint。由MaxCompute提供
    enableOdpsLoggerenable_odps_logger启用MaxCompute JDBC Logger。False
  • 高级参数。
    URLProperties描述是否必选默认值
    stsTokensts_token阿里云STS令牌。
    logConfFilelog_conf_fileSLF4J的配置路径。
    charsetcharset输入和输出的字符集。UTF-8
    executeProjectexecute_project_name以MCQA模式运行,实际执行查询的MaxCompute项目名称。
    alwaysFallbackalways_fallback以MCQA模式运行,如果发生任何异常,控制是否退回到常规模式(非MCQA模式)重新执行。False(无自动回退)
    instanceTunnelMaxRecordinstance_tunnel_max_record以MCQA模式运行且有下载权限时,允许查询展现的结果集最大行数,如果基于JDBC导出,此参数也控制导出行数。若使该项生效,enableLimit选项应设置为false。-1(不限制)
    instanceTunnelMaxSizeinstance_tunnel_max_size以MCQA模式运行且有下载权限时,允许查询展现的结果集大小,如果基于JDBC导出,此参数也控制导出大小。若使该项生效,enableLimit应设置为false-1(不限制)
    enableLimitenable_limit以MCQA模式运行,如果enableLimit设置为true,则结果超过10000行时,不会检查下载权限,但是您的查询结果集记录数将限制为10000。如果设置为false,结果小于10000行的情况下,不会校验权限,超过则校验下载权限。True(不检查下载权限但限制行数)

连接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
    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";
    
        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>",
                "aliyun accessId", "aliyun 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";
    
        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>",
                "aliyun accessId", "aliyun 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";
    
        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>",
                "aliyun accessId", "aliyun 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();
        }
    }
  • 查询表
    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";
    
        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>",
                "aliyun accessId", "aliyun 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));
            }
        }
    }