0

使用.net(c#)语言连接postgresql数据库,npgsql 也提供了故障转移和负载均衡的功能 -利来国际app

张玉龙 2021-11-09
165

在postgresql发行版中只包含两个客户端接口: libpq 和 ecpg

  • libpq is included because it is the primary c language interface, and because many other client interfaces are built on top of it.
  • ecpg is included because it depends on the server-side sql grammar, and is therefore sensitive to changes in postgresql itself.

其他语言客户端接口:

name language comments website
dbd::pg perl perl dbi driver
jdbc java type 4 jdbc driver
libpqxx c c interface
node-postgres javascript node.js driver
npgsql .net .net data provider
pgtcl tcl -
pgtclng tcl -
pq go pure go driver for go’s database/sql
psqlodbc odbc odbc driver
psycopg python db api 2.0-compliant

  至于 c# 语言和 .net 是啥关系,这里就不提了,百度一搜一大把。

  npgsql 是一个用于 postgresql 的开源 ado.net 数据提供程序,它允许用 c#、visual basic、f# 编写的程序访问 postgresql 数据库服务器。它是用 100% c# 代码实现的,是免费的并且是开源的。

  npgsql 也不用单独下载,直接在 visual studio 2019(.net 的编程工具) 就能直接安装。

  npgsql的官方手册:

测试这个还挺麻烦,需要下载安装.net开发工具 visual studio 2019

下载地址:

新建项目

选择 windows 窗体应用,对于我这种小白,不适合直接搞代码,整个窗体拖一拖还是挺舒服



可以使用 visual stdio 2019 连接 postgresql 数据库

本次测试用不到这个,仅作为知识点,visual stdio 2019 中并未自带 postgresql 的连接功能,我们需要手动配置


还需要关闭程序

关闭程序后执行配置,点击 modify






在项目中添加 npgsql,这个是必须的,为了在代码中引用npgsql(using npgsql;) 实现对数据库的操作功能

右击项目名,选择管理 nuget 程序包




在窗体中拖动添加控件,按钮控件(button),标签控件(label),列表框控件(listbox)



为按钮控件和标签控件设置 name 和 text 属性,为列表框控件设置 name 属性


为按钮控件设置单击(click)事件

在源代码中引用 npgsql(using npgsql;)

在源代码里按钮的单击(click)事件中加入以下代码

// 编写数据库连接串 string connstring = "host=192.168.58.10;port=5432;username=postgres;password=postgres;database=postgres"; try { // 创建数据库连接 using (npgsqlconnection conn = new npgsqlconnection(connstring)) { // 打开数据库连接 conn.open(); // 定义查询sql string sql = "select inet_server_addr(),pg_is_in_recovery(),current_database(),current_user"; // 创建 npgsqldataadapter 类的对象 npgsqldataadapter sda = new npgsqldataadapter(sql, conn); // 创建 dataset 类的对象 dataset ds = new dataset(); // 使用 npgsqldataadapter 对象 sda 将查询结果填充到 dataset 对象 ds 中 sda.fill(ds); // 设置列表控件的数据源(datasource)属性 ip_b.datasource = ds.tables[0]; recover_b.datasource = ds.tables[0]; db_b.datasource = ds.tables[0]; user_b.datasource = ds.tables[0]; // 在列表控件中显示列值 ip_b.displaymember = ds.tables[0].columns[0].tostring(); recover_b.displaymember = ds.tables[0].columns[1].tostring(); db_b.displaymember = ds.tables[0].columns[2].tostring(); user_b.displaymember = ds.tables[0].columns[3].tostring(); // 释放资源,关闭数据库连接 ds.dispose(); sda.dispose(); conn.close(); conn.dispose(); } } catch (exception ex) { messagebox.show("查询失败!" ex.message); }

测试运行



c# 连接数据库思路和代码的学习受益于:

npgsql 也提供了故障转移和负载均衡的功能,但是这个功能在 npgsql 6.0 中引入,该版本仍处于测试阶段。

npgsql 最新的版本信息:
npgsql 关于故障转移和负载均衡的介绍:
visual studio 2019 上下载不到 npgsql 6.0 的版本,需要在windows cmd中使用 dotnet 命令指定版本下载:

# cd 到项目文件夹中 c:\users\administrator# cd c:\users\administrator\source\repos\pg_conn\pg_conn c:\users\administrator\source\repos\pg_conn\pg_conn# dotnet add pg_conn.csproj package npgsql --version 6.0.0-rc.2

多台服务器和故障转移

npgsql 允许连接字符串中指定多个服务器,如下所示:

host=server1:port,server2:port;username=test;password=test

默认情况下,npgsql 将尝试按照指定的顺序连接到服务器。

# 192.168.58.10是主节点,192.168.58.11/12是只读从节点 # 按顺序连接,当192.168.58.10不可用时,连接192.168.58.11 string connstring = "host=192.168.58.10:5432,192.168.58.11:5432,192.168.58.12:5432;username=postgres;password=postgres;database=postgres";
# 关闭主库 192.168.58.10 ,不进行主备切换 [[email protected] ~]# patronictl pause success: cluster management is paused [[email protected] ~]# su - postgres last login: sat nov 6 17:02:07 cst 2021 on pts/0 [[email protected] ~]$ pg_ctl stop waiting for server to shut down..... done server stopped [[email protected] ~]$ [[email protected] ~]$ patronictl list --------- --------------- --------- --------- ---- ----------- | member | host | role | state | tl | lag in mb | cluster: pg_cluster (7025023477017500881) -- ---- ----------- | pgtest1 | 192.168.58.10 | replica | stopped | | unknown | | pgtest2 | 192.168.58.11 | replica | running | 26 | 0 | | pgtest3 | 192.168.58.12 | replica | running | 26 | 0 | --------- --------------- --------- --------- ---- ----------- maintenance mode: on

  此时连到只读库 192.168.58.11,且多次 点击测试 创建数据库连接,连接的都是 192.168.58.11,如果是只读业务还好,此时不能进行写业务,npgsql 又提供了target session attributes参数指定服务器类型。

指定服务器类型 target session attributes

# 192.168.58.10是主节点,192.168.58.11/12是只读从节点 # 关闭主库 192.168.58.10 ,不进行主备切换的情况下,以下连接报错,找不到 primary string connstring = "host=192.168.58.10:5432,192.168.58.11:5432,192.168.58.12:5432;username=postgres;password=postgres;database=postgres;target session attributes=primary";

  在真实的故障转移场景中,如果主库出现故障,备库通常会提升为新的主服务器。但是,原来的主库可能会恢复并承担备用角色,此时服务器将切换角色,并且 npgsql 将尽可能继续连接原来的主库。为了缓解这种情况,也可以告诉 npgsql 希望连接到哪种服务器类型:

# 192.168.58.10是主节点,192.168.58.11/12是只读从节点 # 关闭主库进行主备切换,当192.168.58.10不可用时,连接到切换后的主库 192.168.58.12(primary) # npgsql 只返回到 primary 的连接,无论 primary 位于 connstring 的主机列表中的哪个位置,192.168.58.12处于最后位置,它的角色是primary,所以就没有连192.168.58.11。 string connstring = "host=192.168.58.10:5432,192.168.58.11:5432,192.168.58.12:5432;username=postgres;password=postgres;database=postgres;target session attributes=primary"; [[email protected] ~]# patronictl resume success: cluster management is resumed [[email protected] ~]# patronictl list --------- --------------- --------- --------- ---- ----------- | member | host | role | state | tl | lag in mb | cluster: pg_cluster (7025023477017500881) -- ---- ----------- | pgtest1 | 192.168.58.10 | leader | running | 27 | | | pgtest2 | 192.168.58.11 | replica | running | 27 | 0 | | pgtest3 | 192.168.58.12 | replica | running | 27 | 0 | --------- --------------- --------- --------- ---- ----------- [[email protected]t1 ~]# systemctl stop patroni [[email protected] ~]# patronictl list --------- --------------- --------- --------- ---- ----------- | member | host | role | state | tl | lag in mb | cluster: pg_cluster (7025023477017500881) -- ---- ----------- | pgtest1 | 192.168.58.10 | replica | stopped | | unknown | | pgtest2 | 192.168.58.11 | replica | running | 27 | 0 | | pgtest3 | 192.168.58.12 | leader | running | 28 | | --------- --------------- --------- --------- ---- -----------

读写分离

  有这种情况,应用程序的某些部分只需要从数据库中读取数据,而其他部分则需要写入数据。如果您有一台或多台备用服务器,npgsql 可以向这些服务器发送只读查询,以减少主服务器的负载。虽然上述故障转移设置提高了可靠性,但负载均衡这种技术提高了性能。

# 写读业务 host=server1:port,server2:port;username=test;password=test;target session attributes=primary"; # 只读业务 host=server1:port,server2:port;username=test;password=test;target session attributes=prefer-standby

  使用 prefer-standby,只要至少有一个备用服务器可用,npgsql 就会返回与该服务器的连接。但是,如果所有备用服务器都关闭(或已用完它们的max pool size设置),则将返回到主服务器的连接。

target session attributes 支持以下选项:

option description
any any successful connection is acceptable.
primary server must not be in hot standby mode (pg_is_in_recovery() must return false).
standby server must be in hot standby mode (pg_is_in_recovery() must return true).
prefer-primary first try to find a primary server, but if none of the listed hosts is a primary server, try again in any mode.
prefer-standby first try to find a standby server, but if none of the listed hosts is a standby server, try again in any mode.
read-write session must accept read-write transactions by default (that is, the server must not be in hot standby mode and the default_transaction_read_only parameter must be off).
read-only session must not accept read-write transactions by default (the converse).
# 192.168.58.10是主节点,192.168.58.11/12是只读从节点 # 在主备库正常的情况下,prefer-standby 控制连接只读备库,多个只读备库的情况下,也是按主机列表顺序连接,多次“点击测试”,只连一个只读备库192.168.58.11 string connstring = "host=192.168.58.10:5432,192.168.58.11:5432,192.168.58.12:5432;username=postgres;password=postgres;database=postgres;target session attributes=prefer-standby"; [[email protected] ~]# patronictl list --------- --------------- --------- --------- ---- ----------- | member | host | role | state | tl | lag in mb | cluster: pg_cluster (7025023477017500881) -- ---- ----------- | pgtest1 | 192.168.58.10 | leader | running | 29 | | | pgtest2 | 192.168.58.11 | replica | running | 29 | 0 | | pgtest3 | 192.168.58.12 | replica | running | 29 | 0 | --------- --------------- --------- --------- ---- -----------

负载均衡

  我们已经了解了如何根据要执行的工作负载类型选择服务器。但是,在上面的例子中,npgsql 仍然尝试根据连接字符串中指定的主机顺序返回连接;这将负载集中在单个主服务器和可能的单个辅助服务器上,并且不会在多个相同类型的服务器之间平衡负载。
  您可以在连接字符串中指定 load balance hosts=true 以指示 npgsql 在所有服务器之间进行负载平衡,通过以循环方式返回连接:

# 写读业务 host=server1:port,server2:port;username=test;password=test;target session attributes=primary"; # 只读业务 host=server1:port,server2:port,server3:port;username=test;password=test;load balance hosts=true;target session attributes=prefer-standby
# 192.168.58.10是主节点,192.168.58.11/12是只读从节点 # 在主备库正常的情况下,prefer-standby 控制连接只读备库,load balance hosts 控制只读备库之间的负载均衡 string connstring = "host=192.168.58.10:5432,192.168.58.11:5432,192.168.58.12:5432;username=postgres;password=postgres;database=postgres;load balance hosts=true;target session attributes=prefer-standby"; [[email protected] ~]# patronictl list --------- --------------- --------- --------- ---- ----------- | member | host | role | state | tl | lag in mb | cluster: pg_cluster (7025023477017500881) -- ---- ----------- | pgtest1 | 192.168.58.10 | leader | running | 29 | | | pgtest2 | 192.168.58.11 | replica | running | 29 | 0 | | pgtest3 | 192.168.58.12 | replica | running | 29 | 0 | --------- --------------- --------- --------- ---- -----------

  再点击一个点击测试 创建数据库连接,就返回另一个只读备库的连接,但是在我的测试中负载均衡load balance hosts=true不咋好使,偶尔能连另一个只读备库,不想jdbc的负载均衡那样丝滑,可能是刚出来的技术,还有待改进。

# 192.168.58.10是主节点,192.168.58.11/12是只读从节点 # 停到一个只读备库,多次连接始终返回另一个只读库的连接 string connstring = "host=192.168.58.10:5432,192.168.58.11:5432,192.168.58.12:5432;username=postgres;password=postgres;database=postgres;load balance hosts=true;target session attributes=prefer-standby"; [[email protected] ~]# systemctl stop patroni [[email protected] ~]# patronictl list --------- --------------- --------- --------- ---- ----------- | member | host | role | state | tl | lag in mb | cluster: pg_cluster (7025023477017500881) -- ---- ----------- | pgtest1 | 192.168.58.10 | leader | running | 29 | | | pgtest2 | 192.168.58.11 | replica | stopped | | unknown | | pgtest3 | 192.168.58.12 | replica | running | 29 | 0 | --------- --------------- --------- --------- ---- -----------
# 192.168.58.10是主节点,192.168.58.11/12是只读从节点 # 停到所有只读备库,返回主库的连接 [[email protected] ~]# systemctl stop patroni [[email protected] ~]# patronictl list --------- --------------- -------- --------- ---- ----------- | member | host | role | state | tl | lag in mb | cluster: pg_cluster (7025023477017500881) - ---- ----------- | pgtest1 | 192.168.58.10 | leader | running | 29 | | --------- --------------- -------- --------- ---- -----------
「喜欢文章,快来给作者赞赏墨值吧」
【利来手机国际的版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:[email protected]进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论