云服务器内容精选

  • 示例 逻辑复制类PGReplicationStream为非线程安全类,并发调用可能导致数据异常。 代码运行的前提条件: 添加JDBC用户机器IP(假设IP为10.11.12.34)到复制数据权限的白名单里,命令如下: gs_guc reload -Z datanode -N all -I all -h 'host replication all 10.11.12.34/32 sha256' 将wal_level参数设置为logical,设置方法请联系管理员处理。 创建表t1和t2,并且对该表进行DDL或DML操作。 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 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 // 以下用例以opengaussjdbc.jar为例。 // 认证用的用户名和密码直接写到代码中有很大的安全风险,建议在配置文件或者环境变量中存放(密码应密文存放,使用时解密),确保安全。 // 本示例以用户名和密码保存在环境变量中为例,运行本示例前请先在本地环境中设置环境变量(环境变量名称请根据自身情况进行设置)EXAMPLE_USERNAME_ENV和EXAMPLE_PASSWORD_ENV。 // $ip、$port、database需要用户自行修改。 import com.huawei.opengauss.jdbc.PGProperty; import com.huawei.opengauss.jdbc.jdbc.PgConnection; import com.huawei.opengauss.jdbc.replication.LogSequenceNumber; import com.huawei.opengauss.jdbc.replication.PGReplicationStream; import java.nio.ByteBuffer; import java.sql.DriverManager; import java.util.Properties; import java.util.concurrent.TimeUnit; public class LogicalReplicationDemo { private static PgConnection conn = null; public static void main(String[] args) { String driver = "com.huawei.opengauss.jdbc.Driver"; // 此处配置数据库IP以及端口,这里的端口为haPort,通常默认是所连接DN的port+1端口 String sourceURL = "jdbc:opengauss://$ip:$port/database"; // 默认逻辑复制槽的名称是:replication_slot // 测试模式:创建逻辑复制槽 int TEST_MODE_CREATE_SLOT = 1; // 测试模式:开启逻辑复制(前提条件是逻辑复制槽已经存在) int TEST_MODE_START_REPL = 2; // 测试模式:删除逻辑复制槽 int TEST_MODE_DROP_SLOT = 3; // 开启不同的测试模式 int testMode = TEST_MODE_START_REPL; try { Class.forName(driver); } catch (Exception e) { e.printStackTrace(); return; } try { Properties properties = new Properties(); PGProperty.USER.set(properties, System.getenv("EXAMPLE_USERNAME_ENV")); PGProperty.PASSWORD.set(properties, System.getenv("EXAMPLE_PASSWORD_ENV")); // 对于逻辑复制,以下三个属性是必须配置项 PGProperty.ASSUME_MIN_SERVER_VERSION.set(properties, "9.4"); PGProperty.REPLICATION.set(properties, "database"); PGProperty.PREFER_QUERY_MODE.set(properties, "simple"); conn = (PgConnection) DriverManager.getConnection(sourceURL, properties); System.out.println("connection success!"); if(testMode == TEST_MODE_CREATE_SLOT){ conn.getReplicationAPI() .createReplicationSlot() .logical() .withSlotName("replication_slot") // 这里字符串如包含大写字母则会自动转化为小写字母 .withOutputPlugin("mppdb_decoding") .make(); }else if(testMode == TEST_MODE_START_REPL) { // 开启此模式前需要创建复制槽 LogSequenceNumber waitLSN = LogSequenceNumber.valueOf("6F/E3C53568"); // LSN需要用户根据实际情况进行修改 PGReplicationStream stream = conn .getReplicationAPI() .replicationStream() .logical() .withSlotName("replication_slot") .withSlotOption("include-xids", true) .withSlotOption("skip-empty-xacts", true) .withStartPosition(waitLSN) .withSlotOption("parallel-decode-num", 10) // 解码线程并行度 .withSlotOption("white-table-list", "public.t1,public.t2") // 白名单列表 // .withSlotOption("standby-connection", true) // 强制备机解码 .withSlotOption("decode-style", "t") // 解码格式 .withSlotOption("sending-batch", 0) // 批量发送解码结果 .withSlotOption("max-txn-in-memory", 100) // 单个解码事务落盘内存阈值为100MB .withSlotOption("max-reorderbuffer-in-memory", 2) // 正在处理的解码事务落盘内存阈值为2GB .withSlotOption("exclude-users", "userA") // 不返回用户userA执行事务的逻辑日志 .withSlotOption("include-user", false) // 事务BEGIN逻辑日志不携带用户名 .withSlotOption("enable-heartbeat", true) // 开启心跳日志 .start(); while (true) { ByteBuffer byteBuffer = stream.readPending(); if (byteBuffer == null) { TimeUnit.MILLISECONDS.sleep(10L); continue; } int offset = byteBuffer.arrayOffset(); byte[] source = byteBuffer.array(); int length = source.length - offset; System.out.println(new String(source, offset, length)); // 如果需要flush lsn,根据业务实际情况调用以下接口,该接口会触发数据库复制槽落盘,对服务端解码性能有一定影响,建议调用间隔大于10s。 // LogSequenceNumber lastRecv = stream.getLastReceiveLSN(); // stream.setFlushedLSN(lastRecv); // stream.forceUpdateStatus(); } }else if(testMode == TEST_MODE_DROP_SLOT){ conn.getReplicationAPI() .dropReplicationSlot("replication_slot"); } } catch (Exception e) { e.printStackTrace(); return; } finally { try { conn.close(); } catch (Exception e) { e.printStackTrace(); } } } } text格式(即't'格式)解码结果示例如下: BEGIN CS N: 2014 first_lsn: 0/2816A28 table public t1 INSERT: a[integer]:1 b[integer]:2 c[text]:'hello' COMMIT XID: 15504 BEGIN CSN: 2015 first_lsn: 0/2816C20 table public t1 UPDATE: old-key: a[integer]:1 b[integer]:2 c[text]:'hello' new-tuple: a[integer]:1 b[integer]:5 c[text]:'hello' COMMIT XID: 15505 BEGIN CSN: 2016 first_lsn: 0/2816D60 table public t1 DELETE: a[integer]:1 b[integer]:5 c[text]:'hello' COMMIT XID: 15506 json格式(即'j'格式)解码结果示例如下: BEGIN CSN: 2014 first_lsn: 0/2816A28 {"table_name":"public.t1","op_type":"INSERT","columns_name":["a","b","c"],"columns_type":["integer","integer","text"],"columns_val":["1","2","'hello'"],"old_keys_name":[],"old_keys_type":[],"old_keys_val":[]} COMMIT XID: 15504 BEGIN CSN: 2015 first_lsn: 0/2816C20 {"table_name":"public.t1","op_type":"UPDATE","columns_name":["a","b","c"],"columns_type":["integer","integer","text"],"columns_val":["1","5","'hello'"],"old_keys_name":["a","b","c"],"old_keys_type":["integer","integer","text"],"old_keys_val":["1","2","'hello'"]} COMMIT XID: 15505 BEGIN CSN: 2016 first_lsn: 0/2816D60 {"table_name":"public.t1","op_type":"DELETE","columns_name":[],"columns_type":[],"columns_val":[],"old_keys_name":["a","b","c"],"old_keys_type":["integer","integer","text"],"old_keys_val":["1","5","'hello'"]} COMMIT XID: 15506
  • 日志诊断场景 ODBC日志分为unixODBC驱动管理器日志和psqlODBC驱动端日志。前者可以用于追溯应用程序API的执行是否成功,后者是底层实现过程中的一些DFX日志,用来帮助定位问题。 unixODBC日志需要在odbcinst.ini文件中配置: 1 2 3 4 5 6 7 [ODBC] Trace=Yes TraceFile=/path/to/odbctrace.log [GaussMPP] Driver64=/usr/local/lib/psqlodbcw.so setup=/usr/local/lib/psqlodbcw.so psqlODBC日志只需要在odbc.ini加上: [gaussdb] Driver=GaussMPP Servername=10.10.0.13(数据库Server IP) ... Debug=1(打开驱动端debug日志) unixODBC日志将会生成在TraceFile配置的路径下,psqlODBC会在系统/tmp/下生成mylog_xxx.log。
  • 创建和调用存储过程 此示例将演示如何基于 GaussDB 提供的JDBC接口开发应用程序。本示例演示如何连接数据库、创建和调用存储过程。 代码运行的前提条件:根据实际情况添加opengaussjdbc.jar包(例如用户使用IDE执行代码,则需要在本地IDE添加opengaussjdbc.jar包)。 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 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 // 认证用的用户名和密码直接写到代码中有很大的安全风险,建议在配置文件或者环境变量中存放(密码应密文存放,使用时解密),确保安全; // 本示例以用户名和密码保存在环境变量中为例,运行本示例前请先在本地环境中设置环境变量(环境变量名称请根据自身情况进行设置)EXAMPLE_USERNAME_ENV和EXAMPLE_PASSWORD_ENV。 // $ip、$port、database需要用户自行修改。 import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Statement; import java.sql.CallableStatement; import java.sql.Types; public class DBTest { //以非加密方式创建数据库连接。 public static Connection GetConnection(String username, String passwd) { String driver = "com.huawei.opengauss.jdbc.Driver"; String sourceURL = "jdbc:opengauss://$ip:$port/database"; Connection conn = null; try { //加载数据库驱动。 Class.forName(driver).newInstance(); } catch (Exception e) { e.printStackTrace(); return null; } try { //创建数据库连接。 conn = DriverManager.getConnection(sourceURL, username, passwd); System.out.println("Connection succeed!"); } catch (Exception e) { e.printStackTrace(); return null; } return conn; }; // 创建存储过程。 public static void CreateCallable(Connection conn) { Statement stmt = null; try { stmt = conn.createStatement(); // 创建存储过程,返回三个输入值的和。 stmt.execute("create or replace procedure testproc \n" + "(\n" + " psv_in1 in integer,\n" + " psv_in2 in integer,\n" + " psv_inout inout integer\n" + ")\n" + "as\n" + "begin\n" + " psv_inout := psv_in1 + psv_in2 + psv_inout;\n" + "end;\n" + "/"); } catch (SQLException e) { throw new RuntimeException(e); } finally { if (stmt != null) { try { stmt.close(); } catch (SQLException e) { throw new RuntimeException(e); } } } } //调用存储过程。 public static void ExecCallableSQL(Connection conn) { CallableStatement cstmt = null; try { cstmt=conn.prepareCall("{? = CALL TESTPROC(?,?,?)}"); cstmt.setInt(2, 50); cstmt.setInt(1, 20); cstmt.setInt(3, 90); cstmt.registerOutParameter(4, Types.INTEGER); //注册out类型的参数,类型为整型。 cstmt.execute(); int out = cstmt.getInt(4); //获取out参数 System.out.println("The CallableStatment TESTPROC returns:"+out); cstmt.close(); } catch (SQLException e) { if (cstmt != null) { try { cstmt.close(); } catch (SQLException e1) { e1.printStackTrace(); } } e.printStackTrace(); } } /** * 主程序,逐步调用各静态方法。 * @param args */ public static void main(String[] args) { //创建数据库连接。 String userName = System.getenv("EXAMPLE_USERNAME_ENV"); String password = System.getenv("EXAMPLE_PASSWORD_ENV"); Connection conn = GetConnection(userName, password); // 创建存储过程。 CreateCallable(conn); //执行存储过程。 ExecCallableSQL(conn); //关闭数据库连接。 try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } 上述示例的运行结果为: Connection succeed! The CallableStatment TESTPROC returns:160 父主题: 典型应用开发示例
  • 获取函数返回值 JDBC调用函数时获取返回值,以下示例展示返回值类型为bit和float8两种数据类型,其他数据类型可参考本示例。 代码运行的前提条件:根据实际情况添加opengaussjdbc.jar包(例如用户使用IDE执行代码,则需要在本地IDE添加opengaussjdbc.jar包)。 // 认证用的用户名和密码直接写到代码中有很大的安全风险,建议在配置文件或者环境变量中存放(密码应密文存放,使用时解密),确保安全。 // 本示例以用户名和密码保存在环境变量中为例,运行本示例前请先在本地环境中设置环境变量(环境变量名称请根据自身情况进行设置)EXAMPLE_USERNAME_ENV和EXAMPLE_PASSWORD_ENV。 // $ip、$port、database需要用户自行修改。 import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; import java.sql.CallableStatement; import java.sql.SQLException; import java.sql.PreparedStatement; import java.sql.Types; public class Type { public static void main(String[] args) throws SQLException { String driver = "com.huawei.opengauss.jdbc.Driver"; String username = System.getenv("EXAMPLE_USERNAME_ENV"); String passwd = System.getenv("EXAMPLE_PASSWORD_ENV"); String sourceURL = "jdbc:opengauss://$ip:$port/database"; Connection conn = null; try { // 加载数据库驱动。 Class.forName(driver).newInstance(); } catch (Exception e) { e.printStackTrace(); } try { // 以非加密方式创建数据库连接。 conn = DriverManager.getConnection(sourceURL, username, passwd); System.out.println("Connection succeed!"); } catch (Exception e) { e.printStackTrace(); } // 建表。 String createsql = "create table if not exists t_bit(col_bit bit)"; Statement stmt = conn.createStatement(); stmt.execute(createsql); stmt.close(); // bit类型使用示例,注意此处bit类型取值范围[0,1]。 Statement st = conn.createStatement(); String sqlstr = "create or replace function fun_1()\n" + "returns bit AS $$\n" + "select col_bit from t_bit limit 1;\n" + "$$\n" + "LANGUAGE SQL;"; st.execute(sqlstr); CallableStatement c = conn.prepareCall("{ ? = call fun_1() }"); // 注册输出类型,位串类型。 c.registerOutParameter(1, Types.BIT); c.execute(); // 使用Boolean类型获取结果。 System.out.println(c.getBoolean(1)); // float8类型使用示例。 st.execute("create table if not exists t_float(col1 float8)"); PreparedStatement pstm = conn.prepareStatement("insert into t_float values(?)"); pstm.setDouble(1, 123456.123); pstm.execute(); pstm.close(); // 函数返回值为float8的使用示例。 st.execute( "create or replace function func_float() " + "return float8 " + "as declare " + "var1 float8; " + "begin " + " select col1 into var1 from t_float limit 1; " + " return var1; " + "end;"); CallableStatement cs = conn.prepareCall("{? = call func_float()}"); cs.registerOutParameter(1, Types.DOUBLE); cs.execute(); System.out.println(cs.getDouble(1)); st.close(); // 关闭数据库连接。 try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } 上述示例的运行结果为: Connection succeed! false 123456.123 当前JDBC不支持调用返回数据类型为money的存储过程和函数。 父主题: 典型应用开发示例
  • 自动寻主场景 某客户存在一套集中式数据库实例,包含1主2备三个节点{node1,node2,node3},其中node1为主节点,node2、node3为备节点。 客户希望应用连接能建立在主DN上,并在发生主备切换时,自动选择新的主节点建连,则url可参考如下配置: jdbc:opengauss://node1,node2,node3/database?targetServerType=master
  • 高性能场景 某客户对于相同sql可能多次执行,仅是传参不同,为了提升执行效率,可开启prepareThreshold参数,避免重复生成执行计划,url可参考如下配置。 jdbc:opengauss://node1/database?prepareThreshold=5 某客户一次查询1000万数据,为避免同时返回造成内存溢出,可使用defaultRowFetchSize,url可参考如下配置。 jdbc:opengauss://node1/database?defaultRowFetchSize=50000 某客户需要批量插入1000万数据,为提升效率,可使用batchMode,url可参考如下配置。 jdbc:opengauss://node1/database?batchMode=on
  • 容灾场景 某客户有两套数据库实例,其中A数据库实例为生产数据库实例,B数据库实例为容灾数据库实例。当客户执行容灾切换时,A数据库实例将降为容灾数据库实例,B数据库实例将升为生产数据库实例。此时为了避免修改配置文件导致的应用重启或重新发版。客户可在初始配置文件时,即将A、B数据库实例写入连接串中。此时在主数据库实例不可连接时,驱动将尝试对容灾数据库实例建连。例如A数据库实例为{node1,node2,node3}。B数据库实例为{node4,node5,node6}。 则url可参考如下进行配置: jdbc:opengauss://node1,node2,node3,node4,node5,node6/database?priorityServers=3
  • 获取函数返回值 JDBC调用函数时获取返回值,以下示例展示返回值类型为bit和float8两种数据类型,其他数据类型可参考本示例。 代码运行的前提条件:根据实际情况添加gaussdbjdbc.jar包(例如用户使用IDE执行代码,则需要在本地IDE添加gaussdbjdbc.jar包)。 // 认证用的用户名和密码直接写到代码中有很大的安全风险,建议在配置文件或者环境变量中存放(密码应密文存放,使用时解密),确保安全。// 本示例以用户名和密码保存在环境变量中为例,运行本示例前请先在本地环境中设置环境变量(环境变量名称请根据自身情况进行设置)EXAMPLE_USERNAME_ENV和EXAMPLE_PASSWORD_ENV。// $ip、$port、database需要用户自行修改。import java.sql.Connection;import java.sql.DriverManager;import java.sql.Statement;import java.sql.CallableStatement;import java.sql.SQLException;import java.sql.PreparedStatement;import java.sql.Types;public class Type { public static void main(String[] args) throws SQLException { String driver = "com.huawei.gaussdb.jdbc.Driver"; String username = System.getenv("EXAMPLE_USERNAME_ENV"); String passwd = System.getenv("EXAMPLE_PASSWORD_ENV"); String sourceURL = "jdbc:gaussdb://$ip:$port/database"; Connection conn = null; try { // 加载数据库驱动。 Class.forName(driver).newInstance(); } catch (Exception e) { e.printStackTrace(); } try { // 以非加密方式创建数据库连接。 conn = DriverManager.getConnection(sourceURL, username, passwd); System.out.println("Connection succeed!"); } catch (Exception e) { e.printStackTrace(); } // 建表。 String createsql = "create table if not exists t_bit(col_bit bit)"; Statement stmt = conn.createStatement(); stmt.execute(createsql); stmt.close(); // bit类型使用示例,注意此处bit类型取值范围[0,1]。 Statement st = conn.createStatement(); String sqlstr = "create or replace function fun_1()\n" + "returns bit AS $$\n" + "select col_bit from t_bit limit 1;\n" + "$$\n" + "LANGUAGE SQL;"; st.execute(sqlstr); CallableStatement c = conn.prepareCall("{ ? = call fun_1() }"); // 注册输出类型,位串类型。 c.registerOutParameter(1, Types.BIT); c.execute(); // 使用Boolean类型获取结果。 System.out.println(c.getBoolean(1)); // float8类型使用示例。 st.execute("create table if not exists t_float(col1 float8)"); PreparedStatement pstm = conn.prepareStatement("insert into t_float values(?)"); pstm.setDouble(1, 123456.123); pstm.execute(); pstm.close(); // 函数返回值为float8的使用示例。 st.execute( "create or replace function func_float() " + "return float8 " + "as declare " + "var1 float8; " + "begin " + " select col1 into var1 from t_float limit 1; " + " return var1; " + "end;"); CallableStatement cs = conn.prepareCall("{? = call func_float()}"); cs.registerOutParameter(1, Types.DOUBLE); cs.execute(); System.out.println(cs.getDouble(1)); st.close(); // 关闭数据库连接。 try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } }} 上述示例的运行结果为: Connection succeed!false123456.123 父主题: 典型应用开发示例