本文为您介绍如何下载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下载
您可以通过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参数说明
建议使用 java.net.URLEncoder#encode(java.lang.String)
对URL中的键和值进行编码。
- 基本参数。
URL Properties 描述 是否必选 默认值 endpoint end_point MaxCompute服务的Endpoint。 是 无 project project_name MaxCompute项目名称。 是 无 accessId access_id 阿里云账号的AccessKey ID。 是 无 accessKey access_key 阿里云账号的AccessKey Secret。 是 无 interactiveMode interactive_mode 启用MCQA。 否 False logview logview_host MaxCompute Logview的Endpoint。 否 由MaxCompute提供 tunnelEndpoint tunnel_endpoint MaxCompute Tunnel服务的Endpoint。 否 由MaxCompute提供 enableOdpsLogger enable_odps_logger 启用MaxCompute JDBC Logger。 否 False - 高级参数。
URL Properties 描述 是否必选 默认值 stsToken sts_token 阿里云STS令牌。 否 无 logConfFile log_conf_file SLF4J的配置路径。 否 无 charset charset 输入和输出的字符集。 否 UTF-8 executeProject execute_project_name 以MCQA模式运行,实际执行查询的MaxCompute项目名称。 否 无 alwaysFallback always_fallback 以MCQA模式运行,如果发生任何异常,控制是否退回到常规模式(非MCQA模式)重新执行。 否 False(无自动回退) instanceTunnelMaxRecord instance_tunnel_max_record 以MCQA模式运行且有下载权限时,允许查询展现的结果集最大行数,如果基于JDBC导出,此参数也控制导出行数。若使该项生效,enableLimit选项应设置为false。 否 -1(不限制) instanceTunnelMaxSize instance_tunnel_max_size 以MCQA模式运行且有下载权限时,允许查询展现的结果集大小,如果基于JDBC导出,此参数也控制导出大小。若使该项生效,enableLimit应设置为false 否 -1(不限制) enableLimit enable_limit 以MCQA模式运行,如果enableLimit设置为true,则结果超过10000行时,不会检查下载权限,但是您的查询结果集记录数将限制为10000。如果设置为false,结果小于10000行的情况下,不会校验权限,超过则校验下载权限。 否 True(不检查下载权限但限制行数)
连接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;
- <maxcompute_endpoint>:MaxCompute服务所在区域的Endpoint。例如,华东1(杭州)区域的外网Endpoint为
- accessId:创建项目空间的AccessKey ID。
- accessKey:创建项目空间的AccessKey ID对应的AccessKey Secret。 说明 AccessKey ID和AccessKey Secret的创建和查看,请参见准备阿里云账号。
- url:格式为
- 执行查询。
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)); } } }