DM7使用裸设备搭建DMRAC

一、操作环境
主机 IP地址(对外服务) IP地址(内部通信) 实例名 操作系统

dmrac1	10.18.13.165	         10.10.10.165	        rac0	Redhat 6.7
dmrac2	10.18.13.166	         10.10.10.166	        rac1	Redhat 6.7

共享存储

/dev/sdb1	/dev/raw/raw1	dcr disk	2G
/dev/sdb2	/dev/raw/raw2	voting disk	2G
/dev/sdb3	/dev/raw/raw3	data disk1	2G
/dev/sdb4	/dev/raw/raw4	data disk2	2G
/dev/sdb1	/dev/raw/raw5	data disk3	2G
/dev/sdb2	/dev/raw/raw6	data disk4	2G
/dev/sdb3	/dev/raw/raw7	log disk1	2G
/dev/sdb4	/dev/raw/raw8	log disk2	2G
/dev/sdb1	/dev/raw/raw9	log disk3	2G
/dev/sdb2	/dev/raw/raw10	log disk4	2G
/dev/sdb3	/dev/raw/raw11	log disk5	2G
/dev/sdb4	/dev/raw/raw12	log disk6	2G

二、操作系统配置
1、关闭防火墙和SELINUX

[root@cs ~]# service iptables stop
iptables: Setting chains to policy ACCEPT: nat mangle filter [  OK  ]
iptables: Flushing firewall rules: [  OK  ]
iptables: Unloading modules: [  OK  ]
[root@cs ~]# chkconfig iptables off
[root@cs ~]# setenforce 0
[root@cs ~]# sed -i s:^SELINUX=.*$:SELINUX=disabled:g /etc/selinux/config

[root@cs ~]# service iptables stop
iptables: Setting chains to policy ACCEPT: nat mangle filter [  OK  ]
iptables: Flushing firewall rules: [  OK  ]
iptables: Unloading modules: [  OK  ]
[root@cs ~]# chkconfig iptables off
[root@cs ~]# setenforce 0
[root@cs ~]# sed -i s:^SELINUX=.*$:SELINUX=disabled:g /etc/selinux/config

2、修改主机名

[root@cs ~]# hostname dm1
[root@cs ~]# sed -i s:^HOSTNAME=.*$:HOSTNAME=dm1:g /etc/sysconfig/network


[root@cs ~]# hostname dm2
[root@cs ~]# sed -i s:^HOSTNAME=.*$:HOSTNAME=dm2:g /etc/sysconfig/network

3、修改hosts文件
[root@cs ~]# echo "
> 10.18.13.165   dm1
> 10.18.13.166   dm2" >> /etc/hosts
[root@cs ~]#


[root@cs ~]# echo "
> 10.18.13.165   dm1
> 10.18.13.166   dm2" >> /etc/hosts
[root@cs ~]#

三、 安装达梦软件
安装操作详见Oracle Linux 7.1中安装达梦数据库DM7

四、绑定UDEV

[root@dm1 rules.d]# vi 99-dm-devices.rules
ACTION=="add", KERNEL=="sdb1", RUN+="/bin/raw /dev/raw/raw1 %N"
ACTION=="add", KERNEL=="sdb2", RUN+="/bin/raw /dev/raw/raw2 %N"
ACTION=="add", KERNEL=="sdb3", RUN+="/bin/raw /dev/raw/raw3 %N"
ACTION=="add", KERNEL=="sdb4", RUN+="/bin/raw /dev/raw/raw4 %N"

ACTION=="add", KERNEL=="sdc1", RUN+="/bin/raw /dev/raw/raw5 %N"
ACTION=="add", KERNEL=="sdc2", RUN+="/bin/raw /dev/raw/raw6 %N"
ACTION=="add", KERNEL=="sdc3", RUN+="/bin/raw /dev/raw/raw7 %N"
ACTION=="add", KERNEL=="sdc4", RUN+="/bin/raw /dev/raw/raw8 %N"

ACTION=="add", KERNEL=="sdd1", RUN+="/bin/raw /dev/raw/raw9 %N"
ACTION=="add", KERNEL=="sdd2", RUN+="/bin/raw /dev/raw/raw10 %N"
ACTION=="add", KERNEL=="sdd3", RUN+="/bin/raw /dev/raw/raw11 %N"
ACTION=="add", KERNEL=="sdd4", RUN+="/bin/raw /dev/raw/raw12 %N"



ACTION=="add", KERNEL=="raw[1-12]", OWNER="dmdba", GROUP="dinstall", MODE="660"


[root@dm1 rules.d]# start_udev
Starting udev: [  OK  ]
[root@dm1 rules.d]# ls -lrt /dev/raw/
total 0
crw-rw---- 1 root  disk     162,  0 May  7 16:28 rawctl
crw-rw---- 1 dmdba dinstall 162,  9 May  7 16:28 raw9
crw-rw---- 1 dmdba dinstall 162, 12 May  7 16:28 raw12
crw-rw---- 1 dmdba dinstall 162, 11 May  7 16:28 raw11
crw-rw---- 1 dmdba dinstall 162, 10 May  7 16:28 raw10
crw-rw---- 1 dmdba dinstall 162,  6 May  7 16:28 raw6
crw-rw---- 1 dmdba dinstall 162,  1 May  7 16:28 raw1
crw-rw---- 1 dmdba dinstall 162,  7 May  7 16:28 raw7
crw-rw---- 1 dmdba dinstall 162,  8 May  7 16:28 raw8
crw-rw---- 1 dmdba dinstall 162,  5 May  7 16:28 raw5
crw-rw---- 1 dmdba dinstall 162,  2 May  7 16:28 raw2
crw-rw---- 1 dmdba dinstall 162,  3 May  7 16:28 raw3
crw-rw---- 1 dmdba dinstall 162,  4 May  7 16:28 raw4



[root@dm2 /]# cd /etc/udev/rules.d/
[root@dm2 rules.d]# vi 99-dm-devices.rules
ACTION=="add", KERNEL=="sdb1", RUN+="/bin/raw /dev/raw/raw1 %N"
ACTION=="add", KERNEL=="sdb2", RUN+="/bin/raw /dev/raw/raw2 %N"
ACTION=="add", KERNEL=="sdb3", RUN+="/bin/raw /dev/raw/raw3 %N"
ACTION=="add", KERNEL=="sdb4", RUN+="/bin/raw /dev/raw/raw4 %N"

ACTION=="add", KERNEL=="sdc1", RUN+="/bin/raw /dev/raw/raw5 %N"
ACTION=="add", KERNEL=="sdc2", RUN+="/bin/raw /dev/raw/raw6 %N"
ACTION=="add", KERNEL=="sdc3", RUN+="/bin/raw /dev/raw/raw7 %N"
ACTION=="add", KERNEL=="sdc4", RUN+="/bin/raw /dev/raw/raw8 %N"

ACTION=="add", KERNEL=="sdd1", RUN+="/bin/raw /dev/raw/raw9 %N"
ACTION=="add", KERNEL=="sdd2", RUN+="/bin/raw /dev/raw/raw10 %N"
ACTION=="add", KERNEL=="sdd3", RUN+="/bin/raw /dev/raw/raw11 %N"
ACTION=="add", KERNEL=="sdd4", RUN+="/bin/raw /dev/raw/raw12 %N"



ACTION=="add", KERNEL=="raw[1-12]", OWNER="dmdba", GROUP="dinstall", MODE="660"

[root@dm2 rules.d]# start_udev
Starting udev: [  OK  ]
[root@dm2 rules.d]# ls -lrt /dev/raw/
total 0
crw-rw---- 1 root  disk     162,  0 May  7 16:28 rawctl
crw-rw---- 1 dmdba dinstall 162,  9 May  7 16:28 raw9
crw-rw---- 1 dmdba dinstall 162, 12 May  7 16:28 raw12
crw-rw---- 1 dmdba dinstall 162, 11 May  7 16:28 raw11
crw-rw---- 1 dmdba dinstall 162, 10 May  7 16:28 raw10
crw-rw---- 1 dmdba dinstall 162,  6 May  7 16:28 raw6
crw-rw---- 1 dmdba dinstall 162,  1 May  7 16:28 raw1
crw-rw---- 1 dmdba dinstall 162,  7 May  7 16:28 raw7
crw-rw---- 1 dmdba dinstall 162,  8 May  7 16:28 raw8
crw-rw---- 1 dmdba dinstall 162,  5 May  7 16:28 raw5
crw-rw---- 1 dmdba dinstall 162,  2 May  7 16:28 raw2
crw-rw---- 1 dmdba dinstall 162,  3 May  7 16:28 raw3
crw-rw---- 1 dmdba dinstall 162,  4 May  7 16:28 raw4

可以通过blockdev –getsize64 /dev/raw/raw1命令查看裸设备大小

[root@dm1 rules.d]# blockdev --getsize64 /dev/raw/raw1
2154991104


[root@dm2 ~]# blockdev --getsize64 /dev/raw/raw1
2154991104

六、配置dmdcr_cfg.ini文件
在2个节点的/dm7/data目录下创建配置文件dmdcr_cfg.ini,仅使用裸设备,不使用ASM文件系统,不需要配置ASM信息,仅配置CSS/DB信息。在文件中添加如下内容:

[dmdba@dm1 dm7]$ mkdir data
[dmdba@dm1 dm7]$ cd data
[dmdba@dm1 data]$ vi dmdcr_cfg.ini
DCR_N_GRP = 2
DCR_VTD_PATH = /dev/raw/raw2
DCR_OGUID = 63635

[GRP]
DCR_GRP_TYPE = CSS
DCR_GRP_NAME = GRP_CSS
DCR_GRP_N_EP = 2
DCR_GRP_DSKCHK_CNT = 60
[GRP_CSS]
DCR_EP_NAME = CSS0
DCR_EP_HOST = 10.10.10.165
DCR_EP_PORT = 9541
[GRP_CSS]
DCR_EP_NAME = CSS1
DCR_EP_HOST = 10.10.10.166
DCR_EP_PORT = 9542


[GRP]
DCR_GRP_TYPE = DB
DCR_GRP_NAME = GRP_RAC
DCR_GRP_N_EP = 2
DCR_GRP_DSKCHK_CNT = 60
[GRP_RAC]
DCR_EP_NAME = RAC0
DCR_EP_SEQNO = 0
DCR_EP_PORT = 5236
DCR_CHECK_PORT = 9741
[GRP_RAC]
DCR_EP_NAME = RAC1
DCR_EP_SEQNO = 1
DCR_EP_PORT = 5236
DCR_CHECK_PORT = 9742

[dmdba@dm2 dm7]$ mkdir data
[dmdba@dm2 dm7]$ cd data
[dmdba@dm2 data]$ vi dmdcr_cfg.ini
DCR_N_GRP = 2
DCR_VTD_PATH = /dev/raw/raw2
DCR_OGUID = 63635

[GRP]
DCR_GRP_TYPE = CSS
DCR_GRP_NAME = GRP_CSS
DCR_GRP_N_EP = 2
DCR_GRP_DSKCHK_CNT = 60
[GRP_CSS]
DCR_EP_NAME = CSS0
DCR_EP_HOST = 10.10.10.165
DCR_EP_PORT = 9541
[GRP_CSS]
DCR_EP_NAME = CSS1
DCR_EP_HOST = 10.10.10.166
DCR_EP_PORT = 9542


[GRP]
DCR_GRP_TYPE = DB
DCR_GRP_NAME = GRP_RAC
DCR_GRP_N_EP = 2
DCR_GRP_DSKCHK_CNT = 60
[GRP_RAC]
DCR_EP_NAME = RAC0
DCR_EP_SEQNO = 0
DCR_EP_PORT = 5236
DCR_CHECK_PORT = 9741
[GRP_RAC]
DCR_EP_NAME = RAC1
DCR_EP_SEQNO = 1
DCR_EP_PORT = 5236
DCR_CHECK_PORT = 9742

七、使用 DMASMCMD 工具初始化(任意一节点执行)

[dmdba@dm1 ~]$ dmasmcmd
DMASMCMD V7.1.6.46-Build(2018.02.08-89107)ENT
ASM>create dcrdisk '/dev/raw/raw1' 'dcr'
the ASM initialize dcrdisk /dev/raw/raw1 to name DMASMdcr
Used time: 1.459(ms).
ASM>create votedisk '/dev/raw/raw2' 'vote'
the ASM initialize votedisk /dev/raw/raw2 to name DMASMvote
Used time: 1.380(ms).
ASM>init dcrdisk '/dev/raw/raw1' from '/dm7/data/dmdcr_cfg.ini'
syntax error
asmcmd parse failed!
ASM>init dcrdisk '/dev/raw/raw1' from '/dm7/data/dmdcr_cfg.ini' identified by 'dameng123'
[Trace]DG 126 allocate 4 extents for file 0xfe000002.
Check dcr disk failed, please check and try again
Used time: 271.543(ms).
ASM>init dcrdisk '/dev/raw/raw1' from '/dm7/data/dmdcr_cfg.ini' identified by 'dameng123'
[Trace]DG 126 allocate 4 extents for file 0xfe000002.
Used time: 68.745(ms).
ASM>init votedisk '/dev/raw/raw2' from '/dm7/data/dmdcr_cfg.ini'
[Trace]DG 125 allocate 4 extents for file 0xfd000002.
Used time: 33.488(ms).

八、操作系统配置准备配置dminit.ini文件,存放在/dm7/data目录中

system_path = /dm7/data
db_name=rac
main = /dev/raw/raw3
main_size = 128
roll = /dev/raw/raw4
roll_size = 128
system = /dev/raw/raw5
system_size = 128
ctl_path = /dev/raw/raw6
ctl_size = 8
dcr_path=/dev/raw/raw1
dcr_seqno=0

[rac0]
config_path=/dm7/data/rac0_config
port_num = 5236
mal_host = 10.10.10.165
mal_port = 9340
log_size = 256
log_path = /dev/raw/raw7
log_path = /dev/raw/raw8
[rac1]
config_path=/dm7/data/rac1_config
port_num = 5236
mal_host = 10.10.10.166
mal_port = 9341
log_size = 256
log_path = /dev/raw/raw9
log_path = /dev/raw/raw10

九、准备dmdcr.ini 配置文件
dmdcr.ini 是 dmcss、dmasmsvr、dmasmtool 工具的输入参数。记录了当前节点序列号以及 DCR 磁盘路径。在2个节点的/dm/dmdbms/data目录下创建dmdcr.ini 配置文件,dmdcr_path 相同,dmasvrmal.ini 文件内容也相同,dmdcr_seqo 分别为 0 和 1。
节点 1:

[dmdba@dmrac1 data]$ vi dmdcr.ini
DMDCR_PATH = /dev/raw/raw1
DMDCR_SEQNO = 0

#ASM
DMDCR_ASM_RESTART_INTERVAL = 0
DMDCR_ASM_STARTUP_CMD = /dm7/bin/dmasmsvr dcr_ini=/dm7/data/dmdcr.ini

#DB
DMDCR_DB_RESTART_INTERVAL = 0
DMDCR_DB_STARTUP_CMD = /dm7/bin/dmserver path=/dm7/data/rac0_config/dm.ini dcr_ini=/dm7/data/dmdcr.ini

节点2:

[dmdba@dmrac2 data]$ vi dmdcr.ini
DMDCR_PATH = /dev/raw/raw1
DMDCR_SEQNO = 1

#ASM
DMDCR_ASM_RESTART_INTERVAL = 0
DMDCR_ASM_STARTUP_CMD = /dm7/bin/dmasmsvr dcr_ini=/dm7/data/dmdcr.ini

#DB
DMDCR_DB_RESTART_INTERVAL = 0
DMDCR_DB_STARTUP_CMD = /dm7/bin/dmserver path=/dm7/data/rac1_config/dm.ini dcr_ini=/dm7/data/dmdcr.ini

十、启动DMCSS 服务程序
1、注册 DMCSS服务
节点一:

[root@dm1 ~]# /dm7/script/root/dm_service_installer.sh -t dmcss -i /dm7/data/dmdcr.ini -p rac1
Move the service script file(/dm7/bin/DmCSSServicerac1 to /etc/rc.d/init.d/DmCSSServicerac1)
Finished to create the service (DmCSSServicerac1)

节点二:

[root@dm2 ~]# /dm7/script/root/dm_service_installer.sh -t dmcss -i /dm7/data/dmdcr.ini -p rac2
Move the service script file(/dm7/bin/DmCSSServicerac2 to /etc/rc.d/init.d/DmCSSServicerac2)
Finished to create the service (DmCSSServicerac2)

2、启动DMCSS 服务
节点一:

[root@dm1 ~]# service DmCSSServicerac1 start
Starting DmCSSServicerac1: [ OK ]

节点二:

[root@dm2 ~]# service DmCSSServicerac2 start
Starting DmCSSServicerac2: [ OK ]

十一、操作系统配置使用dminit初始化DB环境
在任意节点启动 dminit 工具初始化数据库。dminit 执行完成后,会在 config_path 目录(/dm7/data/rac0_config 和/dm7/data/rac1_config)下生成配置文件 dm.ini 和 dmmal.ini。

[dmdba@dm1 data]$ dminit control=/dm7/data/dminit.ini
initdb V7.1.6.46-Build(2018.02.08-89107)ENT
db version: 0x7000a
file dm.key not found, use default license!
License will expire in 14 day(s) on 2020-05-21

 log file path: /dev/raw/raw7


 log file path: /dev/raw/raw8


 log file path: /dev/raw/raw9


 log file path: /dev/raw/raw10

FILE "/dev/raw/raw5" has already existed
FILE "/dev/raw/raw4" has already existed
FILE "/dev/raw/raw3" has already existed
FILE "/dev/raw/raw6" has already existed
FILE "/dev/raw/raw7" has already existed
FILE "/dev/raw/raw8" has already existed
FILE "/dev/raw/raw9" has already existed
FILE "/dev/raw/raw10" has already existed
File "/dev/raw/raw5" has already existed,
whether overwrite(y/n, 1/0): y
File "/dev/raw/raw4" has already existed,
whether overwrite(y/n, 1/0): y
File "/dev/raw/raw3" has already existed,
whether overwrite(y/n, 1/0): y
File "/dev/raw/raw6" has already existed,
whether overwrite(y/n, 1/0): y
File "/dev/raw/raw7" has already existed,
whether overwrite(y/n, 1/0): y
File "/dev/raw/raw8" has already existed,
whether overwrite(y/n, 1/0): y
File "/dev/raw/raw9" has already existed,
whether overwrite(y/n, 1/0): y
File "/dev/raw/raw10" has already existed,
whether overwrite(y/n, 1/0): y
write to dir [/dm7/data/rac].
create dm database success. 2020-05-07 16:41:52

将节点一的配置文件复制到节点二:

[dmdba@dm1 data]$ scp -r rac1_config 10.18.13.166:`pwd`
The authenticity of host '10.18.13.166 (10.18.13.166)' can't be established.
RSA key fingerprint is 89:fc:3e:e3:2d:27:94:07:0e:6b:fc:c5:e8:89:44:1f.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '10.18.13.166' (RSA) to the list of known hosts.
dmdba@10.18.13.166's password:
sqllog.ini                                                                                                                                                                                                100%  479     0.5KB/s   00:00
dm.ini                                                                                                                                                                                                    100%   40KB  39.8KB/s   00:00
dmmal.ini                                                                                                                                                                                                 100%  204     0.2KB/s   00:00
[dmdba@dm1 data]$

一定要将节点一/dm7/data/目录中生成的rac目录复制到节点二的/dm7/data目录中,否则在节点二中启动数据库时会出现以下错误,原因就是因为使用裸设备时生成的rac目录及其文件不是存储在共享存储中可以让集群节点都能访问。

Starting DmServicerac2: [ FAILED ]
file dm.key not found, use default license!
Read ini warning, default dm.ctl backup path [/dm7/data/rac/ctl_bak] does not exist.
Read ini error, name:SYSTEM_PATH, value:/dm7/data/rac
dmserver startup failed, code = -803 [Invalid ini config value]

将节点一/dm7/data/目录中生成的rac目录复制到节点二的/dm7/data目录

[dmdba@dm1 data]$ scp -r rac 10.18.13.166:`pwd`
dmdba@10.18.13.166's password:
dm_20200507164149_942994.ctl                                                                                                                                                                              100% 6144     6.0KB/s   00:00
TEMP0.DBF                                                                                                                                                                                                 100%   10MB  10.0MB/s   00:00
dm_service.prikey                                                                                                                                                                                         100%  633     0.6KB/s   00:00

十二、启动数据库服务器
1、在2个节点分别注册DM 数据库服务:
节点一:

[root@dm1 ~]# /dm7/script/root/dm_service_installer.sh -t dmserver -i /dm7/data/rac0_config/dm.ini -d /dm7/data/dmdcr.ini -p rac1
Move the service script file(/dm7/bin/DmServicerac1 to /etc/rc.d/init.d/DmServicerac1)
Finished to create the service (DmServicerac1)

节点二:

[root@dm2 ~]# /dm7/script/root/dm_service_installer.sh -t dmserver -i /dm7/data/rac1_config/dm.ini -d /dm7/data/dmdcr.ini -p rac2
Move the service script file(/dm7/bin/DmServicerac2 to /etc/rc.d/init.d/DmServicerac2)
Finished to create the service (DmServicerac2)

2、启动数据库

[root@dm1 ~]# service DmServicerac1 start
Starting DmServicerac1: [ OK ]

[root@dm2 ~]# service DmServicerac2 start
Starting DmServicerac2: [ OK ]

手工启动命令如下,手工启动后窗口不能关闭,所以

./dmserver /dm7/data/rac0_config/dm.ini dcr_ini=/dm7/data/dmdcr.ini
./dmserver /dm7/data/rac1_config/dm.ini dcr_ini=/dm7/data/dmdcr.ini

十三、操作系统配置连接数据库验证
13.1配置服务名文件

[dmdba@dm1 data]$ vi /etc/dm_svc.conf
rac=(10.18.13.165:5236,10.18.13.166:5236)
SWITCH_TIME=(10000)
SWITCH_INTERVAL=(10)

TIME_ZONE=(480)
LANGUAGE=(en)

[dmdba@dm2 rac]$ vi /etc/dm_svc.conf
TIME_ZONE=(480)
rac=(10.18.13.165:5236,10.18.13.166:5236)
SWITCH_TIME=(10000)
SWITCH_INTERVAL=(10)

TIME_ZONE=(480)
LANGUAGE=(en)

13.2 连接RAC集群
节点一:

[dmdba@dm1 data]$ disql SYSDBA/SYSDBA@rac

Server[10.18.13.166:5236]:mode is normal, state is open
login used time: 9.596(ms)
disql V7.1.6.46-Build(2018.02.08-89107)ENT
Connected to: DM 7.1.6.46
SQL> select instance_name from v$instance;

LINEID     INSTANCE_NAME
---------- -------------
1          RAC1

used time: 5.020(ms). Execute id is 2.
SQL> select * from v$rac_ep_info;

LINEID     EP_NAME EP_SEQNO    EP_GUID              EP_TIMESTAMP         EP_MODE EP_STATUS
---------- ------- ----------- -------------------- -------------------- ------- ---------
1          RAC0    0           2982624975           2982625916           MASTER  OK
2          RAC1    1           2983098335           2983098713           SLAVE   OK

used time: 7.731(ms). Execute id is 3.

节点二:

SQL> select instance_name from v$instance;

LINEID     INSTANCE_NAME
---------- -------------
1          RAC1

used time: 117.515(ms). Execute id is 1.
SQL> select * from v$rac_ep_info;

LINEID     EP_NAME EP_SEQNO    EP_GUID              EP_TIMESTAMP         EP_MODE EP_STATUS
---------- ------- ----------- -------------------- -------------------- ------- ---------
1          RAC0    0           2982624975           2982632228           MASTER  OK
2          RAC1    1           2983098335           2983105025           SLAVE   OK

used time: 4.439(ms). Execute id is 4.

13.3测试故障重连

[dmdba@dm2 rac]$ disql SYSDBA/SYSDBA@rac

Server[10.18.13.166:5236]:mode is normal, state is open
login used time: 6.728(ms)
disql V7.1.6.46-Build(2018.02.08-89107)ENT
Connected to: DM 7.1.6.46
SQL> select instance_name from v$instance;

LINEID     INSTANCE_NAME
---------- -------------
1          RAC1

used time: 117.515(ms). Execute id is 1.
SQL> select * from v$rac_ep_info;

LINEID     EP_NAME EP_SEQNO    EP_GUID              EP_TIMESTAMP         EP_MODE EP_STATUS
---------- ------- ----------- -------------------- -------------------- ------- ---------
1          RAC0    0           2982624975           2982632228           MASTER  OK
2          RAC1    1           2983098335           2983105025           SLAVE   OK

used time: 4.439(ms). Execute id is 4.

#此时连接的rac1,我们kill 进程:

[root@dm2 ~]# ps -ef | grep dm.ini
dmdba     6231     1  0 17:25 pts/2    00:00:44 /dm7/bin/dmserver /dm7/data/rac1_config/dm.ini DCR_INI=/dm7/data/dmdcr.ini -noconsole
root     10844  5237  0 19:20 pts/2    00:00:00 grep dm.ini
[root@dm2 ~]# kill -9 6231

#在查询,故障重连成功:

SQL> select instance_name from v$instance;
[-70065]:Connection exception, switch the current connection sucessful.
[-70065]:Connection exception, switch the current connection sucessful.

Server[10.18.13.165:5236]:mode is normal, state is open
SQL> select instance_name from v$instance;

LINEID     INSTANCE_NAME
---------- -------------
1          RAC0

used time: 9.443(ms). Execute id is 807.

SQL> select * from v$rac_ep_info;

LINEID     EP_NAME EP_SEQNO    EP_GUID              EP_TIMESTAMP         EP_MODE EP_STATUS
---------- ------- ----------- -------------------- -------------------- ------- ---------
1          RAC0    0           2982624975           2982632568           MASTER  OK
2          RAC1    1           2983098335           2983105240           SLAVE   ERROR

used time: 3.184(ms). Execute id is 808.

可以看到连接的实例从rac1变为了rac0

DM7使用DMASM安装DMRAC

一.环境准备
主机 IP地址(对外服务) IP地址(内部通信) 实例名 操作系统
dmrac1 10.18.13.161 10.10.10.161 rac0 Redhat 6.7
dmrac2 10.18.13.162 10.10.10.162 rac1 Redhat 6.7

共享存储
/dev/sdb /dev/raw/raw1 dcr disk 2G
/dev/sdc /dev/raw/raw2 voting disk 2G
/dev/sdd /dev/raw/raw3 log disk 10G
/dev/sde /dev/raw/raw4 data disk1 10G
/dev/sdf /dev/raw/raw5 data disk2 10G

二、操作系统配置

1、关闭防火墙和SELINUX

[root@cs ~]# service iptables stop
iptables: Setting chains to policy ACCEPT: nat mangle filter [ OK ]
iptables: Flushing firewall rules: [ OK ]
iptables: Unloading modules: [ OK ]
[root@cs ~]# chkconfig iptables off
[root@cs ~]# setenforce 0
[root@cs ~]# sed -i s:^SELINUX=.*$:SELINUX=disabled:g /etc/selinux/config

[root@cs ~]# service iptables stop
iptables: Setting chains to policy ACCEPT: nat mangle filter [ OK ]
iptables: Flushing firewall rules: [ OK ]
iptables: Unloading modules: [ OK ]
[root@cs ~]# chkconfig iptables off
[root@cs ~]# setenforce 0
[root@cs ~]# sed -i s:^SELINUX=.*$:SELINUX=disabled:g /etc/selinux/config

2、修改主机名

[root@cs ~]# hostname dmrac1
[root@cs ~]# hostname dmrac2
[root@cs ~]# sed -i s:^HOSTNAME=.*$:HOSTNAME=dmrac1:g /etc/sysconfig/network
[root@cs ~]# sed -i s:^HOSTNAME=.*$:HOSTNAME=dmrac2:g /etc/sysconfig/network

3、修改hosts文件

[root@cs ~]# echo "
> 10.18.13.161 dmrac1
> 10.18.13.162 dmrac2" >> /etc/hosts

[root@cs ~]# echo "
> 10.18.13.161 dmrac1
> 10.18.13.162 dmrac2" >> /etc/hosts

三、 安装达梦软件
为了减少对操作系统的影响,用户不应该以root系统用户来安装和运行DM。用户可以在安装之前为DM创建一个专用的系统用户。具体操作详见Oracle Linux 7.1中安装达梦数据库DM7

四、绑定UDEV

[root@dmrac1 rules.d]# vi 99-dm-devices.rules
ACTION=="add", KERNEL=="sdb", RUN+="/bin/raw /dev/raw/raw1 %N"
ACTION=="add", KERNEL=="sdc", RUN+="/bin/raw /dev/raw/raw2 %N"
ACTION=="add", KERNEL=="sdd", RUN+="/bin/raw /dev/raw/raw3 %N"
ACTION=="add", KERNEL=="sde", RUN+="/bin/raw /dev/raw/raw4 %N"
ACTION=="add", KERNEL=="sdf", RUN+="/bin/raw /dev/raw/raw5 %N"


ACTION=="add", KERNEL=="raw[1-5]", OWNER="dmdba", GROUP="dinstall", MODE="660"
~
[root@dmrac1 rules.d]# start_udev
Starting udev: [ OK ]
[root@dmrac1 rules.d]# ls -lrt /dev/raw/
total 0
crw-rw----. 1 root disk 162, 0 Apr 24 14:08 rawctl
crw-rw----. 1 dmdba dinstall 162, 2 Apr 24 14:08 raw2
crw-rw----. 1 dmdba dinstall 162, 1 Apr 24 14:08 raw1
crw-rw----. 1 dmdba dinstall 162, 4 Apr 24 14:08 raw4
crw-rw----. 1 dmdba dinstall 162, 3 Apr 24 14:08 raw3
crw-rw----. 1 dmdba dinstall 162, 5 Apr 24 14:08 raw5


[root@dmrac2 rules.d]# vi 99-dm-devices.rules
ACTION=="add", KERNEL=="sdb", RUN+="/bin/raw /dev/raw/raw1 %N"
ACTION=="add", KERNEL=="sdc", RUN+="/bin/raw /dev/raw/raw2 %N"
ACTION=="add", KERNEL=="sdd", RUN+="/bin/raw /dev/raw/raw3 %N"
ACTION=="add", KERNEL=="sde", RUN+="/bin/raw /dev/raw/raw4 %N"
ACTION=="add", KERNEL=="sdf", RUN+="/bin/raw /dev/raw/raw5 %N"


ACTION=="add", KERNEL=="raw[1-5]", OWNER="dmdba", GROUP="dinstall", MODE="660"
~
[root@dmrac2 rules.d]# start_udev
Starting udev: [ OK ]
[root@dmrac2 rules.d]# ls -lrt /dev/raw/
total 0
crw-rw----. 1 root disk 162, 0 Apr 24 14:08 rawctl
crw-rw----. 1 dmdba dinstall 162, 2 Apr 24 14:08 raw2
crw-rw----. 1 dmdba dinstall 162, 1 Apr 24 14:08 raw1
crw-rw----. 1 dmdba dinstall 162, 4 Apr 24 14:08 raw4
crw-rw----. 1 dmdba dinstall 162, 3 Apr 24 14:08 raw3
crw-rw----. 1 dmdba dinstall 162, 5 Apr 24 14:08 raw5

可以通过blockdev –getsize64 /dev/raw/raw1命令查看裸设备大小

[root@dmrac1 rules.d]# blockdev --getsize64 /dev/raw/raw1
2147483648
[root@dmrac1 rules.d]# blockdev --getsize64 /dev/raw/raw2
2147483648
[root@dmrac1 rules.d]# blockdev --getsize64 /dev/raw/raw3
10737418240
[root@dmrac1 rules.d]# blockdev --getsize64 /dev/raw/raw4
10737418240
[root@dmrac1 rules.d]# blockdev --getsize64 /dev/raw/raw5
10737418240

[root@dmrac2 rules.d]# blockdev --getsize64 /dev/raw/raw1
2147483648
[root@dmrac2 rules.d]# blockdev --getsize64 /dev/raw/raw2
2147483648
[root@dmrac2 rules.d]# blockdev --getsize64 /dev/raw/raw3
10737418240
[root@dmrac2 rules.d]# blockdev --getsize64 /dev/raw/raw4
10737418240
[root@dmrac2 rules.d]# blockdev --getsize64 /dev/raw/raw5
10737418240

六、配置dmdcr_cfg.ini文件
在2个节点的/dm7/data目录下创建配置文件dmdcr_cfg.ini,在文件中添加如下内容:

[root@dmrac1 /]# su - dmdba
[dmdba@dmrac1 ~]$ mkdir /dm7/data
[dmdba@dmrac1 ~]$cd /dm7/data
[dmdba@dmrac1 data]$ cat dmdcr_cfg.ini
DCR_N_GRP = 3
DCR_VTD_PATH = /dev/raw/raw2
DCR_OGUID = 63635

[GRP]
DCR_GRP_TYPE = CSS
DCR_GRP_NAME = GRP_CSS
DCR_GRP_N_EP = 2
DCR_GRP_DSKCHK_CNT = 60
[GRP_CSS]
DCR_EP_NAME = CSS0
DCR_EP_HOST = 10.10.10.161
DCR_EP_PORT = 9541
[GRP_CSS]
DCR_EP_NAME = CSS1
DCR_EP_HOST = 10.10.10.162
DCR_EP_PORT = 9542

[GRP]
DCR_GRP_TYPE = ASM
DCR_GRP_NAME = GRP_ASM
DCR_GRP_N_EP = 2
DCR_GRP_DSKCHK_CNT = 60
[GRP_ASM]
DCR_EP_NAME = ASM0
DCR_EP_SHM_KEY = 93360
DCR_EP_SHM_SIZE = 10
DCR_EP_HOST = 10.18.13.161
DCR_EP_PORT = 9641
DCR_EP_ASM_LOAD_PATH = /dev/raw
[GRP_ASM]
DCR_EP_NAME = ASM1
DCR_EP_SHM_KEY = 93361
DCR_EP_SHM_SIZE = 10
DCR_EP_HOST = 10.18.13.162
DCR_EP_PORT = 9642
DCR_EP_ASM_LOAD_PATH = /dev/raw

[GRP]
DCR_GRP_TYPE = DB
DCR_GRP_NAME = GRP_RAC
DCR_GRP_N_EP = 2
DCR_GRP_DSKCHK_CNT = 60
[GRP_RAC]
DCR_EP_NAME = RAC0
DCR_EP_SEQNO = 0
DCR_EP_PORT = 5236
DCR_CHECK_PORT = 9741
[GRP_RAC]
DCR_EP_NAME = RAC1
DCR_EP_SEQNO = 1
DCR_EP_PORT = 5236
DCR_CHECK_PORT = 9742


[root@dmrac2 /]# su - dmdba
[dmdba@dmrac2 ~]$ mkdir /dm7/data
[dmdba@dmrac2 ~]$cd /dm7/data
[dmdba@dmrac2 data]$ cat dmdcr_cfg.ini
DCR_N_GRP = 3
DCR_VTD_PATH = /dev/raw/raw2
DCR_OGUID = 63635

[GRP]
DCR_GRP_TYPE = CSS
DCR_GRP_NAME = GRP_CSS
DCR_GRP_N_EP = 2
DCR_GRP_DSKCHK_CNT = 60
[GRP_CSS]
DCR_EP_NAME = CSS0
DCR_EP_HOST = 10.10.10.161
DCR_EP_PORT = 9541
[GRP_CSS]
DCR_EP_NAME = CSS1
DCR_EP_HOST = 10.10.10.162
DCR_EP_PORT = 9542

[GRP]
DCR_GRP_TYPE = ASM
DCR_GRP_NAME = GRP_ASM
DCR_GRP_N_EP = 2
DCR_GRP_DSKCHK_CNT = 60
[GRP_ASM]
DCR_EP_NAME = ASM0
DCR_EP_SHM_KEY = 93360
DCR_EP_SHM_SIZE = 10
DCR_EP_HOST = 10.18.13.161
DCR_EP_PORT = 9641
DCR_EP_ASM_LOAD_PATH = /dev/raw
[GRP_ASM]
DCR_EP_NAME = ASM1
DCR_EP_SHM_KEY = 93361
DCR_EP_SHM_SIZE = 10
DCR_EP_HOST = 10.18.13.162
DCR_EP_PORT = 9642
DCR_EP_ASM_LOAD_PATH = /dev/raw

[GRP]
DCR_GRP_TYPE = DB
DCR_GRP_NAME = GRP_RAC
DCR_GRP_N_EP = 2
DCR_GRP_DSKCHK_CNT = 60
[GRP_RAC]
DCR_EP_NAME = RAC0
DCR_EP_SEQNO = 0
DCR_EP_PORT = 5236
DCR_CHECK_PORT = 9741
[GRP_RAC]
DCR_EP_NAME = RAC1
DCR_EP_SEQNO = 1
DCR_EP_PORT = 5236
DCR_CHECK_PORT = 9742

七、使用 DMASMCMD 工具初始化(任意一节点执行)

[dmdba@dmrac1 data]$ dmasmcmd
DMASMCMD V7.1.6.46-Build(2018.02.08-89107)ENT
ASM>create dcrdisk '/dev/raw/raw1' 'dcr'
the ASM initialize dcrdisk /dev/raw/raw1 to name DMASMdcr
Used time: 9.322(ms).
ASM>create votedisk '/dev/raw/raw2' 'vote'
the ASM initialize votedisk /dev/raw/raw2 to name DMASMvote
Used time: 6.251(ms).
ASM>create asmdisk '/dev/raw/raw3' 'LOG0'
the ASM initialize asmdisk /dev/raw/raw3 to name DMASMLOG0
Used time: 8.825(ms).
ASM>create asmdisk '/dev/raw/raw4' 'DATA0'
the ASM initialize asmdisk /dev/raw/raw4 to name DMASMDATA0
Used time: 6.145(ms).
ASM>init dcrdisk '/dev/raw/raw1' from '/dm7/data/dmdcr_cfg.ini' identified by 'dameng123'
[Trace]DG 126 allocate 4 extents for file 0xfe000002.
Check dcr disk failed, please check and try again
Used time: 84.489(ms).提示检查dcr磁盘失败请再次执行
ASM>init dcrdisk '/dev/raw/raw1' from '/dm7/data/dmdcr_cfg.ini' identified by 'dameng123'
[Trace]DG 126 allocate 4 extents for file 0xfe000002.
Used time: 00:00:06.078.
ASM>init votedisk '/dev/raw/raw2' from '/dm7/data/dmdcr_cfg.ini'
[Trace]DG 125 allocate 4 extents for file 0xfd000002.
Used time: 36.305(ms).

八、准备DMASM 的 MAL 配置文件
在2个节点的/dm7/data目录下创建 DMASM 的 MAL 配置文件(命名为 dmasvrmal.ini),使用 DMASM 的所有节点都要配置,内容完全一样。

[dmdba@dmrac1 data]$ vi dmasvrmal.ini
[MAL_INST1]
MAL_INST_NAME = ASM0
MAL_HOST = 10.10.10.161
MAL_PORT = 7236

[MAL_INST2]
MAL_INST_NAME = ASM1
MAL_HOST = 10.10.10.162
MAL_PORT = 7237
[dmdba@dmrac2 data]$ vi dmasvrmal.ini
[MAL_INST1]
MAL_INST_NAME = ASM0
MAL_HOST = 10.10.10.161
MAL_PORT = 7236

[MAL_INST2]
MAL_INST_NAME = ASM1
MAL_HOST = 10.10.10.162
MAL_PORT = 7237
~

九、准备dmdcr.ini 配置文件
dmdcr.ini 是 dmcss、dmasmsvr、dmasmtool 工具的输入参数。记录了当前节点序列号以及 DCR 磁盘路径。
在2个节点的/dm/dmdbms/data目录下创建dmdcr.ini 配置文件,dmdcr_path 相同,dmasvrmal.ini 文件内容也相同,dmdcr_seqo 分别为 0 和 1。
节点 1:

[dmdba@dmrac1 data]$ vi dmdcr.ini
DMDCR_PATH = /dev/raw/raw1
DMDCR_MAL_PATH =/dm7/data/dmasvrmal.ini
DMDCR_SEQNO = 0

#ASM
DMDCR_ASM_RESTART_INTERVAL = 0
DMDCR_ASM_STARTUP_CMD = /dm7/bin/dmasmsvr dcr_ini=/dm7/data/dmdcr.ini

#DB
DMDCR_DB_RESTART_INTERVAL = 0
DMDCR_DB_STARTUP_CMD = /dm7/bin/dmserver path=/dm7/data/rac0_config/dm.ini dcr_ini=/dm7/data/dmdcr.ini

节点2:

[dmdba@dmrac2 data]$ vi dmdcr.ini
DMDCR_PATH = /dev/raw/raw1
DMDCR_MAL_PATH =/dm7/data/dmasvrmal.ini
DMDCR_SEQNO = 1

#ASM
DMDCR_ASM_RESTART_INTERVAL = 0
DMDCR_ASM_STARTUP_CMD = /dm7/bin/dmasmsvr dcr_ini=/dm7/data/dmdcr.ini

#DB
DMDCR_DB_RESTART_INTERVAL = 0
DMDCR_DB_STARTUP_CMD = /dm7/bin/dmserver path=/dm7/data/rac1_config/dm.ini dcr_ini=/dm7/data/dmdcr.ini

十、启动DMCSS、DMASM 服务程序
1、注册 DMCSS和DMASM服务
节点一:

[root@dmrac1 ~]# /dm7/script/root/dm_service_installer.sh -t dmcss -i /dm7/data/dmdcr.ini -p rac1
Move the service script file(/dm7/bin/DmCSSServicerac1 to /etc/rc.d/init.d/DmCSSServicerac1)
Finished to create the service (DmCSSServicerac1)
[root@dmrac1 ~]# /dm7/script/root/dm_service_installer.sh -t dmasmsvr -i /dm7/data/dmdcr.ini -p rac1
Move the service script file(/dm7/bin/DmASMSvrServicerac1 to /etc/rc.d/init.d/DmASMSvrServicerac1)
Finished to create the service (DmASMSvrServicerac1)
[root@dmrac1 ~]#

节点二:

[root@dmrac2 ~]# /dm7/script/root/dm_service_installer.sh -t dmcss -i /dm7/data/dmdcr.ini -p rac2
Move the service script file(/dm7/bin/DmCSSServicerac2 to /etc/rc.d/init.d/DmCSSServicerac2)
Finished to create the service (DmCSSServicerac2)
[root@dmrac2 ~]# /dm7/script/root/dm_service_installer.sh -t dmasmsvr -i /dm7/data/dmdcr.ini -p rac2
Move the service script file(/dm7/bin/DmASMSvrServicerac2 to /etc/rc.d/init.d/DmASMSvrServicerac2)
Finished to create the service (DmASMSvrServicerac2)

2、启动DMCSS和DMASM服务
节点一:

[root@dmrac1 init.d]# service DmCSSServicerac1 start
Starting DmCSSServicerac1: [ OK ]
[root@dmrac1 init.d]# service DmASMSvrServicerac1 start
Starting DmASMSvrServicerac1: [ OK ]

节点二:

[root@dmrac2 init.d]# service DmCSSServicerac2 start
Starting DmCSSServicerac2: [ OK ]
[root@dmrac2 init.d]# service DmASMSvrServicerac2 start
Starting DmASMSvrServicerac2: [ OK ]

十一、创建DMASM磁盘组
在任意节点使用 dmasmtool 工具创建 DMASM 磁盘组。

[dmdba@dmrac1 ~]$ dmasmtool DCR_INI=/dm7/data/dmdcr.ini
DMASMTOOL V7.1.6.46-Build(2018.02.08-89107)ENT
ASM>create diskgroup 'DMLOG' asmdisk '/dev/raw/raw3'
Used time: 00:00:06.363.
ASM>create diskgroup 'DMDATA' asmdisk '/dev/raw/raw4'
Used time: 00:00:06.504.

十二、准备dminit.ini 配置文件
在2个节点的/dm/dmdbms/data目录下创建 dminit.ini 配置文件,添加如下内容。 在2个节点都创建。

[dmdba@dmrac1 data]$ vi dminit.ini
db_name = rac
system_path = +DMDATA/data
system = +DMDATA/data/rac/system.dbf
system_size = 128
roll = +DMDATA/data/rac/roll.dbf
roll_size = 128
main = +DMDATA/data/rac/main.dbf
main_size = 128
ctl_path = +DMDATA/data/rac/dm.ctl
ctl_size = 8
log_size = 256
dcr_path = /dev/raw/raw1 #dcr 磁盘路径,目前不支持 asm,只能是裸设备
dcr_seqno = 0
auto_overwrite = 1

[RAC0] #inst_name 跟 dmdcr_cfg.ini 中 DB 类型 group 中 DCR_EP_NAME 对应
config_path = /dm7/data/rac0_config
port_num = 5236
mal_host = 10.10.10.161
mal_port = 9340
log_path = +DMLOG/log/rac0_log01.log
log_path = +DMLOG/log/rac0_log02.log

[RAC1] #inst_name 跟 dmdcr_cfg.ini 中 DB 类型 group 中 DCR_EP_NAME 对应
config_path = /dm7/data/rac1_config
port_num = 5236
mal_host = 10.10.10.162
mal_port = 9341
log_path = +DMLOG/log/rac1_log01.log
log_path = +DMLOG/log/rac1_log02.log


[dmdba@dmrac2 data]$ vi dminit.ini
db_name = rac
system_path = +DMDATA/data
system = +DMDATA/data/rac/system.dbf
system_size = 128
roll = +DMDATA/data/rac/roll.dbf
roll_size = 128
main = +DMDATA/data/rac/main.dbf
main_size = 128
ctl_path = +DMDATA/data/rac/dm.ctl
ctl_size = 8
log_size = 256
dcr_path = /dev/raw/raw1 #dcr 磁盘路径,目前不支持 asm,只能是裸设备
dcr_seqno = 0
auto_overwrite = 1

[RAC0] #inst_name 跟 dmdcr_cfg.ini 中 DB 类型 group 中 DCR_EP_NAME 对应
config_path = /dm7/data/rac0_config
port_num = 5236
mal_host = 10.10.10.161
mal_port = 9340
log_path = +DMLOG/log/rac0_log01.log
log_path = +DMLOG/log/rac0_log02.log

[RAC1] #inst_name 跟 dmdcr_cfg.ini 中 DB 类型 group 中 DCR_EP_NAME 对应
config_path = /dm7/data/rac1_config
port_num = 5236
mal_host = 10.10.10.162
mal_port = 9341
log_path = +DMLOG/log/rac1_log01.log
log_path = +DMLOG/log/rac1_log02.log

十三、使用dminit初始化数据库
在任意节点启动 dminit 工具初始化数据库。dminit 执行完成后,会在 config_path 目录(/dm7/data/rac0_config 和/dm7/data/rac1_config)下生成配置文件 dm.ini 和 dmmal.ini。

[dmdba@dmrac1 data]$ dminit control=/dm7/data/dminit.ini
initdb V7.1.6.46-Build(2018.02.08-89107)ENT
db version: 0x7000a
file dm.key not found, use default license!
License will expire on 2020-05-08

log file path: +DMLOG/log/rac0_log01.log


log file path: +DMLOG/log/rac0_log02.log


log file path: +DMLOG/log/rac1_log01.log


log file path: +DMLOG/log/rac1_log02.log

write to dir [+DMDATA/data/rac].
create dm database success. 2020-04-24 16:39:03

将节点一的配置文件复制到节点二:

[dmdba@dmrac1 data]$ scp -r rac1_config 10.18.13.162:`pwd`
The authenticity of host '10.18.13.162 (10.18.13.162)' can't be established.
RSA key fingerprint is 89:fc:3e:e3:2d:27:94:07:0e:6b:fc:c5:e8:89:44:1f.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '10.18.13.162' (RSA) to the list of known hosts.
dmdba@10.18.13.162's password:
sqllog.ini 100% 479 0.5KB/s 00:00
dm.ini 100% 40KB 39.8KB/s 00:00
dmmal.ini 100% 204 0.2KB/s 00:00
[dmdba@dmrac1 data]$

十四、启动数据库服务器
1、在2个节点分别注册DM 数据库服务:
节点一:

[root@dmrac1 init.d]# /dm7/script/root/dm_service_installer.sh -t dmserver -i /dm7/data/rac0_config/dm.ini -d /dm7/data/dmdcr.ini -p rac1
Move the service script file(/dm7/bin/DmServicerac1 to /etc/rc.d/init.d/DmServicerac1)
Finished to create the service (DmServicerac1)

节点二:

[root@dmrac2 ~]# /dm7/script/root/dm_service_installer.sh -t dmserver -i /dm7/data/rac1_config/dm.ini -d /dm7/data/dmdcr.ini -p rac2
Move the service script file(/dm7/bin/DmServicerac2 to /etc/rc.d/init.d/DmServicerac2)
Finished to create the service (DmServicerac2)

2、启动数据库

[root@dmrac1 init.d]# service DmServicerac1 start
Starting DmServicerac1: [ OK ]

[root@dmrac2 ~]# service DmServicerac2 start
Starting DmServicerac2: [ OK ]

手工启动命令如下,手工启动后窗口不能关闭,所以

./dmserver /dm7/data/rac0_config/dm.ini dcr_ini=/dm7/data/dmdcr.ini
./dmserver /dm7/data/rac1_config/dm.ini dcr_ini=/dm7/data/dmdcr.ini

15 连接数据库验证
15.1 配置服务名文件

[dmdba@dmrac1 ~]$ vi /etc/dm_svc.conf
TIME_ZONE=(480)
rac=(10.18.13.161:5236,10.18.13.162:5236)
SWITCH_TIME=(10000)
SWITCH_INTERVAL=(10)

TIME_ZONE=(480)
LANGUAGE=(en)

[dmdba@dmrac2 ~]$ vi /etc/dm_svc.conf
TIME_ZONE=(480)
rac=(10.18.13.161:5236,10.18.13.162:5236)
SWITCH_TIME=(10000)
SWITCH_INTERVAL=(10)

TIME_ZONE=(480)
LANGUAGE=(en)

15.2 连接RAC集群
节点一:

[dmdba@dmrac1 ~]$ disql SYSDBA/SYSDBA@rac

Server[10.18.13.161:5236]:mode is normal, state is open
login used time: 10.365(ms)
disql V7.1.6.46-Build(2018.02.08-89107)ENT
Connected to: DM 7.1.6.46
SQL> select instance_name from v$instance;

LINEID INSTANCE_NAME
———- ————-
1 RAC0

used time: 18.248(ms). Execute id is 807.
SQL> select * from v$rac_ep_info;

LINEID EP_NAME EP_SEQNO EP_GUID EP_TIMESTAMP EP_MODE EP_STATUS
———- ——- ———– ——————– ——————– ——- ———
1 RAC0 0 2067076818 2067077298 MASTER OK
2 RAC1 1 2067098084 2067098537 SLAVE OK

used time: 2.741(ms). Execute id is 808.

节点二:

[dmdba@dmrac2 ~]$ disql SYSDBA/SYSDBA@rac

Server[10.18.13.162:5236]:mode is normal, state is open
login used time: 16.835(ms)
disql V7.1.6.46-Build(2018.02.08-89107)ENT
Connected to: DM 7.1.6.46
SQL> select instance_name from v$instance;

LINEID INSTANCE_NAME
---------- -------------
1 RAC1

used time: 106.703(ms). Execute id is 1.
SQL> select * from v$rac_ep_info;

LINEID EP_NAME EP_SEQNO EP_GUID EP_TIMESTAMP EP_MODE EP_STATUS
---------- ------- ----------- -------------------- -------------------- ------- ---------
1 RAC0 0 2067076818 2067077305 MASTER OK
2 RAC1 1 2067098084 2067098544 SLAVE OK

used time: 7.358(ms). Execute id is 2.

MySQL Version Tokens

MySQL 5.7.8或更高版本的发行版包括版本令牌,该特性支持创建和同步服务器令牌,应用程序可以使用这些令牌来防止访问不正确或过时的数据。

版本令牌接口具有这些特征:
.版本令牌是由用作键或标识符的名称和一个值组成的对
.版本令牌可以被锁定。应用程序可以使用令牌锁向其他协作应用程序表明正在使用令牌,不应该修改它们。
.每个服务器都建立版本令牌列表;例如,指定服务器分配或操作状态。此外,与服务器通信的应用程序可以注册自己的令牌列表,这些令牌表示它需要服务器处于的状态。应用程序发送到不处于所需状态的服务器的SQL语句将产生错误。这是给应用程序的一个信号,它应该寻找另一个处于所需状态的服务器来接收SQL语句。

以下部分描述了版本令牌的组件,讨论了如何安装和使用它,并为其组件提供参考信息。

版本标识组件
名为version_token的服务器端插件持有与服务器关联的版本令牌列表,并订阅语句执行事件的通知。version_token插件使用审计插件API来监视来自客户端的传入语句,并将每个客户端特定于会话的版本令牌列表与服务器版本令牌列表进行匹配。如果存在匹配,插件允许语句通过,服务器继续处理它。否则,插件将向客户端返回一个错误,语句将失败。

一组用户定义函数(udf)提供了一个sql级别的API,用于操作和检查插件维护的服务器版本令牌列表。调用任何的令牌udf版本

系统变量允许客户端指定注册所需服务器状态的版本令牌列表。如果客户端发送语句时服务器处于不同的状态,则客户端接收到一个错误

安装或卸载版本令牌

这里介绍如何安装或卸载版本令牌,这些令牌是在包含插件和用户定义函数的插件库文件中实现的。有关安装或卸载插件和udf的一般信息要使服务器可用,插件库文件必须位于MySQL插件目录中(由plugin_dir系统变量命名的目录)。如果需要,在服务器启动时设置plugin_dir的值,告诉服务器插件目录的位置

插件库的基本名是version_token。文件名后缀因平台而异(例如,对于Unix和类Unix系统,.dll为Windows).

要安装版本令牌插件和udf,请使用install plugin并创建函数语句(根据需要调整.so后缀):

mysql> INSTALL PLUGIN version_tokens SONAME 'version_token.so';
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id:    39
Current database: mysql

Query OK, 0 rows affected (0.07 sec)

mysql> CREATE FUNCTION version_tokens_set RETURNS STRING SONAME 'version_token.so';
Query OK, 0 rows affected (0.02 sec)

mysql> CREATE FUNCTION version_tokens_show RETURNS STRING SONAME 'version_token.so';
Query OK, 0 rows affected (0.02 sec)

mysql> CREATE FUNCTION version_tokens_edit RETURNS STRING SONAME 'version_token.so';
Query OK, 0 rows affected (0.02 sec)

mysql> CREATE FUNCTION version_tokens_delete RETURNS STRING SONAME 'version_token.so';
CREATE FUNCTION version_tokens_lock_shared RETURNS STRING SONAME 'version_token.so';
Query OK, 0 rows affected (0.02 sec)

mysql> CREATE FUNCTION version_tokens_lock_shared RETURNS STRING SONAME 'version_token.so';
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE FUNCTION version_tokens_lock_exclusive RETURNS STRING SONAME 'version_token.so';
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE FUNCTION version_tokens_unlock RETURNS STRING SONAME 'version_token.so';
Query OK, 0 rows affected (0.03 sec)

您必须安装udf来管理服务器的版本令牌列表,但是您还必须安装插件,因为没有它udf将无法正常工作。

如果在主复制服务器上使用插件和udf,也要将它们安装在所有从服务器上,以避免复制问题

如前所述,一旦安装完成,版本令牌插件和udf将一直保持安装状态,直到卸载为止。要删除它们,使用UNINSTALL插件和DROP FUNCTION语句:

mysql> uninstall plugin version_tokens;
Query OK, 0 rows affected, 1 warning (0.02 sec)

mysql> drop function version_tokens_set;
drop function version_tokens_show;
Query OK, 0 rows affected (0.02 sec)

mysql> drop function version_tokens_show;
drop function version_tokens_edit;
Query OK, 0 rows affected (0.00 sec)

mysql> drop function version_tokens_edit;
Query OK, 0 rows affected (0.00 sec)

mysql> drop function version_tokens_delete;
Query OK, 0 rows affected (0.01 sec)

mysql> drop function version_tokens_lock_shared;
Query OK, 0 rows affected (0.00 sec)

mysql> drop function version_tokens_lock_exclusive;
Query OK, 0 rows affected (0.00 sec)

mysql> drop function version_tokens_unlock;
Query OK, 0 rows affected (0.02 sec)

使用版本标记
版本令牌可能有用的一个场景是,系统访问MySQL服务器集合,但是需要通过监视它们并根据负载变化调整服务器分配来管理它们,以实现负载平衡。这样一个系统包括这些组件
.要管理的MySQL服务器集合
.与服务器通信并将它们组织成高可用性组的管理或管理应用程序。组有不同的用途,每个组中的服务器可能有不同的分配。某个组内的服务器的分配可以随时更改
.访问服务器以检索和更新数据的客户机应用程序,根据分配给它们的用途选择服务器。例如,客户端不应该向只读服务器发送更新

版本令牌允许根据分配对服务器访问进行管理,而不需要客户端重复查询服务器的分配
.管理应用程序执行服务器分配并在每个服务器上建立版本令牌以反映其分配。应用程序缓存此信息以提供对其的中央访问点。如果在某个时候管理应用程序需要更改服务器分配(例如,将其从允许写改为仅允许读),则它将更改服务器的版本令牌列表并更新其缓存。

.为了提高性能,客户端应用程序从管理应用程序获取缓存信息,使它们不必为每个语句检索关于服务器分配的信息。基于它将发出的语句类型(例如,读与写),客户端选择适当的服务器并连接到它

.此外,客户端向服务器发送自己的客户端特定版本的令牌来注册它需要的服务器分配。对于客户端发送到服务器的每个语句,服务器将自己的令牌列表与客户端令牌列表进行比较。如果服务器令牌列表包含客户端令牌列表中所有具有相同值的令牌,则存在匹配,服务器执行该语句

另一方面,可能管理应用程序更改了服务器分配及其版本令牌列表。在这种情况下,新的服务器分配现在可能与客户端需求不兼容。服务器和客户端令牌列表之间的令牌不匹配,服务器返回一个错误作为对语句的应答。这指示客户机从管理应用程序缓存中刷新其版本令牌信息,并选择要与之通信的新服务器。

检测版本令牌错误和选择新服务器的客户端逻辑可以通过不同的方式实现:
.客户端可以自己处理所有版本令牌注册、不匹配检测和连接切换
.这些操作的逻辑可以在管理客户端和MySQL服务器之间连接的连接器中实现。这样的连接器可以处理错配错误检测和语句重新发送本身,也可以将错误传递给应用程序,并将其留给应用程序重新发送语句。

下面的例子以更具体的形式说明了前面的讨论。
当版本令牌在给定服务器上初始化时,服务器的版本令牌列表为空。通过调用用户定义函数(udf)来执行令牌列表维护。调用任何版本令牌udf都需要超级特权,因此具有该特权的管理或管理应用程序需要修改令牌列表。

假设一个管理应用程序与一组服务器通信,客户端查询这些服务器以访问雇员和产品数据库(分别名为emp和prod)。所有服务器都被允许处理数据检索语句,但只有一部分服务器被允许进行数据库更新。为了在特定于数据库的基础上处理这个问题,管理应用程序在每个服务器上建立一个版本令牌列表。在给定服务器的令牌列表中,令牌名称表示数据库名称,读写令牌值取决于数据库是否必须以只读方式使用,或者是否可以进行读写。

客户端应用程序通过设置系统变量来注册它们需要服务器匹配的版本令牌列表。变量设置是在客户端特定的基础上进行的,因此不同的客户端可以注册不同的需求。默认情况下,客户端令牌列表是空的,它匹配任何服务器令牌列表。当客户端将其令牌列表设置为非空值时,匹配可能成功也可能失败,这取决于服务器版本令牌列表。

为了定义服务器的版本令牌列表,管理应用程序调用version_token_set() UDF。(稍后将介绍用于修改和显示令牌列表的udf。)例如,应用程序可能将这些语句发送到三个服务器组成的组
服务器1:

mysql> SELECT version_tokens_set('emp=read;prod=read');
+------------------------------------------+
| version_tokens_set('emp=read;prod=read') |
+------------------------------------------+
| 2 version tokens set.                    |
+------------------------------------------+
1 row in set (0.03 sec)

服务器2:

mysql> SELECT version_tokens_set('emp=write;prod=read');
+-------------------------------------------+
| version_tokens_set('emp=write;prod=read') |
+-------------------------------------------+
| 2 version tokens set.                     |
+-------------------------------------------+
1 row in set (0.00 sec)

服务器3:

mysql> SELECT version_tokens_set('emp=read;prod=write');
+-------------------------------------------+
| version_tokens_set('emp=read;prod=write') |
+-------------------------------------------+
| 2 version tokens set.                     |
+-------------------------------------------+
1 row in set (0.00 sec)

在每种情况下,令牌列表都被指定为以分号分隔的名称=值对列表。产生的令牌列表值导致这些服务器连接:
.任何服务器都会接受对两个数据库中的任意一个进行读取
.只有服务器2接受对emp数据库的更新
.只有服务器3接受对prod数据库的更新

除了为每个服务器分配一个版本令牌列表外,管理应用程序还维护一个反映服务器分配的缓存。

在与服务器通信之前,客户机应用程序与管理应用程序进行联系,并检索关于服务器分配的信息。然后客户端根据这些分配选择服务器。假设客户机希望同时执行对emp数据库的读写操作。根据前面的分配,只有服务器2合格。客户机连接到服务器2,并通过设置
version_tokens_session系统变量在服务器2上注册服务器需求:

mysql> SET @@session.version_tokens_session = 'emp=write';
Query OK, 0 rows affected (0.00 sec)

对于客户机发送到服务器2的后续语句,服务器将自己的版本令牌列表与客户机列表进行比较,以检查它们是否匹配。如果是,则语句正常执行:

mysql> UPDATE emp.employee SET salary = salary * 1.1 WHERE id = 4981;
Query OK, 1 row affected (0.07 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT last_name, first_name FROM emp.employee WHERE id = 4981;
+-----------+------------+
| last_name | first_name |
+-----------+------------+
| Smith | Abe |
+-----------+------------+
1 row in set (0.01 sec)

服务器和客户端版本令牌列表之间的差异可能以两种方式出现:
.version_tokens_session值中的令牌名称在服务器令牌列表中不存在。在这种情况下会发生ER_VTOKEN_PLUGIN_TOKEN_NOT_FOUND错误
.version_tokens_session值中的令牌值与服务器令牌列表中相应令牌的值不同。在这种情况下将出现ER_VTOKEN_PLUGIN_TOKEN_MISMATCH错误

只要服务器2的分配没有改变,客户端就会继续使用它进行读写。但是,假设管理应用程序希望更改服务器分配,以便emp数据库的写操作必须发送到服务器1而不是服务器2。为此,它使用version_tokens_edit()修改两个服务器上的emp令牌值(并更新其服务器分配缓存):
服务器1:

mysql> SELECT version_tokens_edit('emp=write');
+----------------------------------+
| version_tokens_edit('emp=write') |
+----------------------------------+
| 1 version tokens updated.        |
+----------------------------------+
1 row in set (0.00 sec)

服务器2:

mysql> SELECT version_tokens_edit('emp=read');
+---------------------------------+
| version_tokens_edit('emp=read') |
+---------------------------------+
| 1 version tokens updated.       |
+---------------------------------+
1 row in set (0.00 sec)

version_tokens_edit()修改服务器令牌列表中的指定令牌而其它的令牌不会改变。

当客户机下一次向服务器2发送一条语句时,它自己的令牌列表将不再与服务器令牌列表匹配,并出现一个错误

mysql> UPDATE emp.employee SET salary = salary * 1.1 WHERE id = 4982;
ERROR 3136 (42000): Version token mismatch for emp. Correct value read

在这种情况下,客户端应该联系管理应用程序以获得关于服务器分配的更新信息,选择一个新服务器,并将失败的语句发送到新服务器

注意:每个客户端必须与版本令牌进行协作,仅根据它在给定服务器上注册的令牌列表发送语句。例如,如果客户端注册了一个’emp=read’的令牌列表,版本令牌中没有任何内容可以阻止客户端发送emp数据库的更新。客户本身必须避免这样做

对于从客户机接收到的每个语句,服务器隐式地使用锁,如下所示:
.为客户端令牌列表(即version_tokens_session值)中命名的每个令牌获取一个共享锁
.执行服务器和客户端令牌列表之间的比较
.根据比较结果执行语句或产生错误
.释放锁

服务器使用共享锁,以便可以在不阻塞的情况下对多个会话进行比较,同时防止对任何试图在操作服务器令牌列表中具有相同名称的令牌之前获取独占锁的会话的令牌进行更改

前面的例子只使用了版本标记插件库中包含的一些用户定义,但是还有其他的。一组udf允许对服务器的版本令牌列表进行操作和检查。另一组udf允许锁定和解锁版本标记

这些udf允许创建、更改、删除和检查服务器的版本标记列表:
.version_tokens_set()完全替换当前列表并分配一个新列表。参数是一个以分号分隔的名称=值对列表。
.version_tokens_edit()支持对当前列表进行部分修改。它可以添加新的令牌或更改现有令牌的值。参数是一个以分号分隔的名称=值对列表
.version_tokens_delete()从当前列表中删除令牌。参数是一个用分号分隔的令牌名称列表
.version_tokens_show()显示当前令牌列表。不需要任何论证

这些函数中的每一个,如果成功,将返回一个指示操作发生的二进制字符串。下面的示例建立服务器令牌列表,通过添加新令牌对其进行修改,删除一些令牌,并显示生成的令牌列表:

mysql> SELECT version_tokens_set('tok1=a;tok2=b');
+-------------------------------------+
| version_tokens_set('tok1=a;tok2=b') |
+-------------------------------------+
| 2 version tokens set.               |
+-------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT version_tokens_edit('tok3=c');
+-------------------------------+
| version_tokens_edit('tok3=c') |
+-------------------------------+
| 1 version tokens updated.     |
+-------------------------------+
1 row in set (0.00 sec)

mysql> SELECT version_tokens_delete('tok2;tok1');
+------------------------------------+
| version_tokens_delete('tok2;tok1') |
+------------------------------------+
| 2 version tokens deleted.          |
+------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT version_tokens_show();
+-----------------------+
| version_tokens_show() |
+-----------------------+
| tok3=c;               |
+-----------------------+
1 row in set (0.00 sec)

如果令牌列表格式不正确,就会出现警告:

mysql> SELECT version_tokens_set('tok1=a; =c');
+----------------------------------+
| version_tokens_set('tok1=a; =c') |
+----------------------------------+
| 1 version tokens set.            |
+----------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql> show warnings \G
*************************** 1. row ***************************
  Level: Warning
   Code: 42000
Message: Invalid version token pair encountered. The list provided is only partially updated.
1 row in set (0.00 sec)

如前所述,版本标记是使用一个以分号分隔的名称=值对列表来定义的。考虑一下version_tokens_set()的调用:

mysql> SELECT version_tokens_set('tok1=b;;; tok2= a = b ; tok1 = 1\'2 3"4');
+---------------------------------------------------------------+
| version_tokens_set('tok1=b;;; tok2= a = b ; tok1 = 1\'2 3"4') |
+---------------------------------------------------------------+
| 3 version tokens set.                                         |
+---------------------------------------------------------------+
1 row in set (0.00 sec)

版本标记对参数的解释如下:
.名称和值周围的空白将被忽略。允许在名称和值中使用空格。(对于version_tokens_delete(),它接受一个没有值的名称列表,名称周围的空白将被忽略。)
.没有报价机制
.令牌的顺序并不重要,除非令牌列表包含给定令牌名称的多个实例,否则最后一个值优先于前面的值

根据这些规则,前面的version_tokens_set()调用会产生一个令牌列表,其中包含两个令牌:tok1的值是1’2 3’4,tok2的值是a = b。

mysql> SELECT version_tokens_show();
+--------------------------+
| version_tokens_show()    |
+--------------------------+
| tok2=a = b;tok1=1'2 3"4; |
+--------------------------+
1 row in set (0.01 sec)

如果令牌列表包含两个令牌,为什么version_tokens_set()返回设置的值3版本令牌?这是因为原来的令牌列表包含两个tok1定义,而第二个定义替换了第一个定义。

版本标记令牌操作udf将这些约束放在令牌名称和值上:
.令牌名称不能包含=或;字符,最大长度为64个字符
.令牌值不能包含;字符。值的长度受到max_allowed_packet系统变量的值的限制
.版本令牌将令牌名称和值视为二进制字符串,因此比较是区分大小写的

版本令牌还包括一组udf,允许对令牌进行锁定和解锁:
.version_tokens_lock_exclusive()获得独占的版本令牌锁。它接受一个或多个锁名和超时值的列表
.version_tokens_lock_shared()获得共享版本令牌锁。它接受一个或多个锁名和超时值的列表
.version_tokens_unlock()释放版本令牌锁(独占和共享)。不需要任何论证

每个锁定函数都返回非零表示成功。否则,将发生错误:

mysql> SELECT version_tokens_lock_shared('lock1', 'lock2', 0);
+-------------------------------------------------+
| version_tokens_lock_shared('lock1', 'lock2', 0) |
+-------------------------------------------------+
| 1 |
+-------------------------------------------------+
mysql> SELECT version_tokens_lock_shared(NULL, 0);
ERROR 3131 (42000): Incorrect locking service lock name '(null)'.

使用版本标记锁定功能的锁定是建议的;申请必须同意合作。

可以锁定不存在的令牌名称。这不会创建令牌。

对于版本令牌锁定函数,令牌名称参数完全按照指定的方式使用。周围的空白不被忽略,并且=和;字符是允许的。这是因为令牌只是像传递
给锁定服务一样传递要锁定的令牌名称。

版本标记引用

版本标记功能
版本令牌插件库包含几个用户定义的函数。一组udf允许对服务器的版本令牌列表进行操作和检查。另一组udf允许锁定和解锁版本标记。调用任何版本令牌UDF都需要超级特权。

下面的udf允许创建、更改、删除和检查服务器的版本令牌列表:
.version_tokens_delete (name_list)
使用name_list参数从服务器的版本令牌列表中删除令牌,并返回指示操作结果的二进制字符串。name_list是要删除的版本令牌名称的分号分隔列表。

mysql> SELECT version_tokens_delete('tok1;tok3');
+------------------------------------+
| version_tokens_delete('tok1;tok3') |
+------------------------------------+
| 2 version tokens deleted.          |
+------------------------------------+
1 row in set (0.00 sec)

从MySQL 5.7.9开始,NULL参数被视为空字符串,这对令牌列表没有影响。
version_tokens_delete()删除其参数中指定的标记(如果它们存在的话)。(删除不存在的令牌不是错误。)要在不知道列表中有哪些令牌的情况下完全清除令牌列表,请将NULL或不包含令牌的字符串传递给version_tokens_set():

mysql> SELECT version_tokens_set(NULL);
+------------------------------+
| version_tokens_set(NULL)     |
+------------------------------+
| Version tokens list cleared. |
+------------------------------+
1 row in set (0.00 sec)

mysql> SELECT version_tokens_set('');
+------------------------------+
| version_tokens_set('')       |
+------------------------------+
| Version tokens list cleared. |
+------------------------------+
1 row in set (0.00 sec)

.version_tokens_edit (token_list)
使用token_list参数修改服务器的版本令牌列表,并返回指示操作结果的二进制字符串。token_list是一个以分号分隔的名称=值对列表,它指定要定义的每个令牌的名称及其值。如果存在令牌,则使用给定的值更新其值。如果标记不存在,则使用给定的值创建它。如果参数为NULL或字符串不包含令牌,则令牌列表保持不变。

mysql> SELECT version_tokens_set('tok1=value1;tok2=value2');
+-----------------------------------------------+
| version_tokens_set('tok1=value1;tok2=value2') |
+-----------------------------------------------+
| 2 version tokens set.                         |
+-----------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT version_tokens_edit('tok2=new_value2;tok3=new_value3');
+--------------------------------------------------------+
| version_tokens_edit('tok2=new_value2;tok3=new_value3') |
+--------------------------------------------------------+
| 2 version tokens updated.                              |
+--------------------------------------------------------+
1 row in set (0.00 sec)

.version_tokens_set (token_list)
用token_list参数中定义的令牌替换服务器的版本令牌列表,并返回指示操作结果的二进制字符串。token_list是一个用分号分隔的名称=值对列表,指定要定义的每个令牌的名称及其值。如果参数为空或字符串不包含令牌,则清除令牌列表。

mysql> SELECT version_tokens_set('tok1=value1;tok2=value2');
+-----------------------------------------------+
| version_tokens_set('tok1=value1;tok2=value2') |
+-----------------------------------------------+
| 2 version tokens set.                         |
+-----------------------------------------------+
1 row in set (0.00 sec)

.version_tokens_show()
以二进制字符串的形式返回服务器的版本标记列表,其中包含一个以分号分隔的名称=值对列表。

mysql> SELECT version_tokens_show();
+--------------------------+
| version_tokens_show()    |
+--------------------------+
| tok2=value2;tok1=value1; |
+--------------------------+
1 row in set (0.00 sec)

下面的udf允许锁定和解锁版本标记:
.version_tokens_lock_exclusive (token_name [token_name]…超时)
获取一个或多个版本令牌(按名称指定为字符串)上的独占锁,如果未在给定的超时值内获取锁,则超时并报错

mysql> SELECT version_tokens_lock_exclusive('lock1', 'lock2', 10);
+-----------------------------------------------------+
| version_tokens_lock_exclusive('lock1', 'lock2', 10) |
+-----------------------------------------------------+
| 1 |
+-----------------------------------------------------+

这个函数是在MySQL 5.7.8中添加的,名为vtoken_get_write_locks(),在5.7.9中重命名为version_tokens_lock_exclusive()

.version_tokens_lock_shared (token_name [token_name]…超时)
获取一个或多个版本令牌(按名称指定为字符串)上的共享锁,如果未在给定的超时值内获取锁,则超时并报错

mysql> SELECT version_tokens_lock_shared('lock1', 'lock2', 10);
+--------------------------------------------------+
| version_tokens_lock_shared('lock1', 'lock2', 10) |
+--------------------------------------------------+
| 1 |
+--------------------------------------------------+

这个函数是在MySQL 5.7.8中添加的,名为vtoken_get_read_locks(),在5.7.9中重命名为version_tokens_lock_shared()

.version_tokens_unlock ()
使用version_tokens_lock_exclusive()和version_tokens_lock_shared()释放在当前会话中获取的所有锁。

mysql> SELECT version_tokens_unlock();
+-------------------------+
| version_tokens_unlock() |
+-------------------------+
| 1 |
+-------------------------+

这个函数是在MySQL 5.7.8中添加的,名为vtoken_release_locks(),在5.7.9中重命名为version_tokens_unlock()。

锁定功能共享这些特性:
.对于成功,返回值为非零。否则,将发生错误
.令牌名称是字符串
.与操作服务器令牌列表的udf的参数处理不同,令牌名称参数周围的空白不会被忽略,并且=和;字符是允许的
.可以锁定不存在的令牌名称。这不会创建令牌
.超时值是非负整数,表示在出现错误超时之前等待获取锁所需的时间(以秒为单位)。如果超时为0,则不存在等待,如果不能立即获取锁,则该函数将产生一个错误
.版本令牌锁定功能基于所描述的锁定服务在Section 28.3.1 锁服务中描述。

版本令牌系统变量
版本标记支持以下系统变量。这些变量不可用,除非安装版本令牌插件

系统变量:
.version_tokens_session
命令行格式:–version-tokens-session=value
变量范围:Global,Session
动态:Yes
允许的值:类型为字符串,默认值为NULL
此变量的会话值指定客户端版本令牌列表,并指示客户端会话要求服务器版本令牌列表具有的令牌。

如果version_tokens_session变量为NULL(默认值)或值为空,则任何服务器版本令牌列表都是匹配的。(实际上,空值会禁用匹配需求。)

如果version_tokens_session变量有一个非空值,那么它的值与服务器版本令牌列表之间的任何不匹配都会导致会话发送给服务器的任何语句出错。在这种情况下会发生失配:
.version_tokens_session值中的令牌名称在服务器令牌列表中不存在。在本例中,发生了ER_VTOKEN_PLUGIN_TOKEN_NOT_FOUND错误
.version_tokens_session值中的令牌值与服务器令牌列表中相应令牌的值不同。在本例中,将出现ER_VTOKEN_PLUGIN_TOKEN_MISMATCH错误

服务器版本令牌列表中包含没有在version_tokens_session值中命名的令牌不是不匹配的

假设一个管理应用程序将服务器令牌列表设置为如下所示:

mysql> SELECT version_tokens_set('tok1=a;tok2=b;tok3=c');
+--------------------------------------------+
| version_tokens_set('tok1=a;tok2=b;tok3=c') |
+--------------------------------------------+
| 3 version tokens set. |
+--------------------------------------------+

客户端通过设置其version_tokens_session值来注册它需要服务器匹配的令牌。然后,对于客户端发送的每个后续语句,服务器将根据客户
端version_tokens_session值检查其令牌列表,如果存在不匹配,则产生一个错误:

mysql> SET @@session.version_tokens_session = 'tok1=a;tok2=b';
mysql> SELECT 1;
+---+
| 1 |
+---+
| 1 |
+---+
mysql> SET @@session.version_tokens_session = 'tok1=b';
mysql> SELECT 1;
ERROR 3136 (42000): Version token mismatch for tok1. Correct value a

第一个选择成功是因为客户端令牌tok1和tok2出现在服务器令牌列表中,并且每个令牌在服务器列表中具有相同的值。第二个SELECT失败是因为,虽然tok1出现在服务器令牌列表中,但它的值与客户机指定的值不同

此时,客户端发送的任何语句都将失败,除非服务器令牌列表发生更改,使其再次匹配。假设管理应用程序按如下方式更改服务器令牌列表:

mysql> SELECT version_tokens_edit('tok1=b');
+-------------------------------+
| version_tokens_edit('tok1=b') |
+-------------------------------+
| 1 version tokens updated. |
+-------------------------------+
mysql> SELECT version_tokens_show();
+-----------------------+
| version_tokens_show() |
+-----------------------+
| tok3=c;tok1=b;tok2=b; |
+-----------------------+

现在,客户机version_tokens_session值与服务器令牌列表匹配,客户机可以再次成功执行语句:

mysql> SELECT 1;
+---+
| 1 |
+---+
| 1 |
+---+

这个变量是在MySQL 5.7.8中添加的
.version_tokens_session_number
命令行格式:–version-tokens-session-number=N
变量范围:Global,Session
动态:NO
允许的值:类型为整型,默认值为0
此变量供内部使用。
这个变量是在MySQL 5.7.8中添加的。

DMRAC缓存交换

缓存交换
根据目前的硬件发展状况来看,网络的传输速度比磁盘的读、写速度更快,因此,DMRAC集群引入了缓存交换(Buffer Swap)技术,节点间的数据页尽可能通过网络传递,避免通过磁盘的写入、再读出方式在节点间传递数据,从而减少数据库的IO等待时间,提升系统的响应速度。

缓存交换的实现基础是GBS/LBS服务,在GBS/LBS中维护了Buffer数据页的相关信息。包括:1. 闩的封锁权限(LATCH);2. 哪些站点访问过此数据页(Access MAP);3. 最新数据保存在哪一个节点(Fresh EP)中;4. 以及最新数据页的LSN值(Fresh LSN)等信息。这些信息作为LBS封锁、GBS授权和GBS权限回收请求的附加信息进行传递,因此并不会带来额外的通讯开销。

下面,以两节点DMRAC集群(EP0/EP1)访问数据页P1为例子。初始页P1位于共享存储上,P1的GBS控制结构位于节点EP1上。初始页P1还没有被任何一个节点访问过,初始页P1的LSN为10000。通过几种常见场景分析,逐步深入,解析缓存交换的原理。
场景1
节点EP0访问数据页P1。
1. 节点EP0的本地LBS向EP1的GBS请求数据页P1的S LATCH权限
2. 节点EP1的GBS修改P1控制结构,记录访问节点EP0的封锁模式为S LATCH(数据分布节点为EP0),并响应EP0的LBS请求
3. 节点EP0的LBS获得GBS授权后,记录获得的授权模式是S_LATCH,P1数据不在其他节点的Buffer中,发起本地IO请求,从磁盘读取数据。
IO完成后,修改LBS控制结构,记录数据页上的LSN信息

场景2
节点EP1访问数据页P1。
1. 节点EP1本地LBS向EP1的GBS请求数据页P1的S LATCH权限
2. 节点EP1的GBS修改控制结构,记录访问节点EP1的封锁模式为S LATCH(数据分布节点为EP0/EP1),并响应EP1的LBS请求
3. 节点EP1的LBS获得GBS授权后,记录获得的授权模式是S LATCH,根据数据分布情况,EP1向EP0发起P1的读请求,通过内部网络从EP0获取
数据,而不是重新从磁盘读取P1数据

场景3
节点EP0修改数据页P1。
1. 节点EP0本地LBS向EP1的GBS请求数据页P1的X LATCH权限(附加LSN信息)
2. 节点EP1的GBS修改控制结构的LSN值,从EP1的LBS回收P1的权限
3. 修改访问节点EP0的封锁模式为S + X LATCH,并响应EP0的LBS请求
4. 节点EP0的LBS获得GBS授权后,记录获得的授权模式是S + X LATCH
5. 节点EP0修改数据页P1,LSN修改为11000
这个过程中,只有全局Latch请求,数据页并没有在节点间传递。

修改之后,数据页P1的LSN修改为11000。如下所示:

场景4
节点EP1修改数据页P1。
1.节点EP1本地LBS向EP1的GBS请求数据页P1的X LATCH权限
2.节点EP1的GBS发现P1被EP0以S + X方式封锁,向EP0发起回收P1权限的请求
3.节点EP0释放P1的全局LATCH,响应GBS,并且在响应消息中附加了最新的PAGE LSN值
4.节点EP1的GBS收到EP0的响应后,修改GBS控制结构,记录最新数据保存在EP0,最新的LSN值信息,记录EP0获得的授权模式是S + X LATCH
(此时,数据分布节点仍然是EP0/EP1),并授权EP1的LBS
5.节点EP1的LBS收到授权信息后,记录获得的授权模式是S + X LATCH,并根据数据分布情况,向节点EP0发起数据页P1的读请求
6.节点EP1修改数据页P1,LSN修改为12000

修改之后,数据页P1的LSN修改为12000。如下所示:

这个过程中,数据页P1的最新数据从EP0传递到了EP1,但并没有产生磁盘IO。

达梦7异构(DM-Oracle) DBLINK

使用DM数据库,创建一个连接到IP地址为10.10.10.180机器上的oracle数据库的外部链接。可以通过三种方式创建:一网络服务名tsn_name;二连接描述符description;三/< 服务名>。

(一) 通过网络服务名创建
首先介绍Oracle网络服务名的配置方法。网络服务名配置成功才能创建DBLINK
安装Oracle客户端挺费时间的,而且大部分功能都用不到,Oracle官方给出了简易客户端,直接解压就可以使用,下载地址:http://www.oracle.com/technetwork/topics/linuxx86-64soft-092277.html
下面来看安装步骤:
1、下载安装包,我这里把所有的都下载下来了

 [root@dmks soft]# ls -lrt
总用量 2293896
drwxr-xr-x. 19 1000 1000       4096 4月  20 2010 unixODBC-2.3.0
drwxrwxr-x.  5  502  502       4096 1月  27 2017 client
-rw-r--r--.  1  502  502 1258314437 3月   2 2017 linuxx64_12201_client.zip
-rw-r--r--.  1 root root  493170688 3月  19 2018 dm7_setup_neokylin6_64_20180209.iso
-rw-r--r--.  1 root root  488814959 3月   4 15:19 DM_linux64.zip
drwxr-xr-x.  2 root root       4096 3月   6 19:47 dm_soft
-rw-r--r--.  1 root root    1804749 3月  11 17:20 unixODBC-2.3.0.tar.gz
-rw-r--r--.  1 root root     904309 3月  21 18:38 instantclient-sqlplus-linux.x64-12.2.0.1.0.zip
-rw-r--r--.  1 root root   68965195 3月  21 18:42 instantclient-basic-linux.x64-12.2.0.1.0.zip
-rw-r--r--.  1 root root     674743 3月  21 18:45 instantclient-sdk-linux.x64-12.2.0.1.0.zip
-rw-r--r--.  1 root root    1572942 3月  21 22:51 instantclient-jdbc-linux.x64-12.2.0.1.0.zip
-rw-r--r--.  1 root root     634023 3月  21 22:51 instantclient-odbc-linux.x64-12.2.0.1.0-2.zip
-rw-r--r--.  1 root root   32917466 3月  21 22:51 instantclient-basiclite-linux.x64-12.2.0.1.0.zip
-rw-r--r--.  1 root root    1132671 3月  21 22:52 instantclient-tools-linux.x64-12.2.0.1.0.zip

2、unzip解压
解压出来一个目录instantclient_12_2

[root@dmks soft]# unzip instantclient-sqlplus-linux.x64-12.2.0.1.0.zip
Archive:  instantclient-sqlplus-linux.x64-12.2.0.1.0.zip
  inflating: instantclient_12_2/glogin.sql
  inflating: instantclient_12_2/libsqlplusic.so
  inflating: instantclient_12_2/libsqlplus.so
  inflating: instantclient_12_2/sqlplus
  inflating: instantclient_12_2/SQLPLUS_README
[root@dmks soft]# unzip instantclient-basic-linux.x64-12.2.0.1.0.zip
Archive:  instantclient-basic-linux.x64-12.2.0.1.0.zip
  inflating: instantclient_12_2/adrci
  inflating: instantclient_12_2/BASIC_README
  inflating: instantclient_12_2/genezi
  inflating: instantclient_12_2/libclntshcore.so.12.1
  inflating: instantclient_12_2/libclntsh.so.12.1
  inflating: instantclient_12_2/libipc1.so
  inflating: instantclient_12_2/libmql1.so
  inflating: instantclient_12_2/libnnz12.so
  inflating: instantclient_12_2/libocci.so.12.1
  inflating: instantclient_12_2/libociei.so
  inflating: instantclient_12_2/libocijdbc12.so
  inflating: instantclient_12_2/libons.so
  inflating: instantclient_12_2/liboramysql12.so
  inflating: instantclient_12_2/ojdbc8.jar
  inflating: instantclient_12_2/uidrvci
  inflating: instantclient_12_2/xstreams.jar
[root@dmks soft]# unzip instantclient-sdk-linux.x64-12.2.0.1.0.zip
Archive:  instantclient-sdk-linux.x64-12.2.0.1.0.zip
   creating: instantclient_12_2/sdk/
  inflating: instantclient_12_2/sdk/ott
 extracting: instantclient_12_2/sdk/ottclasses.zip
  inflating: instantclient_12_2/sdk/SDK_README
   creating: instantclient_12_2/sdk/demo/
  inflating: instantclient_12_2/sdk/demo/setuporamysql.sh
  inflating: instantclient_12_2/sdk/demo/occiobj.typ
  inflating: instantclient_12_2/sdk/demo/occidml.cpp
  inflating: instantclient_12_2/sdk/demo/occidemo.sql
  inflating: instantclient_12_2/sdk/demo/occiobj.cpp
  inflating: instantclient_12_2/sdk/demo/occidemod.sql
  inflating: instantclient_12_2/sdk/demo/oraaccess.xml
  inflating: instantclient_12_2/sdk/demo/demo.mk
  inflating: instantclient_12_2/sdk/demo/cdemo81.c
   creating: instantclient_12_2/sdk/include/
  inflating: instantclient_12_2/sdk/include/occiControl.h
  inflating: instantclient_12_2/sdk/include/oro.h
  inflating: instantclient_12_2/sdk/include/ociapr.h
  inflating: instantclient_12_2/sdk/include/occiCommon.h
  inflating: instantclient_12_2/sdk/include/occiData.h
  inflating: instantclient_12_2/sdk/include/oci8dp.h
  inflating: instantclient_12_2/sdk/include/ociextp.h
  inflating: instantclient_12_2/sdk/include/orl.h
  inflating: instantclient_12_2/sdk/include/nzt.h
  inflating: instantclient_12_2/sdk/include/ldap.h
  inflating: instantclient_12_2/sdk/include/occi.h
  inflating: instantclient_12_2/sdk/include/ociap.h
  inflating: instantclient_12_2/sdk/include/odci.h
  inflating: instantclient_12_2/sdk/include/ocixstream.h
  inflating: instantclient_12_2/sdk/include/nzerror.h
  inflating: instantclient_12_2/sdk/include/oci1.h
  inflating: instantclient_12_2/sdk/include/ori.h
  inflating: instantclient_12_2/sdk/include/ocixmldb.h
  inflating: instantclient_12_2/sdk/include/ocidem.h
  inflating: instantclient_12_2/sdk/include/occiAQ.h
  inflating: instantclient_12_2/sdk/include/ocidef.h
  inflating: instantclient_12_2/sdk/include/occiObjects.h
  inflating: instantclient_12_2/sdk/include/oci.h
  inflating: instantclient_12_2/sdk/include/oratypes.h
  inflating: instantclient_12_2/sdk/include/orid.h
  inflating: instantclient_12_2/sdk/include/xa.h
  inflating: instantclient_12_2/sdk/include/ocikpr.h
  inflating: instantclient_12_2/sdk/include/ocidfn.h
  inflating: instantclient_12_2/sdk/include/ort.h
   creating: instantclient_12_2/sdk/admin/
  inflating: instantclient_12_2/sdk/admin/oraaccess.xsd
[root@dmks soft]# unzip instantclient-jdbc-linux.x64-12.2.0.1.0.zip
Archive:  instantclient-jdbc-linux.x64-12.2.0.1.0.zip
  inflating: instantclient_12_2/JDBC_README
  inflating: instantclient_12_2/libheteroxa12.so
  inflating: instantclient_12_2/orai18n.jar
  inflating: instantclient_12_2/orai18n-mapping.jar
[root@dmks soft]# unzip instantclient-odbc-linux.x64-12.2.0.1.0-2.zip
Archive:  instantclient-odbc-linux.x64-12.2.0.1.0-2.zip
   creating: instantclient_12_2/help/
   creating: instantclient_12_2/help/ja/
  inflating: instantclient_12_2/help/ja/blafdoc.css
  inflating: instantclient_12_2/help/ja/oracle.gif
   creating: instantclient_12_2/help/ja/img_text/
  inflating: instantclient_12_2/help/ja/img_text/setup_ssmig.htm
  inflating: instantclient_12_2/help/ja/img_text/setup_work.htm
  inflating: instantclient_12_2/help/ja/img_text/odbcmodel.htm
  inflating: instantclient_12_2/help/ja/img_text/setup_app.htm
  inflating: instantclient_12_2/help/ja/img_text/setup_ora.htm
  inflating: instantclient_12_2/help/ja/img_text/odbcdrvarch.htm
  inflating: instantclient_12_2/help/ja/toc.htm
  inflating: instantclient_12_2/help/ja/map.xml
   creating: instantclient_12_2/help/ja/META-INF/
  inflating: instantclient_12_2/help/ja/META-INF/MANIFEST.MF
   creating: instantclient_12_2/help/ja/img/
  inflating: instantclient_12_2/help/ja/img/setup_app.gif
  inflating: instantclient_12_2/help/ja/img/odbcmodel.gif
  inflating: instantclient_12_2/help/ja/img/setup_ora.gif
  inflating: instantclient_12_2/help/ja/img/odbcdrvarch.gif
  inflating: instantclient_12_2/help/ja/img/setup_ssmig.gif
  inflating: instantclient_12_2/help/ja/img/setup_work.gif
  inflating: instantclient_12_2/help/ja/cpyr.htm
  inflating: instantclient_12_2/help/ja/sqora.htm
   creating: instantclient_12_2/help/us/
  inflating: instantclient_12_2/help/us/blafdoc.css
  inflating: instantclient_12_2/help/us/oracle.gif
   creating: instantclient_12_2/help/us/img_text/
  inflating: instantclient_12_2/help/us/img_text/setup_ssmig.htm
  inflating: instantclient_12_2/help/us/img_text/setup_work.htm
  inflating: instantclient_12_2/help/us/img_text/odbcmodel.htm
  inflating: instantclient_12_2/help/us/img_text/setup_app.htm
  inflating: instantclient_12_2/help/us/img_text/setup_ora.htm
  inflating: instantclient_12_2/help/us/img_text/odbcdrvarch.htm
  inflating: instantclient_12_2/help/us/toc.htm
  inflating: instantclient_12_2/help/us/map.xml
   creating: instantclient_12_2/help/us/META-INF/
  inflating: instantclient_12_2/help/us/META-INF/MANIFEST.MF
   creating: instantclient_12_2/help/us/img/
  inflating: instantclient_12_2/help/us/img/setup_app.gif
  inflating: instantclient_12_2/help/us/img/odbcmodel.gif
  inflating: instantclient_12_2/help/us/img/setup_ora.gif
  inflating: instantclient_12_2/help/us/img/odbcdrvarch.gif
  inflating: instantclient_12_2/help/us/img/setup_ssmig.gif
  inflating: instantclient_12_2/help/us/img/setup_work.gif
  inflating: instantclient_12_2/help/us/cpyr.htm
  inflating: instantclient_12_2/help/us/sqora.htm
  inflating: instantclient_12_2/libsqora.so.12.1
  inflating: instantclient_12_2/ODBC_IC_Readme_Unix.html
  inflating: instantclient_12_2/odbc_update_ini.sh
[root@dmks soft]# unzip instantclient-basiclite-linux.x64-12.2.0.1.0.zip
Archive:  instantclient-basiclite-linux.x64-12.2.0.1.0.zip
replace instantclient_12_2/adrci? [y]es, [n]o, [A]ll, [N]one, [r]ename: A
  inflating: instantclient_12_2/adrci
  inflating: instantclient_12_2/BASIC_LITE_README
  inflating: instantclient_12_2/genezi
  inflating: instantclient_12_2/libclntshcore.so.12.1
  inflating: instantclient_12_2/libclntsh.so.12.1
  inflating: instantclient_12_2/libipc1.so
  inflating: instantclient_12_2/libmql1.so
  inflating: instantclient_12_2/libnnz12.so
  inflating: instantclient_12_2/libocci.so.12.1
  inflating: instantclient_12_2/libociicus.so
  inflating: instantclient_12_2/libocijdbc12.so
  inflating: instantclient_12_2/libons.so
  inflating: instantclient_12_2/liboramysql12.so
  inflating: instantclient_12_2/ojdbc8.jar
  inflating: instantclient_12_2/uidrvci
  inflating: instantclient_12_2/xstreams.jar
[root@dmks soft]# unzip instantclient-tools-linux.x64-12.2.0.1.0.zip
Archive:  instantclient-tools-linux.x64-12.2.0.1.0.zip
  inflating: instantclient_12_2/exp
  inflating: instantclient_12_2/expdp
  inflating: instantclient_12_2/imp
  inflating: instantclient_12_2/impdp
  inflating: instantclient_12_2/libnfsodm12.so
  inflating: instantclient_12_2/sqlldr
  inflating: instantclient_12_2/TOOLS_README
  inflating: instantclient_12_2/wrc

3、配置环境变量

export ORACLE_HOME=/soft/instantclient_12_2
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ORACLE_HOME
export PATH=$ORACLE_HOME:$PATH

4、配置tns

[root@dmks instantclient_12_2]# mkdir -p network/admin
[root@dmks instantclient_12_2]# cd  network/admin/

[root@dmks admin]# vi tnsnames.ora
shardcat =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = 10.10.10.180)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = shardcat)
    )
  )

5、测试sqlplus,成功

[root@dmks admin]# sqlplus jy/xxzx7817600@shardcat

SQL*Plus: Release 12.2.0.1.0 Production on Sat Mar 21 23:07:41 2020

Copyright (c) 1982, 2016, Oracle.  All rights reserved.

Last Successful login time: Sun Mar 22 2020 01:36:51 +08:00

Connected to:
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production

SQL>

拷贝动态库文件

[root@dmks instantclient_12_2]# cp  *so*  /dm_home/dmdbms/bin/

[root@dmks instantclient_12_2]# cd  /dm_home/dmdbms/bin/
[root@dmks bin]# chown -R dmdba:dinstall *so*  //一定要将动态库文件修改为dmdba用户所有
[root@dmks bin]# chmod -R 777 /dm_home/dmdbms/bin/

创建DBlink
网络服务名配置成功后,就可以使用网络服务名shardcat或网络连接描述符创建DBLINK.

SQL> create or replace public link link3 connect 'oracle' with system identified by "xxzx7817600" using 'shardcat';
executed successfully
used time: 27.431(ms). Execute id is 8.
SQL> select * from v$version@link3;

LINEID     BANNER                                                                       CON_ID
---------- ---------------------------------------------------------------------------- ------
1          Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production 0
2          PL/SQL Release 12.2.0.1.0 - Production                                       0
3          CORE 12.2.0.1.0 Production                                                   0
4          TNS for Linux: Version 12.2.0.1.0 - Production                               0
5          NLSRTL Version 12.2.0.1.0 - Production                                       0

used time: 66.846(ms). Execute id is 9.

(二) 通过连接描述符创建

SQL> create or replace public link link4 connect 'oracle' with system identified by "xxzx7817600" using '(description =
2   (address_list = (address = (protocol = tcp)(host = 10.10.10.180)(port = 1521)))
3   (connect_data = (service_name = shardcat)))';
executed successfully
used time: 19.074(ms). Execute id is 10.
SQL> select * from v$version@link4;

LINEID     BANNER                                                                       CON_ID
---------- ---------------------------------------------------------------------------- ------
1          Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production 0
2          PL/SQL Release 12.2.0.1.0 - Production                                       0
3          CORE 12.2.0.1.0 Production                                                   0
4          TNS for Linux: Version 12.2.0.1.0 - Production                               0
5          NLSRTL Version 12.2.0.1.0 - Production                                       0

used time: 140.930(ms). Execute id is 12.

(三) 通过/< 服务名>创建

SQL> create or replace public link link5 connect 'oracle' with system identified by "xxzx7817600" using '10.10.10.180/shardcat';
executed successfully
used time: 17.347(ms). Execute id is 13.
SQL> select * from v$version@link5;

LINEID     BANNER                                                                       CON_ID
---------- ---------------------------------------------------------------------------- ------
1          Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production 0
2          PL/SQL Release 12.2.0.1.0 - Production                                       0
3          CORE 12.2.0.1.0 Production                                                   0
4          TNS for Linux: Version 12.2.0.1.0 - Production                               0
5          NLSRTL Version 12.2.0.1.0 - Production                                       0


used time: 92.869(ms). Execute id is 14.
SQL> select * from jy.t1@link3;

LINEID     T_ID T_NAME
---------- ---- -------
1          9    m_YYL
2          1    m_A
3          2    m_B
4          3    m_C
5          4    m_D
6          5    m_E
7          6    m_F
8          7    m_JYHY
9          8    m_JYYYL

9 rows got

used time: 10.891(ms). Execute id is 15.
SQL> insert into jy.t1@link3 values(9,'m_wy');
affect rows 1

used time: 33.658(ms). Execute id is 16.
SQL> commit;
executed successfully
used time: 20.563(ms). Execute id is 17.

SQL> select * from jy.t1;

      T_ID T_NAME
---------- ----------------------------------------
         9 m_wy
         9 m_YYL
         1 m_A
         2 m_B
         3 m_C
         4 m_D
         5 m_E
         6 m_F
         7 m_JYHY
         8 m_JYYYL

10 rows selected.

删除外部链接
删除一个外部链接。
语法格式
DROP [PUBLIC] LINK [< 模式名>.]< 外部链接名>;
参数
1.< 模式名> 指明被操作的外部链接属于哪个模式,缺省为当前模式;
2.< 外部链接名> 指明被操作的外部链接的名称。

语句功能
删除一个外部链接。
使用说明
只有链接对象的创建者和DBA拥有该对象的删除权限。

举例说明
删除外部链接LINK1。
DROP LINK LINK1;

使用外部链接通过外部链接,可以对远程服务器的对象进行查询或进行增删改操作,可以调用远程的过程。使用外部链接进行查询或增删改的语法格式与普通格式基本一致,唯一的区别在于指定外部链接表时需要使用如下格式作为表或视图的引用:
[TABLENAME | VIEWNAME] [LINK | @] 链接名

举例说明 使用外部链接查询LINK1上的远程表进行查询
SELECT * FROM SYSOBJECTS LINK LINK1; 或对远程表进行插入数据:
INSERT INTO T1@LINK1 VALUES(1,2,3);
也可以查询本地表或其他链接的表对远程表进行操作,如
UPDATE T1@LINK1 SET C1 = C1+1 WHERE C2 NOT IN (SELECT ID FROM LOCAL_TABLE);
DELETE FROM T1@LINK1 WHERE C1 IN (SELECT ID FROM T2@LINK2);

使用外部链接,可以调用远程的存储过程,但是不支持调用远程的函数,使用中有以下约束:
(1)参数数据类型为SQL类型,不允许为DMSQL程序类型;
(2)参数数据类型不允许为复合类型。
其使用方式为:
[CALL] [< 模式名>.][< 包名>.]< 过程名> [@] < 外部链接名>(< 参数列>);

使用限制
外部链接的使用有以下限制:
1. DM-DM的同构外部链接不支持MPP环境,DM与异构数据库的外部链接支持MPP环境;
2. 增删改不支持INTO语句;
3. 不支持使用游标进行增删改操作;
4. DBLINK理论上不支持LOB类型列的操作,但支持简单的增删改语句中使用常量来对LOB类型列进行操作。
另外,DM连接异构数据库的外部链接还有如下使用限制:
1. 数据类型以DM为基础,不支持DM没有的数据类型;
2. 语法以DM的语法为标准,不支持DM不兼容的语法;
3. 主键更新,如果是涉及到多个服务器的语句,不能保证更新操作一定成功。

达梦7同构(DM-DM)DBLINK

外部链接对象(LINK)是DM中的一种特殊的数据库实体对象,它记录了远程数据库的连接和路径信息,用于建立与远程数据的联系。通过多台数据库主库间的相互通讯,用户可以透明地操作远程数据库的数据,使应用程序看起来只有一个大型数据库。用户远程数据库中的数据请求,都被自动转换为网络请求,并在相应结点上实现相应的操作。用户可以建立一个数据库链接,以说明一个对象在远程数据库中的访问路径。这个链接可以是公用的(数据库中所有用户使用),也可以是私有的(只能被某个用户使用)。

用户可以通过外部链接对远程数据库的表进行查询和增删改操作,以及本地调用远程的存储过程。

语法格式
CREATE [OR REPLACE] [PUBLIC] LINK < 外部链接名> CONNECT [‘< 连接库类型>‘] WITH < 登录名> IDENTIFIED BY < 登录口令> USING ‘< 连接串> ‘;
< 连接库类型> ::= DAMENG | ORACLE | ODBC
< 连接串> ::=< 外部链接串>
< 外部链接串>::=< DAMENG外部链接串>| < ORACLE外部链接串> |
< DAMENG外部链接串>::=< 实例IP地址>/< 实例端口号> |
/ |

< ORACLE外部链接串>::= ||/< 服务名>
::=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=)(PORT=< 端口号>)))(CONNECT_DATA=(SERVICE_NAME=< 服务名>)))
::=

参数
1. OR REPLACE 使用OR REPLACE选项的好处是,如果系统中已经有同名的数据库链接名,服务器会自动用新的代码覆盖原来的代码。如果不使用OR REPLACE选项,当创建的新外部链接名称与系统中已有的外部链接名称同名时,服务器会报错。
2. PUBLIC 此链接对象是否能够被创建者之外的用户引用;
3. < 外部链接名> 数据库链接的名称;
4. < 连接库类型> 目前只支持DAMENG、ORACLE或ODBC,默认为DAMENG;
5. < 登录名> 登录用户名称;
6. < 登录口令> 登录用户口令;
7. 支持三种格式,分别对应目标节点在dmmal.ini中的配置项,具体如下:
l mal_inst_host/mal_inst_port
l mal_host/mal_port
l mal_inst_name
8. 可以使用配置的网络服务名tsn_name(网络服务名需要配置),或者连接描述符description(连接描述符是网络连接目标特殊格式的描述,它包括网络协议、主库IP地址、端口号和服务名),或者/< 服务名>;
9. DSN需要用户手动配置。

语句功能
创建一个外部链接。
使用说明
1.要创建到DM数据库的外部链接,必须首先配置dmmal.ini,才能使用LINK。DM的连接串有两种格式:
INSTANCE_NAME:直接使用远程库的实例名(该实例名必须配置到dmmal.ini中);
/< 端口号>:其中端口号为DM外部链接服务器的dmmal.ini配置中的MAL_PORT端口号。
dmmal.ini的详细配置可参考《DM7系统管理员手册》的2.1节,需要注意同时将dm.ini中的MAL_INI参数置为1以开启MAL系统。
2. 要创建到ORACLE的外部链接,可以使用配置的网络服务名;如果没有配置tsn_name,可以使用连接描述符或者/< 服务名>作为连接串。
3.通过LINK对远程服务器所作的修改,由用户在本地服务器通过commit或rollback进行提交或回滚。
4.只支持普通用户,不支持SSL和Kerberos认证。
5.DM7不支持连接自身实例的LINK。
6.支持在CREATE SCHEMA中CREATE LINK,但是不支持CREATE PUBLIC LINK。
7.只有DBA和具有CREATE LINK权限的用户可以创建外部链接。

举例说明 例1 使用DM数据库,创建一个连接到IP地址为10.10.10.186,MAL_PORT端口号为5336的MAL站点的外部链接,登录到此站点使用的用户名为sysdba,密码为dameng123,实例名为:dmks。
先对远程DM数据库设置dmmai.in文件,并设置MAL_INI参数为1,然后重启dmks数据库

[dmdba@dmks dmks]$ vi dmmal.ini
MAL_CHECK_INTERVAL = 5
MAL_CONN_FAIL_INTERVAL = 5

[MAL_dmks]
MAL_INST_NAME = dmks
MAL_HOST = 10.10.10.187
MAL_PORT = 5337
MAL_INST_PORT = 5236
MAL_INST_HOST = 10.10.10.187

[MAL_jydm]
MAL_INST_NAME = jydm
MAL_HOST = 10.10.10.180
MAL_PORT = 5336
MAL_INST_PORT = 5236
MAL_INST_HOST = 10.10.10.180


SQL> select sf_get_para_value(1,'MAL_INI');

LINEID     SF_GET_PARA_VALUE(1,'MAL_INI')
---------- ------------------------------
1          0

used time: 7.852(ms). Execute id is 1609.
SQL> select * from v$dm_ini where para_name='MAL_INI';

LINEID     PARA_NAME PARA_VALUE MIN_VALUE MAX_VALUE MPP_CHK SESS_VALUE FILE_VALUE DESCRIPTION PARA_TYPE
---------- --------- ---------- --------- --------- ------- ---------- ---------- ----------- ---------
1          MAL_INI   0          0         1         N       0          0          dmmal.ini   IN FILE

used time: 8.395(ms). Execute id is 1610.

SQL> alter system set 'MAL_INI'=1 spfile;
DMSQL executed successfully
used time: 8.209(ms). Execute id is 1611.
SQL> select sf_get_para_value(1,'MAL_INI');

LINEID     SF_GET_PARA_VALUE(1,'MAL_INI')
---------- ------------------------------
1          1

used time: 5.533(ms). Execute id is 1612.
SQL>  select * from v$dm_ini where para_name='MAL_INI';

LINEID     PARA_NAME PARA_VALUE MIN_VALUE MAX_VALUE MPP_CHK SESS_VALUE FILE_VALUE DESCRIPTION PARA_TYPE
---------- --------- ---------- --------- --------- ------- ---------- ---------- ----------- ---------
1          MAL_INI   0          0         1         N       0          1          dmmal.ini   IN FILE

used time: 7.583(ms). Execute id is 1613.


[root@dmks ~]# netstat -nltp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name
tcp        0      0 0.0.0.0:5901                0.0.0.0:*                   LISTEN      24268/Xvnc
tcp        0      0 0.0.0.0:111                 0.0.0.0:*                   LISTEN      1738/rpcbind
tcp        0      0 0.0.0.0:39792               0.0.0.0:*                   LISTEN      1964/rpc.statd
tcp        0      0 0.0.0.0:6001                0.0.0.0:*                   LISTEN      24268/Xvnc
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      2191/sshd
tcp        0      0 127.0.0.1:631               0.0.0.0:*                   LISTEN      2027/cupsd
tcp        0      0 127.0.0.1:25                0.0.0.0:*                   LISTEN      2290/master
tcp        0      0 :::38955                    :::*                        LISTEN      1964/rpc.statd
tcp        0      0 :::111                      :::*                        LISTEN      1738/rpcbind
tcp        0      0 :::6001                     :::*                        LISTEN      24268/Xvnc
tcp        0      0 :::5236                     :::*                        LISTEN      21657/dmserver
tcp        0      0 :::22                       :::*                        LISTEN      2191/sshd
tcp        0      0 ::1:631                     :::*                        LISTEN      2027/cupsd
tcp        0      0 ::1:25                      :::*                        LISTEN      2290/master
[root@dmks ~]# service DmServicedmks restart
Stopping DmServicedmks: [ OK ]
Starting DmServicedmks: [ OK ]
[root@dmks ~]# netstat -nltp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name
tcp        0      0 0.0.0.0:5901                0.0.0.0:*                   LISTEN      24268/Xvnc
tcp        0      0 0.0.0.0:111                 0.0.0.0:*                   LISTEN      1738/rpcbind
tcp        0      0 0.0.0.0:39792               0.0.0.0:*                   LISTEN      1964/rpc.statd
tcp        0      0 0.0.0.0:6001                0.0.0.0:*                   LISTEN      24268/Xvnc
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      2191/sshd
tcp        0      0 127.0.0.1:631               0.0.0.0:*                   LISTEN      2027/cupsd
tcp        0      0 127.0.0.1:25                0.0.0.0:*                   LISTEN      2290/master
tcp        0      0 :::38955                    :::*                        LISTEN      1964/rpc.statd
tcp        0      0 :::111                      :::*                        LISTEN      1738/rpcbind
tcp        0      0 :::6001                     :::*                        LISTEN      24268/Xvnc
tcp        0      0 :::5236                     :::*                        LISTEN      840/dmserver
tcp        0      0 :::22                       :::*                        LISTEN      2191/sshd
tcp        0      0 ::1:631                     :::*                        LISTEN      2027/cupsd
tcp        0      0 :::5337                     :::*                        LISTEN      840/dmserver
tcp        0      0 ::1:25                      :::*                        LISTEN      2290/master

从上面的输出可以看到端口5336实战启用了

SQL> select * from v$dm_ini where para_name='MAL_INI';

LINEID     PARA_NAME PARA_VALUE MIN_VALUE MAX_VALUE MPP_CHK SESS_VALUE FILE_VALUE DESCRIPTION PARA_TYPE
---------- --------- ---------- --------- --------- ------- ---------- ---------- ----------- ---------
1          MAL_INI   1          0         1         N       1          1          dmmal.ini   IN FILE

used time: 12.648(ms). Execute id is 3.
SQL>  select sf_get_para_value(2,'MAL_INI');

LINEID     SF_GET_PARA_VALUE(2,'MAL_INI')
---------- ------------------------------
1          1

used time: 1.191(ms). Execute id is 4.

对本地DM数据库配置dmmal.ini,注意这里还要添加远程数据库的信息,否则在创建外部link时会提示实例不存在

[dmdba@shard1 jydm]$ cat  dmmal.ini
MAL_CHECK_INTERVAL = 5
MAL_CONN_FAIL_INTERVAL = 5

[MAL_dmks]
MAL_INST_NAME = dmks
MAL_HOST = 10.10.10.187
MAL_PORT = 5337
MAL_INST_PORT = 5236
MAL_INST_HOST = 10.10.10.187

[MAL_jydm]
MAL_INST_NAME = jydm
MAL_HOST = 10.10.10.180
MAL_PORT = 5336
MAL_INST_PORT = 5236
MAL_INST_HOST = 10.10.10.180

SQL> select * from v$dm_ini where para_name='MAL_INI';

LINEID     PARA_NAME PARA_VALUE MIN_VALUE MAX_VALUE MPP_CHK SESS_VALUE FILE_VALUE DESCRIPTION PARA_TYPE
---------- --------- ---------- --------- --------- ------- ---------- ---------- ----------- ---------
1          MAL_INI   1          0         1         N       1          1          dmmal.ini   IN FILE

used time: 8.629(ms). Execute id is 6.
SQL> select sf_get_para_value(2,'MAL_INI');

LINEID     SF_GET_PARA_VALUE(2,'MAL_INI')
---------- ------------------------------
1          1

used time: 1.302(ms). Execute id is 8.
SQL>

重启本地数据库

[root@shard1 tmp]# systemctl start DmServicejydm.service

SQL> create public link link1 connect 'dameng' with sysdba identified by "dameng123" using '10.10.10.180/5336';
executed successfully
used time: 19.417(ms). Execute id is 9.

或者

SQL> create or replace public link link2 connect 'dameng' with sysdba identified by "dameng123" using 'jydm';
executed successfully
used time: 35.346(ms). Execute id is 12.

在远程数据库中创建jy.t1表

SQL> insert into jy.t1 values(1,'JY');
affect rows 1

used time: 1.019(ms). Execute id is 2809.
SQL> commit;
executed successfully
used time: 13.274(ms). Execute id is 2810.

在本地数据库中通过外部link来查询远程数据库的sysdba.t1表

SQL> select * from jy.t1@link1;

LINEID     C1          C2
---------- ----------- --
1          1           JY

used time: 5.955(ms). Execute id is 134.
SQL> select * from jy.t1@link2;

LINEID     C1          C2
---------- ----------- --
1          1           JY

used time: 2.538(ms). Execute id is 135.

在本地数据库中通过外部link向远程数据库的jy.t1表插入数据

SQL> insert into jy.t1@link1 values(2,'HY');
affect rows 1

used time: 2.611(ms). Execute id is 136.
SQL> commit;
executed successfully
used time: 13.105(ms). Execute id is 137.

在远程数据库中使用sysdba来查询t1表的记录来验证记录是否被插入

SQL>  select * from jy.t1;

LINEID     C1          C2
---------- ----------- --
1          1           JY
2          2           HY

used time: 0.906(ms). Execute id is 2819.

MySQL Rewriter Query Rewrite Plugin

从MySQL 5.7.6开始,MySQL服务器支持查询重写插件它可以在服务器执行语句之前可以检查和可能修改接收到的语句。MySQL包含一个名为Rewriter的查询重写插件和安装插件与它相关组件的脚本。这些组件一起工作提供对select的重写能力:
.服务端插件名为Rewriter检查select语句并且可能基于缓存在内存中的重写规则来重写它们。标准select语句和预备语句中的select语句可能经受重写。出现在视图定义中或存储过程中的select语句不会经受重写。

.Rewriter插件使用一个包含rewrite_rules表的query_rewrite数据库。表提供了对规则的永久存储,插件使用它来决赛是否重写语句。通过存储在表中的规则集让用户与插件通信。通过设置表中记录的message列来让用户与插件通信。

.query_rewrite数据库包含一个名为flush_rewrite_rules()的存储过程用来把规则表中的内容加载到插件中。

.用户定义函数load_rewrite_rules()被flush_rewrite_rules()存储过程来调用。

.Rewriter插件显示了系统变量能让插件配置和状态变量来提供运行时操作信息。

下面将描述如何安装与使用Rewriter插件并提供与它相关组件的信息。

安装或卸载Rewriter查询重写插件
为了安装或卸载Rewriter查询重写插件,在MySQL安装目录下的share目录中选择执行合适的脚本:
.install_rewriter.sql: 使用这个脚本来安装Rewriter插件和它相关的组件。
.uninstall_rewriter.sql:使用这个脚本来卸载Rewriter插件和它相关的组件。

运行安装脚本

[mysql@localhost share]$ mysql -uroot -p < install_rewriter.sql
Enter password:

运行安装脚本将会安装与启用插件。为了验证它,连接到数据库执行以下语句:

mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| binlog |
| mysql |
| performance_schema |
| query_rewrite |
| sys |
+--------------------+
6 rows in set (0.00 sec)

mysql> show global variables like 'rewriter_enabled';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| rewriter_enabled | ON |
+------------------+-------+
1 row in set (0.00 sec)

使用Rewriter查询重写插件
为了启用或禁用Rewriter查询重写插件可以通过启用或禁用rewriter_enabled系统变量来完成。默认情况是当你安装Rewriter查询重写插件时是启用的。为了显式设置初始化Rewriter查询重写插件的状态,可以在服务器启动时设置rewriter_enabled变量。例如为了在选项文件中启用Rewriter插件可以进行以下设置:
[mysqld]
rewriter_enabled=ON

也可以在运行时启用或禁用Rewriter插件:

mysql> set global rewriter_enabled=OFF;
Query OK, 0 rows affected (0.00 sec)

mysql> show global variables like 'rewriter_enabled';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| rewriter_enabled | OFF |
+------------------+-------+
1 row in set (0.00 sec)

mysql> set global rewriter_enabled=ON;
Query OK, 0 rows affected (0.00 sec)

mysql> show global variables like 'rewriter_enabled';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| rewriter_enabled | ON |
+------------------+-------+
1 row in set (0.01 sec)

mysql> desc query_rewrite.rewrite_rules;
+--------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+------------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| pattern | varchar(10000) | NO | | NULL | |
| pattern_database | varchar(20) | YES | | NULL | |
| replacement | varchar(10000) | NO | | NULL | |
| enabled | enum('YES','NO') | NO | | YES | |
| message | varchar(1000) | YES | | NULL | |
| pattern_digest | varchar(32) | YES | | NULL | |
| normalized_pattern | varchar(100) | YES | | NULL | |
+--------------------+------------------+------+-----+---------+----------------+
8 rows in set (0.00 sec)

mysql> select * from query_rewrite.rewrite_rules;
Empty set (0.00 sec)

假设Rewriter插件被启用,它将检查和可能修改由服务器所接收到的每个select语句。插件将基于内存中缓存的重写规则(从query_rewriter数据库的rewrite_rules表中加载的)来决定是否重写语句。

添加重写规则
为了向Rewriter插件添加规则,向rewrite_rules表中添加记录,然后调用flush_rewrite_rules()存储过程来从表中加载规则到插件中。下面的例子来创建一个简单规则来匹配单个文本值的查询语句。

mysql> insert into query_rewrite.rewrite_rules(pattern,replacement) values('select ?','select ?+1');
Query OK, 1 row affected (0.03 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from query_rewrite.rewrite_rules;
+----+----------+------------------+-------------+---------+---------+----------------+--------------------+
| id | pattern | pattern_database | replacement | enabled | message | pattern_digest | normalized_pattern |
+----+----------+------------------+-------------+---------+---------+----------------+--------------------+
| 1 | select ? | NULL | select ?+1 | YES | NULL | NULL | NULL |
+----+----------+------------------+-------------+---------+---------+----------------+--------------------+
1 row in set (0.00 sec)

mysql> select * from query_rewrite.rewrite_rules\G;
*************************** 1. row ***************************
id: 1
pattern: select ?
pattern_database: NULL
replacement: select ?+1
enabled: YES
message: NULL
pattern_digest: NULL
normalized_pattern: NULL
1 row in set (0.00 sec)

规则指定一种模式模板指示那种查询语句会被匹配,并且替换模板指示了如何重写匹配的语句。然而添加规则到rewrite_rules表中不足以造成Rewriter插件使用这个规则。我们必须要调用flush_rewrite_rules()过程来将规则表的内容加载到插件内存缓存中:

mysql> call query_rewrite.flush_rewrite_rules();
Query OK, 0 rows affected, 1 warning (0.04 sec)

当插件从规则表中读取每种规则时,它将计算一个标准化(语句摘要)格式的模式和一个摘要哈希值并使用它们来更新normalized_pattern和pattern_digest列:

mysql> select * from query_rewrite.rewrite_rules\G;
*************************** 1. row ***************************
id: 1
pattern: select ?
pattern_database: NULL
replacement: select ?+1
enabled: YES
message: NULL
pattern_digest: 3d4fc22e33e10d7235eced3c75a84c2c
normalized_pattern: select ?
1 row in set (0.00 sec)

模式使用与预备语句相同的语法。使用模式模板,?字符实际上作为参数标记用来匹配数据值。参数标记只能用于应该出现数据值的地方,而不能用于SQL关键字、标识符等.?字符不应该使用引号括起来。

像模式一样,替换可以包含?字符。对于匹配一种模式模板的语句,重写插件将重写它,通过模式中的相关标记所匹配的数据值来替换?字符标记。替换的结果是一种完整的语句字符。重写插件要求服务器解析它并执行重写之后的语句将结果返回。

在添加和加载重写规则后,检查匹配规则模式的语句是否会被重写:

mysql> select pi();
+----------+
| pi() |
+----------+
| 3.141593 |
+----------+
1 row in set (0.02 sec)

mysql> select 10;
+------+
| 10+1 |
+------+
| 11 |
+------+
1 row in set, 1 warning (0.00 sec)

从上面的执行结果来看,第一个查询语句没有出现重写,但第二个查询被重写了。因为第二个查询语句Rewriter插件重写语句后生成了一个警告信息。为了查看这个警告信息可以使用show warnings:

mysql> show warnings\g
+-------+------+------------------------------------------------------------------------+
| Level | Code | Message |
+-------+------+------------------------------------------------------------------------+
| Note | 1105 | Query 'select 10' rewritten to 'select 10+1' by a query rewrite plugin |
+-------+------+------------------------------------------------------------------------+
1 row in set (0.00 sec)

为了启用或禁用现有的规则,可以通过修改enabled列并重新加载规则表到重写插件。

为了禁用规则1

mysql> update query_rewrite.rewrite_rules set enabled='NO' where id=1;
Query OK, 1 row affected (0.03 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> call query_rewrite.flush_rewrite_rules();
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> select * from query_rewrite.rewrite_rules\G;
*************************** 1. row ***************************
id: 1
pattern: select ?
pattern_database: NULL
replacement: select ?+1
enabled: NO
message: NULL
pattern_digest: 3d4fc22e33e10d7235eced3c75a84c2c
normalized_pattern: select ?
1 row in set (0.00 sec)

mysql> select 10;
+----+
| 10 |
+----+
| 10 |
+----+
1 row in set (0.00 sec)

这就可以不同从表中删除重写规则来禁用重写规则。

为了重新启用重写规则1:

mysql> update query_rewrite.rewrite_rules set enabled='YES' where id=1;
Query OK, 1 row affected (0.03 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> call query_rewrite.flush_rewrite_rules();
Query OK, 0 rows affected (0.02 sec)

mysql> select * from query_rewrite.rewrite_rules\G;
*************************** 1. row ***************************
id: 1
pattern: select ?
pattern_database: NULL
replacement: select ?+1
enabled: YES
message: NULL
pattern_digest: 3d4fc22e33e10d7235eced3c75a84c2c
normalized_pattern: select ?
1 row in set (0.00 sec)

mysql> select 10;
+------+
| 10+1 |
+------+
| 11 |
+------+
1 row in set, 1 warning (0.00 sec)

rewrite_rules表包含了一个pattern_database列它是Rewriter用来匹配没有使用数据库名限定的表名:
.如果相关的数据库和表名相同,语句中限定表名匹配模式中的限定名。
.只有默认数据库与pattern_database一样并且表名相同时语句中的非限定表名匹配模式中的非限定名

假设表mysql.cs有一个名为id的列并且应用程序从以下形式的查询中选择一个来从表中查询记录,这里第二个查询只能在默认数据库为mysql的情况下被执行:
select * from mysql.cs where id=id_value;
select * from cs where id=id_value;

现在假设id列被重命名为user_id了。这种修改意味着应用程序必须引用user_id而不是id。但是如果旧的应用程序不能进行修改,那么它们将不能工作了。Rewriter重写插件可以解决这个问题。为了匹配和重写那些不管是否有限定名的查询语句,添加以下两个规则并重新加载规则表:

mysql> select * from cs where mysql.id=1;
ERROR 1054 (42S22): Unknown column 'mysql.id' in 'where clause'
mysql> insert into query_rewrite.rewrite_rules(pattern,replacement)
-> values('select * from mysql.cs where id= ?','select * from mysql.cs where user_id= ?');
Query OK, 1 row affected (0.05 sec)

mysql> insert into query_rewrite.rewrite_rules(pattern,replacement,pattern_database)
-> values('select * from cs where id=?','select * from cs where user_id=?','mysql');
Query OK, 1 row affected (0.05 sec)

mysql> call query_rewrite.flush_rewrite_rules();
Query OK, 0 rows affected, 1 warning (0.02 sec)

mysql> select * from query_rewrite.rewrite_rules\G;
*************************** 1. row ***************************
id: 1
pattern: select ?
pattern_database: NULL
replacement: select ?+1
enabled: YES
message: NULL
pattern_digest: 3d4fc22e33e10d7235eced3c75a84c2c
normalized_pattern: select ?
*************************** 2. row ***************************
id: 2
pattern: select * from mysql.cs where id= ?
pattern_database: NULL
replacement: select * from mysql.cs where user_id= ?
enabled: YES
message: NULL
pattern_digest: 45281da14b71c1357dd053a4fe49dfac
normalized_pattern: select `*` from `mysql`.`cs` where (`id` = ?)
*************************** 3. row ***************************
id: 3
pattern: select * from cs where id=?
pattern_database: mysql
replacement: select * from cs where user_id=?
enabled: YES
message: NULL
pattern_digest: 0da2491bc4c0e1462cc020e4fcfde16b
normalized_pattern: select `*` from `mysql`.`cs` where (`id` = ?)
3 rows in set (0.00 sec)

mysql> select * from mysql.cs where id=1;
+------+------+---------+
| id | name | user_id |
+------+------+---------+
| 1 | jy | 1 |
+------+------+---------+
1 row in set, 1 warning (0.00 sec)

mysql> show warnings;
+-------+------+----------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message |
+-------+------+----------------------------------------------------------------------------------------------------------------------------+
| Note | 1105 | Query 'select * from mysql.cs where id=1' rewritten to 'select * from mysql.cs where user_id= 1' by a query rewrite plugin |
+-------+------+----------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> select * from cs where id=1;
+------+------+---------+
| id | name | user_id |
+------+------+---------+
| 1 | jy | 1 |
+------+------+---------+
1 row in set, 1 warning (0.00 sec)

mysql> show warnings;
+-------+------+---------------------------------------------------------------------------------------------------------------+
| Level | Code | Message |
+-------+------+---------------------------------------------------------------------------------------------------------------+
| Note | 1105 | Query 'select * from cs where id=1' rewritten to 'select * from cs where user_id=1' by a query rewrite plugin |
+-------+------+---------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

Rewriter插件使用第一个规则匹配有限定名的查询,使用第二个规则匹配没有限定名,但默认数据库必须为mysql才能进行查询重写。

如何进行模式匹配
Rewriter插件使用语句摘要和摘要哈希值来使用重写规则匹配输入语句。max_digest_length系统变量决定了用于计算语句摘要的buffer大小。值越大计算的摘要越能区分更长的语句。值越小使用的内存越小但增加了更长语句使用相同摘要的可能性。


mysql> show global variables like 'max_digest_length';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| max_digest_length | 1024 |
+-------------------+-------+
1 row in set (0.00 sec)

插件匹配语句进行重写的规则如下:
1.计算语句摘要的哈希值并将它与规则摘要哈希值进行比较。这可能会出现误报,但可以作为快速的拒绝测试

2.如果语句摘要哈希值匹配任何一个模式摘要哈希值,则匹配规范化哈希值(语句摘要)将语句的形式转化为匹配规则模式所规范化的形式。

3.如果规范化语句与规则匹配,请比较语句和模式中的文字值。模式中的一个?号值与语句中的任何文字值匹配。如果语句准备了一个SELECT语句,模式中的?也匹配语句中的?。否则,对应的文字必须相同。

如果多个规则匹配一个语句,则不确定插件使用哪个规则来重写该语句。

如果一个模式包含比替换更多的标记,那么插件将丢弃多余的数据值。如果一个模式包含的标记比替换的少,这就是一个错误。当加载规则表时,插件会注意到这一点,它会向规则行的message列写入一条错误消息来传递问题,并将Rewriter_reload_error状态变量设置为ON。

重写预备语句
预备语句是在解析时被重写,而不是在执行时被重写。预备语句与非预备语句的区别在于它们可能包含?字符作为参数标记。为了匹配预备语句中的?字符,重写模式必须在同一个地方包含?字符。假设重写规则具有这种模式
select ?, 3
下面列出了几种预备语句和是否与它匹配的模式
预备语句                                模式是否匹配语句
prepare s as ‘select 3, 3’     Yes
prepare s as ‘select ?, 3’     Yes
prepare s as ‘select 3, ?’     No
prepare s as ‘select ?, ?’     No

Rewriter插件操作信息
Rewriter插件通过几种状态变量来表示它的操作信息:

mysql> show global status like 'Rewriter%';
+-----------------------------------+-------+
| Variable_name | Value |
+-----------------------------------+-------+
| Rewriter_number_loaded_rules | 3 |
| Rewriter_number_reloads | 5 |
| Rewriter_number_rewritten_queries | 5 |
| Rewriter_reload_error | OFF |
+-----------------------------------+-------+
4 rows in set (0.01 sec)

Linux Use ODBC Connect Oracle

因为工作需要,需要使用ODBC访问Oracle,下面是ODBC访问Oracle的具体配置
1.下载unixODBC和Oracle简易客户端软件包
1.1下载地址:

http://www.unixodbc.org/

1.1.1下载文件:

unixODBC-2.3.0.tar.gz

2 Oracle ODBC Driver
2.1下载地址:

http://www.oracle.com/technetwork/topics/linuxx86-64soft-092277.html

2.1.1下载文件:

instantclient-sqlplus-linux.x64-12.2.0.1.0.zip
instantclient-basic-linux.x64-12.2.0.1.0.zip
instantclient-sdk-linux.x64-12.2.0.1.0.zip
instantclient-jdbc-linux.x64-12.2.0.1.0.zip
instantclient-odbc-linux.x64-12.2.0.1.0-2.zip
instantclient-basiclite-linux.x64-12.2.0.1.0.zip
instantclient-tools-linux.x64-12.2.0.1.0.zip

将这些软件包上传到/soft目录

3.安装unixODBC(root用户)

#cd /soft
#tar xvf unixODBC-2.3.0.tar.gz
#cd /soft/unixODBC-2.3.0
#./configure
#make
#make install

(默认是被安装到/usr/local)

4.安装Oracle ODBC(root用户)

#cd /soft/
#unzip instantclient-sqlplus-linux.x64-12.2.0.1.0.zip
#unzip instantclient-basic-linux.x64-12.2.0.1.0.zip
#unzip instantclient-sdk-linux.x64-12.2.0.1.0.zip
#unzip instantclient-jdbc-linux.x64-12.2.0.1.0.zip
#unzip instantclient-odbc-linux.x64-12.2.0.1.0-2.zip
#unzip instantclient-basiclite-linux.x64-12.2.0.1.0.zip
#unzip instantclient-tools-linux.x64-12.2.0.1.0.zip
[root@dmks instantclient_12_2]# ./odbc_update_ini.sh /usr/local
 *** ODBCINI environment variable not set,defaulting it to HOME directory!

更新操作完成后,会在/usr/local/etc/odbcinst.ini增加Oracle12C的驱动描述信息。

[root@dmks etc]# cat odbcinst.ini
[DM7 ODBC DRIVER]
Description = ODBC DRIVER FOR DM7
Driver = /dm_home/dmdbms/bin/libdodbc.so


[Oracle 12c ODBC driver]
Description     = Oracle ODBC driver for Oracle 12c
Driver          = /soft/instantclient_12_2/libsqora.so.12.1
Setup           =
FileUsage       =
CPTimeout       =
CPReuse         =

并且会在HOME目录下也就是/root,生成.odbc.ini文件,修改.odbc.ini文件

[root@dmks ~]# cat .odbc.ini
[OracleODBC-12c]
Application Attributes = T
Attributes = W
BatchAutocommitMode = IfAllSuccessful
BindAsFLOAT = F
CloseCursor = F
DisableDPM = F
DisableMTS = T
Driver = Oracle 12c ODBC driver
DSN = OracleODBC-12c
EXECSchemaOpt =
EXECSyntax = T
Failover = T
FailoverDelay = 10
FailoverRetryCount = 10
FetchBufferSize = 64000
ForceWCHAR = F
Lobs = T
Longs = T
MaxLargeData = 0
MetadataIdDefault = F
QueryTimeout = T
ResultSets = T
ServerName = shardcat 与tnsnames.ora文件中的服务器一致
SQLGetData extensions = F
Translation DLL =
Translation Option = 0
DisableRULEHint = T
UserID =
StatementCache=F
CacheBufferSize=20
UseOCIDescribeAny=F
SQLTranslateErrors=F
MaxTokenSize=8192
AggregateSQLType=FLOAT
5.测试ODBC连接Oracle
[root@dmks ~]# isql  OracleODBC-12c system xxzx7817600 -v
+---------------------------------------+
| Connected!                            |
|                                       |
| sql-statement                         |
| help [tablename]                      |
| quit                                  |
|                                       |
+---------------------------------------+
SQL> select * from v$version;
+---------------------------------------------------------------------------------+-----------------------------------------+
| BANNER                                                                          | CON_ID                                  |
+---------------------------------------------------------------------------------+-----------------------------------------+
| Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production    | 0                                       |
| PL/SQL Release 12.2.0.1.0 - Production                                          | 0                                       |
| CORE  12.2.0.1.0      Production                                                      | 0                                       
| TNS for Linux: Version 12.2.0.1.0 - Production                                  | 0                                       |
| NLSRTL Version 12.2.0.1.0 - Production                                          | 0                                       |
+---------------------------------------------------------------------------------+-----------------------------------------+

到此使用odbc连接Oracle的操作完成,还是很简单的。

18C RAC DBCA建库时找不到ASM磁盘

在Oracle Linux 7.1中使用dbca为Oracle 18C RAC创建数据库时,找不到ASM磁盘组;而grid用户使用asmca却又能看到ASM磁盘组。

解决方法
1. 检查创建ASM磁盘设备的权限,正确的权限为grid:asmadmin,通过下面输出可知权限正确

[root@18c1 ~]# ls -lrt /dev/asm*
brw-rw---- 1 grid asmadmin 8, 16 Mar 16 22:28 /dev/asmdisk01
brw-rw---- 1 grid asmadmin 8, 32 Mar 17 08:40 /dev/asmdisk02

[root@18c2 ~]# ls -lrt /dev/asm*
brw-rw---- 1 grid asmadmin 8, 32 Mar 17 08:41 /dev/asmdisk02
brw-rw---- 1 grid asmadmin 8, 16 Mar 17 08:41 /dev/asmdisk01

2.检查ASM实例是否启动

[grid@18c1 ~]$ asmcmd lsdg
State    Type    Rebal  Sector  Logical_Sector  Block       AU  Total_MB  Free_MB  Req_mir_free_MB  Usable_file_MB  Offline_disks  Voting_files  Name
MOUNTED  EXTERN  N         512             512   4096  4194304     61440    35868                0           35868              0             Y  CRS/
MOUNTED  EXTERN  N         512             512   4096  4194304     40960    36036                0           36036              0             N  DATA/

[grid@18c2 ~]$ asmcmd lsdg
State    Type    Rebal  Sector  Logical_Sector  Block       AU  Total_MB  Free_MB  Req_mir_free_MB  Usable_file_MB  Offline_disks  Voting_files  Name
MOUNTED  EXTERN  N         512             512   4096  4194304     61440    35868                0           35868              0             Y  CRS/
MOUNTED  EXTERN  N         512             512   4096  4194304     40960    36036                0           36036              0             N  DATA/

3. 检查GRID_HOME/bin下oracle是否有s权限,如果没有需要添加s权限,通过下面的输出可知GRID_HOME/bin目录下的oracle是没有s权限的,这里需要添加

[root@18c1 ~]# ls -lrt /u01/app/oracle/18.0.0/db/bin/oracle
-rwsr-s--x 1 oracle asmadmin 437038067 Mar 16 23:00 /u01/app/oracle/18.0.0/db/bin/oracle
[root@18c1 ~]# ls -lrt /u01/app/18.0.0/grid/bin/oracle
-rwxr-x--x. 1 grid oinstall 413877125 Mar 16 19:10 /u01/app/18.0.0/grid/bin/oracle
[root@18c2 /]# ls -lrt /u01/app/oracle/18.0.0/db/bin/oracle
-rwsr-s--x 1 oracle oinstall 437038067 Mar 16 23:07 /u01/app/oracle/18.0.0/db/bin/oracle
[root@18c2 /]# ls -lrt /u01/app/18.0.0/grid/bin/oracle
-rwxr-x--x. 1 grid oinstall 413877125 Mar 16 19:30 /u01/app/18.0.0/grid/bin/oracle

[root@18c1 ~]# chmod +s /u01/app/18.0.0/grid/bin/oracle
[root@18c1 ~]# ls -lrt /u01/app/18.0.0/grid/bin/oracle
-rwsr-s--x. 1 grid oinstall 413877125 Mar 16 19:10 /u01/app/18.0.0/grid/bin/oracle

[root@18c2 /]# chmod +s /u01/app/18.0.0/grid/bin/oracle
[root@18c2 /]# ls -lrt /u01/app/18.0.0/grid/bin/oracle
-rwsr-s--x. 1 grid oinstall 413877125 Mar 16 19:30 /u01/app/18.0.0/grid/bin/oracle

4.检查用户所有组

[root@18c1 ~]# id oracle
uid=1001(oracle) gid=1011(oinstall) groups=1007(asmdba),1009(dba),1010(oper),1012(backupdba),1013(dgdba),1014(kmdba),1015(racdba),1011(oinstall)
[root@18c1 ~]# id grid
uid=1002(grid) gid=1011(oinstall) groups=1006(asmadmin),1007(asmdba),1008(asmoper),1009(dba),1011(oinstall)
[root@18c1 ~]# gpasswd -a oracle asmadmin
Adding user oracle to group asmadmin
[root@18c1 ~]# id oracle
uid=1001(oracle) gid=1011(oinstall) groups=1006(asmadmin),1007(asmdba),1009(dba),1010(oper),1012(backupdba),1013(dgdba),1014(kmdba),1015(racdba),1011(oinstall)

[root@18c2 /]# id oracle
uid=1001(oracle) gid=1011(oinstall) groups=1007(asmdba),1009(dba),1010(oper),1012(backupdba),1013(dgdba),1014(kmdba),1015(racdba),1011(oinstall)
[root@18c2 /]# id grid
uid=1002(grid) gid=1011(oinstall) groups=1006(asmadmin),1007(asmdba),1008(asmoper),1009(dba),1011(oinstall)
[root@18c2 /]# gpasswd -a oracle asmadmin
Adding user oracle to group asmadmin
[root@18c2 /]# id oracle
uid=1001(oracle) gid=1011(oinstall) groups=1006(asmadmin),1007(asmdba),1009(dba),1010(oper),1012(backupdba),1013(dgdba),1014(kmdba),1015(racdba),1011(oinstall)

再执行dbca创建数据库时能正确找到磁盘组

DM自定义数据类型

自定义类型
用户使用CREATE TYPE语句可以定义记录类型、对象类型、命名的数组类型、集合类型等,如果在对象类型中声明了过程或方法,可以使用CREATE TYPE BODY定义这些过程和方法。

创建类型可以使用CREATE TYPE语句创建记录类型、对象类型、数组和集合类型。
语法格式
CREATE [OR REPLACE] TYPE [< 模式名>.]< 类型名>[WITH ENCRYPTION] [< 调用权限子句>] AS|IS < 记录类型定义子句>|< 对象类型定义子句>
|< 数组类型定义子句>|< 集合类型定义子句>
[< 调用权限子句>]::= AUTHID DEFINER
| AUTHID CURRENT_USER
< 对象类型定义子句> ::= OBJECT [UNDER [< 模式名>.]< 父类型名>] (< 对象定义>,{< 对象定义>})[[NOT] FINAL] [[NOT] INSTANTIABLE]
< 对象定义> ::= < 变量列表定义>|< 过程声明>|< 函数声明>|< 构造函数声明>
< 过程声明> ::= [< 方法继承属性>][STATIC|MEMBER] PROCEDURE < 过程名> < 参数列表>
< 函数声明> ::= [< 方法继承属性>][MAP] [STATIC|MEMBER] FUNCTION < 函数名> < 参数列表> RETURN < 返回值数据类型>[DETERMINISTIC]
[PIPELINED]
< 方法继承属性> ::= < 重载属性> | | < 重载属性>
< 重载属性> ::= [NOT] OVERRDING
::= FINAL | NOT FINAL | INSTANTIABLE | NOT INSTANTIABLE
< 构造函数声明> ::= CONSTRUCTOR FUNCTION < 函数名> < 参数列表> RETURN SELF AS RESULT
< 记录类型定义子句> ::= RECORD(变量列表定义)
< 数组类型定义子句> ::= ARRAY < 数据类型>‘ [‘ [< 常量表达式>]{,[< 常量表达式>]}’]’
< 集合类型定义子句> ::= < 数组集合定义子句>|< 嵌套表定义子句>|< 索引表定义子句>
< 数组集合定义子句> ::= VARRAY(< 常量表达式>) OF < 数据类型>
< 嵌套表定义子句> ::= TABLE OF < 数据类型>
< 索引表定义子句> ::= TABLE OF < 数据类型> [INDEX BY < 数据类型>]

使用说明
1. 对象类型中过程和函数的声明都是前向声明,类型定义中不包括任何实现代码;达梦系统中对象类型与类是等价的。
2. 对象类型中过程和函数可以声明为STATIC类型,表明为静态过程或函数;也可以声明为MEMBER,表明为成员过程或函数,非STATIC且非构造函数的方法缺省为成员方法。MAP表示将对象类型的实例映射为标量数值,只能用于成员函数;
3. 关于对象类型的继承,参考12.1节中类继承的相关说明;
4. WITH ENCRYPTION 选项,指定是否对自定义类型定义进行加密;
5. 记录类型的定义格式与对象类型类似,但记录类型中不能有过程和函数声明;
6. 在< 数组类型定义子句>的数组长度定义的[]内添加’,’可以定义多维数组。若指定了常量表达式,则定义的是静态数组,其数组长度是固定的。若没有指定常量表达式,则定义的是动态数组,其数组长度是在使用时指定。理论上DM支持静态数组的每一个维度的最大长度为65534,动态数组的每一个维度的最大长度为2147483646,但是数组最大长度同时受系统内部空间大小的限制,如果超出堆栈/堆的空间限制,系统会报错。
7. 数组集合类型中的常量表达式定义了其最大容量,其数组元素数据类型可以是基础类型,也可以是自定义数据类型。
8. 嵌套表类型和索引表类型没有元素个数限制,元素数据类型可以是基础数据类型也可以是其它自定义类型或是对象、记录、静态数组,但是不能是动态数组;第二个则是索引表的下标类型,目前仅支持INTEGER/INT和VARCHAR两种类型,分别代表整数下标和字符串下标。对于VARCHAR类型,长度不能超过1024。

所需权限
1. 使用该语句的用户必须是DBA或具有CREATE TYPE数据库权限的用户。
2.可以用关键字AUTHID DEFINER |AUTHID CURRENT_USER指定自定义类型的调用者权限,若为DEFINER,则采用自定义类型定义者权限,若为CURRENT_USER则为当前用户权限,默认为定义者权限。

创建类型体对于对象类型中声明的过程和函数,在类型体中进行实现。
语法格式
CREATE [OR REPLACE] TYPE BODY [< 模式名>.]< 类型名>[WITH ENCRYPTION] AS|IS < 对象类型体定义子句> END
< 对象类型体定义子句>::= < 对象类型体定义>,{< 对象类型体定义>}
< 对象类型体定义>::= < 过程实现>|< 函数实现>|< 构造函数实现>
< 过程实现> ::= [< 方法继承属性>][STATIC|MEMBER] PROCEDURE < 过程名> < 参数列表> AS|IS BEGIN < 实现体> END [过程名]
< 函数实现> ::= [< 方法继承属性>][MAP] [STATIC|MEMBER] FUNCTION < 函数名>< 参数列表> RETURN < 返回值数据类型>[DETERMINISTIC]
[PIPELINED] AS|IS BEGIN < 实现体> END [函数名]
< 方法继承属性> ::= < 重载属性> | | < 重载属性>
< 重载属性> ::= [NOT] OVERRDING
::= FINAL | NOT FINAL | INSTANTIABLE | NOT INSTANTIABLE
< 构造函数实现> ::= CONSTRUCTOR FUNCTION < 函数名> < 参数列表> RETURN SELF AS RESULT AS|IS BEGIN < 实现体> END [函数名]

使用说明
1. 对象类型体中的过程、函数定义必须和类型定义中的前向声明完全相同。包括过程的名字、参数定义列表的参数名和数据类型定义;

所需权限
使用该语句的用户必须是DBA或该类型对象的拥有者且具有CREATE TYPE数据库权限的用户。

重编译类型
重新对类型进行编译,如果重新编译失败,则将类型置为禁止状态。
重编功能主要用于检验类型的正确性。
语法格式
ALTER TYPE [< 模式名>.]< 类型名> COMPILE [DEBUG];
参数
1.< 模式名> 指明被重编译的类型所属的模式;
2.< 类型名> 指明被重编译的类型的名字;
3.[DEBUG] 可忽略。

所需权限
执行该操作的用户必须是类型的创建者,或者具有DBA权限。

删除类型
类型的删除分为类型删除和类型体的删除。对于拥有类型体的对象类型,删除类型会将类型体一起删除;删除类型体的话,类型本身依然存在。

删除类型使用DROP TYPE完成类型的删除。对于拥有类型体的对象类型,删除类型会将类型体一起删除。
语法格式
DROP TYPE [< 模式名>.]< 类型名>[RESTRICT | CASCADE];
使用说明
1.如果被删除的类型不属于当前模式,必须在语句中指明模式名;
2.如果一个拥有类型体的对象类型被删除,那么对应的类型体被自动删除。

所需权限
执行该操作的用户必须是该类型的拥有者,或者具有DBA权限。

删除类型体
使用DROP TYPE BODY删除一个对象类型的类型体。
语法格式
DROP TYPE BODY [< 模式名>.]< 类型名>[RESTRICT | CASCADE]; 使用说明
如果被删除的类型体不属于当前模式,必须在语句中指明模式名。

所需权限
执行该操作的用户必须是该类型的拥有者,或者具有DBA权限。

自定义类型的使用
使用规则
1. 对象类型与类等价,类的使用规则可详见第12章《类类型》;
2. 创建的记录类型、数组类型和集合类型,可以直接在DMSQL程序语句块中使用,不必在语句块中声明类型,使用方式可参见10.1.1节部分;

3. 用户自定义数据类型可以作为其他用户自定义数据类型的元素类型或成员变量类型;
4. 只有对象类型可以直接作为表中列的数据类型;其他类型只能作为对象类型中成员变量的类型或类型中嵌套使用的数据类型。但含有索引表类型和游标类型的对象类型也不能作为表中列的数据类型。

应用实例
创建一个用来表示复数的对象类型,有实数部分和虚数部分,并实现了复数的加与减的操作。

SQL> CREATE TYPE COMPLEX AS OBJECT(
2     RPART REAL,
3     IPART REAL,
4     FUNCTION PLUS(X COMPLEX) RETURN COMPLEX,
5     FUNCTION LES(X COMPLEX) RETURN COMPLEX
6   );
7   /
executed successfully
used time: 53.553(ms). Execute id is 128

SQL> CREATE TYPE BODY COMPLEX AS
2     FUNCTION PLUS(X COMPLEX) RETURN COMPLEX IS
3     BEGIN
4      RETURN COMPLEX(RPART+X.RPART, IPART+X.IPART);
5     END;
6     FUNCTION LES(X COMPLEX) RETURN COMPLEX IS
7     BEGIN
8      RETURN COMPLEX(RPART-X.RPART, IPART-X.IPART);
9     END;
10  END;
11  /
executed successfully
used time: 14.330(ms). Execute id is 129.

建立表c_tab,表中的第二列的列类型为complex对象类型。

SQL> CREATE TABLE C_TAB(C1 INT, C2 COMPLEX);
executed successfully
used time: 16.381(ms). Execute id is 130.
SQL> INSERT INTO C_TAB VALUES(1, COMPLEX(2,3));
affect rows 1

used time: 1.508(ms). Execute id is 131.

向表c_tab中插入数据

SQL> INSERT INTO C_TAB VALUES(2, COMPLEX(4,2).PLUS(COMPLEX(2,3)));
affect rows 1

used time: 0.969(ms). Execute id is 132.
SQL> commit;
executed successfully
used time: 10.709(ms). Execute id is 133.
SQL> select * from c_tab;

LINEID     C1          C2
---------- ----------- -------------------
1          1           SYSDBA.COMPLEX(2,3)
2          2           SYSDBA.COMPLEX(6,5)

used time: 1.047(ms). Execute id is 134.