华为云用户手册

  • java.sql.PreparedStatement java.sql.PreparedStatement是预处理语句接口。 表5 对java.sql.PreparedStatement的支持情况 方法名 返回值类型 支持JDBC 4 clearParameters() void Yes execute() boolean Yes executeQuery() ResultSet Yes executeUpdate() int Yes getMetaData() ResultSetMetaData Yes setBoolean(int parameterIndex, boolean x) void Yes setBigDecimal(int parameterIndex, BigDecimal x) void Yes setByte(int parameterIndex, byte x) void Yes setBytes(int parameterIndex, byte[] x) void Yes setDate(int parameterIndex, Date x) void Yes setDouble(int parameterIndex, double x) void Yes setFloat(int parameterIndex, float x) void Yes setInt(int parameterIndex, int x) void Yes setLong(int parameterIndex, long x) void Yes setNString(int parameterIndex, String value) void Yes setShort(int parameterIndex, short x) void Yes setString(int parameterIndex, String x) void Yes addBatch() void Yes executeBatch() int[] Yes clearBatch() void Yes addBatch()、execute()必须在clearBatch()之后才能执行。 调用executeBatch()方法并不会清除batch。用户必须显式使用clearBatch()清除 。 在添加了一个batch的绑定变量后,用户若想重用这些值(再次添加一个batch),无需再次使用set*()方法 。 以下方法是从java.sql.Statement继承而来:close,execute,executeQuery,executeUpdate,getConnection,getResultSet,getUpdateCount,isClosed,setMaxRows, setFetchSize。
  • java.sql.ResultSet java.sql.ResultSet是执行结果集接口。 表6 对java.sql.ResultSet的支持情况 方法名 返回值类型 支持JDBC 4 findColumn(String columnLabel) int Yes getBigDecimal(int columnIndex) BigDecimal Yes getBigDecimal(String columnLabel) BigDecimal Yes getBoolean(int columnIndex) boolean Yes getBoolean(String columnLabel) boolean Yes getByte(int columnIndex) byte Yes getBytes(int columnIndex) byte[] Yes getByte(String columnLabel) byte Yes getBytes(String columnLabel) byte[] Yes getDate(int columnIndex) Date Yes getDate(String columnLabel) Date Yes getDouble(int columnIndex) double Yes getDouble(String columnLabel) double Yes getFloat(int columnIndex) float Yes getFloat(String columnLabel) float Yes getInt(int columnIndex) int Yes getInt(String columnLabel) int Yes getLong(int columnIndex) long Yes getLong(String columnLabel) long Yes getShort(int columnIndex) short Yes getShort(String columnLabel) short Yes getString(int columnIndex) String Yes getString(String columnLabel) String Yes getTime(int columnIndex) Time Yes getTime(String columnLabel) Time Yes getTimestamp(int columnIndex) Timestamp Yes getTimestamp(String columnLabel) Timestamp Yes isAfterLast() boolean Yes isBeforeFirst() boolean Yes isFirst() boolean Yes next() boolean Yes 一个Statement不能有多个处于“open”状态的ResultSet。 用于遍历结果集(ResultSet)的游标(Cursor)在被提交后不能保持“open”的状态。
  • java.sql.DatabaseMetaData java.sql.DatabaseMetaData是数据库对象定义接口。 表3 对java.sql.DatabaseMetaData的支持情况 方法名 返回值类型 支持JDBC 4 getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) ResultSet Yes getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) ResultSet Yes getTableTypes() ResultSet Yes getUserName() String Yes isReadOnly() boolean Yes nullsAreSortedHigh() boolean Yes nullsAreSortedLow() boolean Yes nullsAreSortedAtStart() boolean Yes nullsAreSortedAtEnd() boolean Yes getDatabaseProductName() String Yes getDatabaseProductVersion() String Yes getDriverName() String Yes getDriverVersion() String Yes getDriverMajorVersion() int Yes getDriverMinorVersion() int Yes usesLocalFiles() boolean Yes usesLocalFilePerTable() boolean Yes supportsMixedCaseIdentifiers() boolean Yes storesUpperCaseIdentifiers() boolean Yes storesLowerCaseIdentifiers() boolean Yes supportsMixedCaseQuotedIdentifiers() boolean Yes storesUpperCaseQuotedIdentifiers() boolean Yes storesLowerCaseQuotedIdentifiers() boolean Yes storesMixedCaseQuotedIdentifiers() boolean Yes supportsAlterTableWithAddColumn() boolean Yes supportsAlterTableWithDropColumn() boolean Yes supportsColumnAliasing() boolean Yes nullPlusNonNullIsNull() boolean Yes supportsConvert() boolean Yes supportsConvert(int fromType, int toType) boolean Yes supportsTableCorrelationNames() boolean Yes supportsDifferentTableCorrelationNames() boolean Yes supportsExpressionsInOrderBy() boolean Yes supportsOrderByUnrelated() boolean Yes supportsGroupBy() boolean Yes supportsGroupByUnrelated() boolean Yes supportsGroupByBeyondSelect() boolean Yes supportsLikeEscapeClause() boolean Yes supportsMultipleResultSets() boolean Yes supportsMultipleTransactions() boolean Yes supportsNonNullableColumns() boolean Yes supportsMinimumSQLGrammar() boolean Yes supportsCoreSQLGrammar() boolean Yes supportsExtendedSQLGrammar() boolean Yes supportsANSI92EntryLevelSQL() boolean Yes supportsANSI92IntermediateSQL() boolean Yes supportsANSI92FullSQL() boolean Yes supportsIntegrityEnhancementFacility() boolean Yes supportsOuterJoins() boolean Yes supportsFullOuterJoins() boolean Yes supportsLimitedOuterJoins() boolean Yes isCatalogAtStart() boolean Yes supportsSchemasInDataManipulation() boolean Yes supportsSavepoints() boolean Yes supportsResultSetHoldability(int holdability) boolean Yes getResultSetHoldability() int Yes getDatabaseMajorVersion() int Yes getDatabaseMinorVersion() int Yes getJDBCMajorVersion() int Yes getJDBCMinorVersion() int Yes
  • java.sql.Connection java.sql.Connection是数据库连接接口。 表1 对java.sql.Connection接口的支持情况 方法名 返回值类型 支持JDBC 4 close() void Yes commit() void Yes createStatement() Statement Yes getAutoCommit() boolean Yes getClientInfo() Properties Yes getClientInfo(String name) String Yes getTransactionIsolation() int Yes isClosed() boolean Yes isReadOnly() boolean Yes prepareStatement(String sql) PreparedStatement Yes rollback() void Yes setAutoCommit(boolean autoCommit) void Yes setClientInfo(Properties properties) void Yes setClientInfo(String name,String value) void Yes 接口内部默认使用自动提交模式,若通过setAutoCommit(false)关闭自动提交,将会导致后面执行的语句都受到显式事务包裹,数据库中不支持事务中执行的语句不能在此模式下执行。
  • java.sql.CallableStatement java.sql.CallableStatement是存储过程执行接口。 表2 对java.sql.CallableStatement的支持情况 方法名 返回值类型 支持JDBC 4 registerOutParameter(int parameterIndex, int type) void Yes wasNull() boolean Yes getString(int parameterIndex) String Yes getBoolean(int parameterIndex) boolean Yes getByte(int parameterIndex) byte Yes getShort(int parameterIndex) short Yes getInt(int parameterIndex) int Yes getLong(int parameterIndex) long Yes getFloat(int parameterIndex) float Yes getDouble(int parameterIndex) double Yes getBigDecimal(int parameterIndex) BigDecimal Yes getBytes(int parameterIndex) byte[] Yes getDate(int parameterIndex) Date Yes getTime(int parameterIndex) Time Yes getTimestamp(int parameterIndex) Timestamp Yes getObject(int parameterIndex) Object Yes 不允许含有OUT参数的语句执行批量操作。 以下方法是从java.sql.Statement继承而来:close,execute,executeQuery,executeUpdate,getConnection,getResultSet,getUpdateCount,isClosed,setMaxRows , setFetchSize。 以下方法是从java.sql.PreparedStatement继承而来:addBatch,clearParameters,execute,executeQuery,executeUpdate,getMetaData,setBigDecimal,setBoolean,setByte,setBytes,setDate,setDouble,setFloat,setInt,setLong,setNull,setObject,setString,setTime,setTimestamp 。
  • 从MySQL向 GaussDB (DWS)进行数据迁移 下面示例演示如何通过CopyManager从mysql向GaussDB(DWS)进行数据迁移的过程。 以下用例以gsjdbc4.jar为例,如果要使用gsjdbc200.jar,请替换驱动类名(将代码中的“org.postgresql”替换成“com.huawei.gauss200.jdbc”)与连接URL串前缀(将“jdbc:postgresql”替换为“jdbc:gaussdb”)。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 import java.io.StringReader; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.postgresql.copy.CopyManager; import org.postgresql.core.BaseConnection; public class Migration{ public static void main(String[] args) { String url = new String("jdbc:postgresql://10.180.155.74:8000/gaussdb"); //数据库URL String user = new String("jack"); //DWS用户名 String pass = new String("********"); //DWS密码 String tablename = new String("migration_table"); //定义表信息 String delimiter = new String("|"); //定义分隔符 String encoding = new String("UTF8"); //定义字符集 String driver = "org.postgresql.Driver"; StringBuffer buffer = new StringBuffer(); //定义存放格式 化数据的缓存 try { //获取源数据库查询结果集 ResultSet rs = getDataSet(); //遍历结果集,逐行获取记录 //将每条记录中各字段值,按指定分隔符分割,由换行符结束,拼成一个字符串 //把拼成的字符串,添加到缓存buffer while (rs.next()) { buffer.append(rs.getString(1) + delimiter + rs.getString(2) + delimiter + rs.getString(3) + delimiter + rs.getString(4) + "\n"); } rs.close(); try { //建立目标数据库连接 Class.forName(driver); Connection conn = DriverManager.getConnection(url, user, pass); BaseConnection baseConn = (BaseConnection) conn; baseConn.setAutoCommit(false); //初始化表信息 String sql = "Copy " + tablename + " from STDIN DELIMITER " + "'" + delimiter + "'" + " ENCODING " + "'" + encoding + "'"; //提交缓存buffer中的数据 CopyManager cp = new CopyManager(baseConn); StringReader reader = new StringReader(buffer.toString()); cp.copyIn(sql, reader); baseConn.commit(); reader.close(); baseConn.close(); } catch (ClassNotFoundException e) { e.printStackTrace(System.out); } catch (SQLException e) { e.printStackTrace(System.out); } } catch (Exception e) { e.printStackTrace(); } } 从源数据库返回查询结果集: private static ResultSet getDataSet() { ResultSet rs = null; try { Class.forName("com.mysql.jdbc.Driver").newInstance(); Connection conn = DriverManager.getConnection("jdbc:mysql://10.119.179.227:3306/jack?useSSL=false&allowPublicKeyRetrieval=true", "jack", "********"); Statement stmt = conn.createStatement(); rs = stmt.executeQuery("select * from migration_table"); } catch (SQLException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return rs; } }
  • 通过本地文件导入导出数据 在使用JAVA语言基于GaussDB(DWS)进行二次开发时,可以使用CopyManager接口,通过流方式,将数据库中的数据导出到本地文件或者将本地文件导入数据库中,文件格式支持 CS V、TEXT等格式。 样例程序如下,执行时需要加载GaussDB(DWS) jdbc驱动。 以下用例以gsjdbc4.jar为例,如果要使用gsjdbc200.jar,请替换驱动类名(将代码中的“org.postgresql”替换成“com.huawei.gauss200.jdbc”)与连接URL串前缀(将“jdbc:postgresql”替换为“jdbc:gaussdb”)。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import java.sql.Connection; import java.sql.DriverManager; import java.io.IOException; import java.io.FileInputStream; import java.io.FileOutputStream; import java.sql.SQLException; import org.postgresql.copy.CopyManager; import org.postgresql.core.BaseConnection; public class Copy{ public static void main(String[] args) { String urls = new String("jdbc:postgresql://10.180.155.74:8000/gaussdb"); //数据库URL String username = new String("jack"); //用户名 String password = new String("********"); //密码 String tablename = new String("migration_table"); //定义表信息 String tablename1 = new String("migration_table_1"); //定义表信息 String driver = "org.postgresql.Driver"; Connection conn = null; try { Class.forName(driver); conn = DriverManager.getConnection(urls, username, password); } catch (ClassNotFoundException e) { e.printStackTrace(System.out); } catch (SQLException e) { e.printStackTrace(System.out); } 执行数据导入导出: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 // 将migration_table查询结果导出到本地文件d:/data.txt try { copyToFile(conn, "d:/data.txt", "(SELECT * FROM migration_table)"); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } //将d:/data.txt中的数据导入到migration_table_1中。 try { copyFromFile(conn, "d:/data.txt", migration_table_1); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // 将migration_table_1中的数据导出到本地文件d:/data1.txt try { copyToFile(conn, "d:/data1.txt", migration_table_1); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void copyFromFile(Connection connection, String filePath, String tableName) throws SQLException, IOException { FileInputStream fileInputStream = null; try { CopyManager copyManager = new CopyManager((BaseConnection)connection); fileInputStream = new FileInputStream(filePath); copyManager.copyIn("COPY " + tableName + " FROM STDIN", fileInputStream); } finally { if (fileInputStream != null) { try { fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } public static void copyToFile(Connection connection, String filePath, String tableOrQuery) throws SQLException, IOException { FileOutputStream fileOutputStream = null; try { CopyManager copyManager = new CopyManager((BaseConnection)connection); fileOutputStream = new FileOutputStream(filePath); copyManager.copyOut("COPY " + tableOrQuery + " TO STDOUT", fileOutputStream); } finally { if (fileOutputStream != null) { try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
  • 示例2 客户端内存占用过多解决 此示例主要使用setFetchSize来调整客户端内存使用,它的原理是通过数据库游标来分批获取服务器端数据,但它会加大网络交互,可能会损失部分性能。 由于游标事务内有效,故需要先关闭自动提交。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 // 关闭掉自动提交 conn.setAutoCommit(false); Statement st = conn.createStatement(); // 打开游标,每次获取50行数据 st.setFetchSize(50); ResultSet rs = st.executeQuery("SELECT * FROM mytable"); while (rs.next()){ System.out.print("a row was returned."); } rs.close(); // 关闭服务器游标。 st.setFetchSize(0); rs = st.executeQuery("SELECT * FROM mytable"); while (rs.next()){ System.out.print("many rows were returned."); } rs.close(); // Close the statement. st.close();
  • 获取结果集中光标的位置 对于可滚动的结果集,可能会调用定位方法来改变光标的位置。JDBC驱动程序提供了获取结果集中光标所处位置的方法。获取光标位置的方法如表3所示。 表3 获取结果集光标的位置 方法 描述 isFirst() 是否在一行。 isLast() 是否在最后一行。 isBeforeFirst() 是否在第一行之前。 isAfterLast() 是否在最后一行之后。 getRow() 获取当前在第几行。
  • 获取结果集中的数据 ResultSet对象提供了丰富的方法,以获取结果集中的数据。获取数据常用的方法如表4所示,其他方法请参考JDK官方文档。 表4 ResultSet对象的常用方法 方法 描述 int getInt(int columnIndex) 按列标获取int型数据。 int getInt(String columnLabel) 按列名获取int型数据。 String getString(int columnIndex) 按列标获取String型数据。 String getString(String columnLabel) 按列名获取String型数据。 Date getDate(int columnIndex) 按列标获取Date型数据。 Date getDate(String columnLabel) 按列名获取Date型数据。
  • 在结果集中定位 ResultSet对象具有指向其当前数据行的光标。最初,光标被置于第一行之前。next方法将光标移动到下一行;因为该方法在ResultSet对象没有下一行时返回false,所以可以在while循环中使用它来迭代结果集。但对于可滚动的结果集,JDBC驱动程序提供更多的定位方法,使ResultSet指向特定的行。定位方法如表2所示。 表2 在结果集中定位的方法 方法 描述 next() 把ResultSet向下移动一行。 previous() 把ResultSet向上移动一行。 beforeFirst() 把ResultSet定位到第一行之前。 afterLast() 把ResultSet定位到最后一行之后。 first() 把ResultSet定位到第一行。 last() 把ResultSet定位到最后一行。 absolute(int) 把ResultSet移动到参数指定的行数。 relative(int) 向前或者向后移动参数指定的行。
  • 设置结果集类型 不同类型的结果集有各自的应用场景,应用程序需要根据实际情况选择相应的结果集类型。在执行SQL语句过程中,都需要先创建相应的语句对象,而部分创建语句对象的方法提供了设置结果集类型的功能。具体的参数设置如表1所示。涉及的Connection的方法如下: 1 2 3 4 5 6 7 8 //创建一个Statement对象,该对象将生成具有给定类型和并发性的ResultSet对象。 createStatement(int resultSetType, int resultSetConcurrency); //创建一个PreparedStatement对象,该对象将生成具有给定类型和并发性的ResultSet对象。 prepareStatement(String sql, int resultSetType, int resultSetConcurrency); //创建一个CallableStatement对象,该对象将生成具有给定类型和并发性的ResultSet对象。 prepareCall(String sql, int resultSetType, int resultSetConcurrency); 表1 结果集类型 参数 描述 resultSetType 表示结果集的类型,具体有三种类型: ResultSet.TYPE_FORWARD_ONLY:ResultSet只能向前移动。是缺省值。 ResultSet.TYPE_SCROLL_SENSITIVE:在修改后重新滚动到修改所在行,可以看到修改后的结果。 ResultSet.TYPE_SCROLL_INSENSITIVE:对可修改例程所做的编辑不进行显示。 说明: 结果集从数据库中读取了数据之后,即使类型是ResultSet.TYPE_SCROLL_SENSITIVE,也不会看到由其他事务在这之后引起的改变。调用ResultSet的refreshRow()方法,可进入数据库并从其中取得当前游标所指记录的最新数据。 resultSetConcurrency 表示结果集的并发,具体有两种类型: ResultSet.CONCUR_READ_ONLY:如果不从结果集中的数据建立一个新的更新语句,不能对结果集中的数据进行更新。 ResultSet.CONCUR_UPDATEABLE:可改变的结果集。对于可滚动的结果集,可对结果集进行适当的改变。
  • 执行批处理 用一条预处理语句处理多条相似的数据,数据库只创建一次执行计划,节省了语句的编译和优化时间。可以按如下步骤执行: 调用Connection的prepareStatement方法创建预编译语句对象。 1 PreparedStatement pstmt = con.prepareStatement("INSERT INTO customer_t1 VALUES (?)"); 针对每条数据都要调用setShort设置参数,以及调用addBatch确认该条设置完毕。 1 2 pstmt.setShort(1, (short)2); pstmt.addBatch(); 调用PreparedStatement的executeBatch方法执行批处理。 1 int[] rowcount = pstmt.executeBatch(); 调用PreparedStatement的close方法关闭预编译语句对象。 1 pstmt.close(); 在实际的批处理过程中,通常不终止批处理程序的执行,否则会降低数据库的性能。因此在批处理程序时,应该关闭自动提交功能,每几行提交一次。关闭自动提交功能的语句为:conn.setAutoCommit(false);
  • 执行普通SQL语句 应用程序通过执行SQL语句来操作数据库的数据(不用传递参数的语句),需要按以下步骤执行: 调用Connection的createStatement方法创建语句对象。 1 Statement stmt = con.createStatement(); 调用Statement的executeUpdate方法执行SQL语句。 1 int rc = stmt.executeUpdate("CREATE TABLE customer_t1(c_customer_sk INTEGER, c_customer_name VARCHAR(32));"); 数据库中收到的一次执行请求(不在事务块中),如果含有多条语句,将会被打包成一个事务,事务块中不支持vacuum操作。如果其中有一个语句失败,那么整个请求都将会被回滚。 关闭语句对象。 1 stmt.close();
  • 执行预编译SQL语句 预编译语句是只编译和优化一次,然后可以通过设置不同的参数值多次使用。由于已经预先编译好,后续使用会减少执行时间。因此,如果多次执行一条语句,请选择使用预编译语句。可以按以下步骤执行: 调用Connection的prepareStatement方法创建预编译语句对象。 1 PreparedStatement pstmt = con.prepareStatement("UPDATE customer_t1 SET c_customer_name = ? WHERE c_customer_sk = 1"); 调用PreparedStatement的setShort设置参数。 1 pstmt.setShort(1, (short)2); 调用PreparedStatement的executeUpdate方法执行预编译SQL语句。 1 int rowcount = pstmt.executeUpdate(); 调用PreparedStatement的close方法关闭预编译语句对象。 1 pstmt.close();
  • 调用存储过程 GaussDB(DWS)支持通过JDBC直接调用事先创建的存储过程,步骤如下: 调用Connection的prepareCall方法创建调用语句对象。 1 CallableStatement cstmt = myConn.prepareCall("{? = CALL TESTPROC(?,?,?)}"); 调用CallableStatement的setInt方法设置参数。 1 2 3 cstmt.setInt(2, 50); cstmt.setInt(1, 20); cstmt.setInt(3, 90); 调用CallableStatement的registerOutParameter方法注册输出参数。 1 cstmt.registerOutParameter(4, Types.INTEGER); //注册out类型的参数,类型为整型。 调用CallableStatement的execute执行方法调用。 1 cstmt.execute(); 调用CallableStatement的getInt方法获取输出参数。 1 int out = cstmt.getInt(4); //获取out参数 示例: 1 2 3 4 5 6 7 8 9 10 11 12 //在数据库中已创建了如下存储过程,它带有out参数。 create or replace procedure testproc ( psv_in1 in integer, psv_in2 in integer, psv_inout in out integer ) as begin psv_inout := psv_in1 + psv_in2 + psv_inout; end; / 调用CallableStatement的close方法关闭调用语句。 1 cstmt.close(); 很多的数据库例如Connection、Statement和ResultSet都有close()方法,在使用完对象后应把它们关闭。要注意的是,Connection的关闭将间接关闭所有与它关联的Statement,Statement的关闭间接关闭了ResultSet。 一些JDBC驱动程序还提供命名参数的方法来设置参数。命名参数的方法允许根据名称而不是顺序来设置参数,若参数有默认值,则可以不用指定参数值就可以使用此参数的默认值。即使存储过程中参数的顺序发生了变更,也不必修改应用程序。目前GaussDB(DWS)数据库的JDBC驱动程序不支持此方法。 GaussDB(DWS)数据库不支持带有输出参数的函数,也不支持存储过程和函数参数默认值。 当游标作为存储过程的返回值时,如果使用JDBC调用该存储过程,返回的游标将不可用。 存储过程不能和普通SQL在同一条语句中执行。
  • 参数 表1 数据库连接参数 参数 描述 url gsjdbc4.jar数据库连接描述符。格式如下: jdbc:postgresql:database jdbc:postgresql://host/database jdbc:postgresql://host:port/database jdbc:postgresql://host:port[,host:port][...]/database 说明: 使用gsjdbc200.jar时,将“jdbc:postgresql”修改为“jdbc:gaussdb” database为要连接的数据库名称。 host为数据库服务器名称或IP地址,当集群绑定弹性负载均衡(ELB)时,应设置为ELB的IP地址。 port为数据库服务器端口。缺省情况下,会尝试连接到localhost的8000端口的database。 支持多ip端口配置形式,jdbc自动实现了负载均衡,多ip端口配置形式是采取随机访问+failover的方式,这个过程系统会自动忽略不可达IP。 以","隔开,例如jdbc:postgresql://10.10.0.13:8000,10.10.0.14:8000/database 使用JDBC连接集群时集群链接地址只支持指定jdbc连接参数,不支持增加变量参数。 info 数据库连接属性。常用的属性如下: user:String类型。表示创建连接的数据库用户。 password:String类型。表示数据库用户的密码。 ssl:Boolean类型。表示是否使用SSL连接。 loggerLevel:string类型。为LogStream或LogWriter设置记录进DriverManager当前值的日志信息量。目前支持"OFF"、"DEBUG"和"TRACE"。 值为"DEBUG"时,表示只打印DEBUG级别以上的日志,将记录非常少的信息。值等于TRACE时,表示打印DEBUG和TRACE级别的日志,将产生详细的日志信息。默认值为OFF,表示不打印日志。 prepareThreshold:integer类型。用于确定在转换为服务器端的预备语句之前,要求执行方法PreparedStatement的次数。缺省值是5。 batchMode : boolean类型,用于确定是否使用batch模式连接。 fetchsize : integer类型,用于设置数据库链接所创建statement的默认fetchsize。 ApplicationName:string类型。应用名称,在不做设置时,缺省值为PostgreSQL JDBC Driver。 allowReadOnly:boolean类型,用于设置connection是否允许设置readonly模式,默认为false,若该参数不被设置为true,则执行connection.setReadOnly不生效。 blobMode:string类型,用于设置setBinaryStream方法为不同的数据类型赋值,设置为on时表示为blob数据类型赋值,设置为off时表示为bytea数据类型赋值,默认为on。 connectionExtraInfo:Boolean类型。表示驱动是否上报当前驱动的部署路径、进程属主用户到数据库。 说明: 取值范围:true或false,默认值为true。设置connectionExtraInfo为true,JDBC驱动会将当前驱动的部署路径、进程属主用户上报到数据库中,记录在connection_info参数(参见connection_info)里;同时可以在PG_STAT_ACTIVITY和PGXC_STAT_ACTIVITY中查询到。 user 数据库用户。 password 数据库用户的密码。
  • 示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 //以下用例以gsjdbc4.jar为例,如果要使用gsjdbc200.jar,请替换驱动类名(将代码中的“org.postgresql”替换成“com.huawei.gauss200.jdbc”)与连接URL串前缀(将“jdbc:postgresql”替换为“jdbc:gaussdb”)。 //以下代码将获取数据库连接操作封装为一个接口,可通过给定用户名和密码来连接数据库。 public static Connection GetConnection(String username, String passwd) { //驱动类。 String driver = "org.postgresql.Driver"; //数据库连接描述符。 String sourceURL = "jdbc:postgresql://10.10.0.13:8000/postgres?currentSchema=test"; Connection conn = null; try { //加载驱动。 Class.forName(driver); } catch (ClassNotFoundException e ){ e.printStackTrace(); return null; } try { //创建连接。 conn = DriverManager.getConnection(sourceURL, username, passwd); System.out.println("Connection succeed!"); } catch (SQLException e) { e.printStackTrace(); return null; } return conn; }
  • 加载驱动 在创建数据库连接之前,需要先加载数据库驱动程序。 加载驱动有两种方法: 在代码中创建连接之前任意位置隐含装载:Class.forName("org.postgresql.Driver"); 在JVM启动时参数传递:java -Djdbc.drivers=org.postgresql.Driver jdbctest 上述jdbctest为测试用例程序的名称。 当使用gsjdbc200.jar时,上面的Driver类名相应修改为"com.huawei.gauss200.jdbc.Driver" 父主题: 基于JDBC开发
  • JDBC开发流程 JDBC(Java Database Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问接口,应用程序可基于它操作数据。 GaussDB(DWS)库提供了对JDBC 4.0特性的支持,需要使用JDK1.6及以上版本编译程序代码,不支持JDBC桥接ODBC方式。JDBC开发应用程序的具体流程如下: 图1 采用JDBC开发应用程序的流程 表1 JDBC开发流程 步骤 描述 加载驱动 下载JDBC驱动并在程序中编译和加载。 连接数据库 通过JDBC驱动连接数据库。 执行SQL语句 应用程序通过执行SQL语句来操作数据库的数据。 处理结果集 不同类型的结果集有各自的应用场景,应用程序需要根据实际情况选择相应的结果集类型。 关闭连接 在使用数据库连接完成相应的数据操作后,需要关闭数据库连接。 父主题: 基于JDBC开发
  • JDBC包 从管理控制台下载包名为dws_8.1.x_jdbc_driver.zip。 请参见下载JDBC或ODBC驱动。 解压后有两个JDBC的驱动jar包: gsjdbc4.jar:与PostgreSQL保持兼容的驱动包,其中类名、类结构与PostgreSQL驱动完全一致,曾经运行于PostgreSQL的应用程序可以直接移植到当前系统使用。 gsjdbc200.jar:如果同一JVM进程内需要同时访问PostgreSQL及GaussDB(DWS)请使用此驱动包,它的主类名为“com.huawei.gauss200.jdbc.Driver”(即将“org.postgresql”替换为“com.huawei.gauss200.jdbc”),数据库连接的URL前缀为“jdbc:gaussdb”,其余与gsjdbc4.jar相同。
  • DDL 【建议】在GaussDB(DWS)中,建议DDL(建表、comments等)操作统一执行,在批处理作业中尽量避免DDL操作。避免大量并发事务对性能的影响。 【建议】在非日志表(unlogged table)使用完后,立即执行数据清理(TRUNCATE)操作。因为在异常场景下,GaussDB(DWS)不保证非日志表(unlogged table)数据的安全性。 【建议】临时表和非日志表的存储方式建议和基表相同。当基表为行存(列存)表时,临时表和非日志表也推荐创建为行存(列存)表,可以避免行列混合关联带来的高计算代价。 【建议】索引字段的总长度不超过50字节。否则,索引大小会膨胀比较严重,带来较大的存储开销,同时索引性能也会下降。 【建议】除非已经明确对象间的依赖关系,否则不要使用DROP…CASCADE方式删除对象,以免误删。
  • 数据加载和卸载 【建议】在INSERT语句中显式给出插入的字段列表。例如: 1 INSERT INTO task(name,id,comment) VALUES ('task1','100','第100个任务'); 【建议】在批量数据入库之后,或者数据增量达到一定阈值后,建议对表进行ANALYZE操作,防止统计信息不准确而导致的执行计划劣化。 【建议】如果要清理表中的所有数据,建议使用truncate table方式,不要使用delete table方式。delete table方式删除性能差,且不会释放那些已经删除了的数据占用的磁盘空间。
  • 释放连接 【建议】推荐使用连接池限制应用程序的连接数。每执行一条SQL就连接一次数据库,是一种不好的编写习惯。 【建议】在应用程序完成作业任务之后,应当及时断开和GaussDB(DWS)的连接,释放资源。建议在任务中设置session超时时间参数。 【建议】使用JDBC连接池,在将连接释放给连接池前,需要执行以下操作重置会话环境。否则,可能会因为历史会话信息导致的对象冲突。 如果在连接中设置了GUC参数,那么在将连接归还连接池之前,必须执行“SET SESSION AUTHORIZATION DEFAULT;RESET ALL;”将连接的状态清空。 如果使用了临时表,那么在将连接归还连接池之前,必须将临时表删除。
  • 连接参数 【关注】第三方工具通过JDBC连接GaussDB(DWS)时,JDBC向GaussDB(DWS)发起连接请求,会默认添加以下配置参数,详见JDBC代码ConnectionFactoryImpl类的实现。 params = { { "user", user }, { "database", database }, { "client_encoding", "UTF8" }, { "DateStyle", "ISO" }, { "extra_float_digits", "2" }, { "TimeZone", createPostgresTimeZone() }, }; 这些参数可能会导致JDBC客户端的行为与gsql客户端的行为不一致,例如,Date数据显示方式、浮点数精度表示、timezone显示。 如果实际期望和这些配置不符,建议在java连接设置代码中显式设定这些参数。 【建议】通过JDBC连接数据库时,应该保证下面两个时区设置一致: JDBC客户端所在主机的时区。 GaussDB(DWS)集群所在主机的时区。
  • 选择数据类型 在字段设计时,基于查询效率的考虑,一般遵循以下原则: 【建议】尽量使用高效数据类型。 选择数值类型时,在满足业务精度的情况下,选择数据类型的优先级从高到低依次为整数、浮点数、NUMERIC。 【建议】当多个表存在逻辑关系时,表示同一含义的字段应该使用相同的数据类型。 【建议】对于字符串数据,建议使用变长字符串数据类型,并指定最大长度。请务必确保指定的最大长度大于需要存储的最大字符数,避免超出最大长度时出现字符截断现象。除非明确知道数据类型为固定长度字符串,否则,不建议使用CHAR(n)、BPCHAR(n)、NCHAR(n)、CHARACTER(n)。 关于字符串类型的详细说明,请参见常用字符串类型介绍。
  • 选择分区方案 当表中的数据量很大时,应当对表进行分区,一般需要遵循以下原则: 【建议】使用具有明显区间性的字段进行分区,比如在日期、区域等字段上建立分区。 【建议】分区名称应当体现分区的数据特征。例如,关键字+区间特征。 【建议】将分区上边界的分区值定义为MAXVALUE,以防止可能出现的数据溢出。 典型的分区表定义如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CREATE TABLE staffS_p1 ( staff_ID NUMBER(6) not null, FIRST_NAME VARCHAR2(20), LAST_NAME VARCHAR2(25), EMAIL VARCHAR2(25), PHONE_NUMBER VARCHAR2(20), HIRE_DATE DATE, employment_ID VARCHAR2(10), SALARY NUMBER(8,2), COMMISSION_PCT NUMBER(4,2), MANAGER_ID NUMBER(6), section_ID NUMBER(4) ) PARTITION BY RANGE (HIRE_DATE) ( PARTITION HIRE_19950501 VALUES LESS THAN ('1995-05-01 00:00:00'), PARTITION HIRE_19950502 VALUES LESS THAN ('1995-05-02 00:00:00'), PARTITION HIRE_maxvalue VALUES LESS THAN (MAXVALUE) );
  • 选择分布键 Hash表的分布键选取至关重要,如果分布键选择不当,可能会导致数据倾斜,从而导致查询时I/O负载集中在部分DN上,影响整体查询性能。因此,在确定Hash表的分布策略之后,需要对表数据进行倾斜性检查,以确保数据的均匀分布。分布键的选择一般需要遵循以下原则: 【建议】选作分布键的字段取值应该比较离散,以便数据能在各个DN上均匀分布。当单个字段无法满足离散条件时,可以考虑使用多个字段一起作为分布键。一般情况下,可以考虑选择表的主键作为分布键。例如,在人员信息表中选择证件号码作为分布键。 【建议】在满足第一条原则的情况下,尽量不要选取在查询中存在常量过滤条件的字段作为分布键。例如,在表dwcjk相关的查询中,字段zqdh存在常量过滤条件“zqdh='000001'”,那么就应当尽量不选择zqdh字段作为分布键。 【建议】在满足前两条原则的情况,尽量选择查询中的关联条件为分布键。当关联条件作为分布键时,Join任务的相关数据都分布在DN本地,将极大减少DN之间的数据流动代价。
  • 选择存储方案 【建议】表的存储类型是表定义设计的第一步,用户业务类型是决定表的存储类型的主要因素,表存储类型的选择依据请参考表1。 表1 表的存储类型及场景 存储模型 优点 缺点 适用场景 行存 数据按照行进行存储,在查询某一行数据时,可以快速定位到目标位置。 查询时即使只涉及某几列,所有数据也都会被读取。 表的字段个数比较少,查询表的大部分字段。 点查询(返回记录少,基于索引的简单查询)。 频繁进行增删改查操作且该涉及整行数据。 列存 查询时只有涉及到的列会被读取。 列数据特征比较相似,能够更有效地进行数据压缩。 不适合少量数据INSERT或UPDATE操作。 表的字段比较多(大宽表),查询中涉及到的列不多。 统计分析类查询 (关联、分组操作较多的场景)。 即席查询(查询条件不确定,行存表扫描难以使用索引)。
  • 选择分布方案 【建议】表的分布方式的选择一般遵循以下原则: 表2 表的分布方式及使用场景 分布方式 描述 适用场景 Hash 表数据通过Hash方式散列到集群中的所有DN上。 数据量较大的事实表。 Replication 集群中每一个DN都有一份全量表数据。 维度表、数据量较小的事实表。 Roundrobin 表的每一行被轮番地发送给各个DN,因此数据会被均匀地分布在各个DN中。 数据量较大的事实表,且使用Hash分布时找不到合适的分布列。
共100000条