信创配套实验手册(试用)


信创配套实验手册

配合《信创完整教程》使用 | 共14个实验 | 建议总课时:40-56学时

实验环境如有差异,请根据实际软硬件版本查阅对应产品官方文档。


实验环境总览

环境要求

资源 最低配置 推荐配置
信创服务器 飞腾S2500/鲲鹏920,32核/64GB/500GB SSD ×2 同左 ×3台
信创桌面终端 飞腾D2000/龙芯3A6000,8GB/256GB SSD ×2台
操作系统 麒麟V10服务器版 / 统信UOS
虚拟化 KVM环境(可复用物理机搭建VM)
网络 内网互通,千兆

虚拟机规划(单物理机方案)

如果只有一台物理服务器,通过KVM创建以下虚拟机:

虚拟机 角色 vCPU 内存 磁盘 IP
vm-db-01 达梦DM8主库 8 16GB 100GB 192.168.100.101
vm-db-02 达梦DM8备库 8 16GB 100GB 192.168.100.102
vm-mw-01 TongWeb节点1 4 8GB 50GB 192.168.100.111
vm-mw-02 TongWeb节点2 4 8GB 50GB 192.168.100.112
vm-app 测试应用 4 8GB 50GB 192.168.100.121
vm-client 桌面客户端 4 8GB 100GB 192.168.100.131

实验前准备

# 所有节点:配置hosts
cat >> /etc/hosts << 'EOF'
192.168.100.101 vm-db-01
192.168.100.102 vm-db-02
192.168.100.111 vm-mw-01
192.168.100.112 vm-mw-02
192.168.100.121 vm-app
192.168.100.131 vm-client
EOF

# 所有节点:关闭SELinux和防火墙(实验环境)
setenforce 0
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
systemctl stop firewalld && systemctl disable firewalld

# 所有节点:配置时间同步
timedatectl set-timezone Asia/Shanghai
dnf install -y chrony
systemctl enable chronyd --now

实验一:信创CPU架构识别与硬件认知

课时: 2学时 | 难度: ★★ | 类型: 认知验证

1.1 实验目的

  • 掌握信创CPU架构的识别方法
  • 了解不同CPU的硬件特性差异
  • 学会查看系统硬件信息

1.2 实验步骤

Step 1:识别CPU架构

# 查看CPU架构
uname -m
# 输出: aarch64(ARM/鲲鹏/飞腾) | loongarch64(龙芯) | x86_64(海光/兆芯/Intel)

# 查看CPU详细信息
lscpu
# 关注: Architecture, CPU(s), Thread(s) per core, Model name, CPU max MHz

# 查看CPU厂商信息
cat /proc/cpuinfo | grep -E "model name|vendor|CPU architecture" | head -5

# 查看CPU的字节序
echo -n I | od -to2 | awk '{print $2}'
# 输出1 = 小端(Little Endian),符合ARM/x86

Step 2:识别硬件平台

# 查看服务器型号
dmidecode -t system | grep -E "Manufacturer|Product Name"

# 查看BIOS信息
dmidecode -t bios | grep -E "Vendor|Version|Release Date"
# 信创平台BIOS通常为 昆仑BIOS(华为)/Byosoft(百敖)/昆仑固件

# 查看BMC管理芯片
ipmitool mc info 2>/dev/null | grep -E "Manufacturer|Product"

Step 3:内存与存储识别

# 内存信息
free -h
dmidecode -t memory | grep -E "Size|Type|Speed|Manufacturer" | grep -v "No Module"

# 磁盘信息
lsblk -d -o NAME,SIZE,TYPE,TRAN,MODEL
fdisk -l | grep "Disk /dev"

Step 4:网络与PCI设备

# 网卡信息
lspci | grep -i ethernet
ip link show

# 国产网卡识别(网讯等)
lspci | grep -i netswift

# 所有PCI设备
lspci

1.3 实验记录

检查项 记录值
CPU架构
CPU型号/核数
服务器厂商/型号
BIOS厂商
内存总量
磁盘型号/容量
网卡型号

1.4 思考题

  1. ARM64(x86_64/LoongArch)架构与x86_64架构在内存对齐方面有何差异?
  2. 如何判断一个二进制程序能否在当前CPU架构上运行?

实验二:麒麟操作系统安装与基础配置

课时: 3学时 | 难度: ★★★ | 类型: 安装部署

2.1 实验目的

  • 掌握麒麟V10服务器版的安装流程
  • 掌握系统初始化配置
  • 掌握包管理和用户管理

2.2 实验步骤

Step 1:系统安装

1. 下载ISO  制作USB启动盘  从USB引导
2. 安装选项
   - 语言中文
   - 分区手动分区
     /boot      1GB
     /boot/efi  512MB (UEFI模式)
     /          50GB
     /home      剩余空间
     swap       16GB
   - 软件包选择"带GUI的服务器""最小安装"
   - 设置root密码创建管理员用户
3. 完成安装重启

Step 2:初始化配置

# 1. 验证系统版本
cat /etc/kylin-release
uname -r

# 2. 配置主机名
hostnamectl set-hostname kylin-lab-01
hostnamectl status

# 3. 配置静态IP
nmcli con show                          # 查看连接名
nmcli con mod "ens33" \
    ipv4.addresses 192.168.100.101/24 \
    ipv4.gateway 192.168.100.1 \
    ipv4.dns 114.114.114.114 \
    ipv4.method manual
nmcli con down "ens33" && nmcli con up "ens33"
ip addr show

# 4. 配置YUM/DNF源
cat > /etc/yum.repos.d/kylin-local.repo << 'EOF'
[kylin-base]
name=Kylin Base
baseurl=file:///mnt/cdrom
enabled=1
gpgcheck=0
EOF

# 挂载ISO作为本地源
mkdir -p /mnt/cdrom
mount -o loop /path/to/kylin.iso /mnt/cdrom
dnf makecache

# 5. 安装常用工具
dnf install -y vim wget curl net-tools lsof tcpdump \
    telnet bash-completion unzip tar gzip

Step 3:用户与权限管理

# 创建三权分立用户
useradd -m sysadmin     # 系统管理员
useradd -m secadmin     # 安全管理员
useradd -m auditadmin   # 审计管理员

passwd sysadmin
passwd secadmin
passwd auditadmin

# 创建应用用户
groupadd appgroup
useradd -g appgroup -m appuser

# 配置sudo权限
echo "sysadmin ALL=(ALL) ALL" >> /etc/sudoers.d/sysadmin

Step 4:SSH与远程管理

# 确保SSH服务运行
systemctl enable sshd --now

# 配置密钥登录(可选)
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519
ssh-copy-id root@192.168.100.101

# 安全加固(实验环境可跳过)
# vim /etc/ssh/sshd_config
# PermitRootLogin prohibit-password
# PasswordAuthentication no
# systemctl restart sshd

2.3 验证清单

验证项 命令 预期结果
系统版本 cat /etc/kylin-release Kylin V10
内核 uname -r 5.10.x
网络 ping 114.114.114.114
YUM源 dnf repolist 有可用源
SSH systemctl status sshd active

2.4 常见问题

问题 解决
安装后无法引导 检查UEFI/BIOS引导模式,确保分区方案匹配
网络不通 nmcli 检查连接状态,确认网卡名称
YUM源报错 检查ISO挂载,运行 dnf clean all && dnf makecache

实验三:统信UOS系统管理

课时: 3学时 | 难度: ★★★ | 类型: 系统管理

3.1 实验目的

  • 掌握UOS服务器版的系统管理
  • 对比UOS与麒麟的命令差异
  • 掌握容器与虚拟化基础

3.2 实验步骤

Step 1:系统信息与包管理

# UOS版本信息
cat /etc/os-release
cat /etc/product-info

# 服务器版包管理(RPM体系,与麒麟一致)
dnf install -y nginx
systemctl enable nginx --now

# 查看已安装软件包
rpm -qa | wc -l         # 包总数
rpm -qa | grep kernel   # 内核包

Step 2:Docker容器环境搭建

# 安装Docker
dnf install -y docker-ce containerd.io
# 如果官方源不可用,使用系统自带的docker
dnf install -y docker

systemctl enable docker --now
docker version

# 配置镜像加速(可选)
cat > /etc/docker/daemon.json << 'EOF'
{
  "registry-mirrors": ["https://mirror.ccs.tencentyun.com"],
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": { "max-size": "100m" }
}
EOF
systemctl restart docker

# 拉取ARM64架构镜像
docker pull arm64v8/nginx:latest
docker run -d --name nginx-test -p 8080:80 arm64v8/nginx:latest
curl localhost:8080
docker rm -f nginx-test

Step 3:KVM虚拟化

# 安装虚拟化组件
dnf install -y qemu-kvm libvirt virt-install virt-manager bridge-utils

systemctl enable libvirtd --now

# 验证KVM
lsmod | grep kvm
# ARM平台输出: kvm
# x86平台输出: kvm_intel 或 kvm_amd

# 创建桥接网络
cat > /tmp/bridge.xml << 'EOF'
<network>
  <name>br0</name>
  <forward mode="bridge"/>
  <bridge name="br0"/>
</network>
EOF
# virsh net-define /tmp/bridge.xml  # 按需启用

# 查看虚拟化能力
virsh capabilities | grep -A5 "<cpu>"

Step 4:统信特有工具

# 统信有易 — 系统迁移评估(如可用)
# deepin-system-migration-tool --check-source centos7

# 统信有雀 — 容器平台(如可用)
# k8s-installer --version

# 桌面版工具(仅桌面环境)
# dde-control-center     # 控制中心
# dde-file-manager       # 文件管理器

3.3 麒麟 vs UOS 操作对比

操作 麒麟V10 统信UOS
查看版本 cat /etc/kylin-release cat /etc/os-release
包管理 dnf (RPM) dnf (服务器)/apt (桌面)
默认桌面 UKUI DDE
SELinux工具 semanage semanage
防火墙 firewall-cmd firewall-cmd

实验四:达梦DM8数据库安装与配置

课时: 4学时 | 难度: ★★★★ | 类型: 安装部署

4.1 实验目的

  • 掌握达梦DM8的完整安装流程
  • 掌握实例创建和参数配置
  • 掌握用户、表空间和权限管理

4.2 实验步骤

Step 1:环境准备

# 创建用户和目录(root执行)
groupadd dinstall
useradd -g dinstall -m -d /home/dmdba dmdba
echo "dmdba:DM@2024pass" | chpasswd

mkdir -p /opt/dmdbms
mkdir -p /opt/dmdbms/data
mkdir -p /opt/dmdbms/backup
mkdir -p /opt/dmdbms/arch
chown -R dmdba:dinstall /opt/dmdbms

# 系统参数调整
cat >> /etc/security/limits.conf << 'EOF'
dmdba soft nofile 65536
dmdba hard nofile 65536
dmdba soft nproc 20480
dmdba hard nproc 20480
EOF

# 调整内核参数
cat >> /etc/sysctl.conf << 'EOF'
kernel.sem = 250 32000 100 128
net.core.somaxconn = 65535
vm.overcommit_memory = 0
EOF
sysctl -p

Step 2:安装DM8

# 获取安装包(如需从官网下载)
# wget https://package.dameng.com/.../dm8_xxx_arm64.tar.gz

# 挂载ISO或解压
mkdir -p /mnt/dmiso
# mount -o loop dm8_xxx.iso /mnt/dmiso
# 或
tar -zxvf dm8_xxx_arm64.tar.gz -C /tmp/dm8

# 以dmdba用户安装
su - dmdba
cd /tmp/dm8  # 或 /mnt/dmiso
./DMInstall.bin -i

# 按提示操作:
# 1. 选择语言: c (中文)
# 2. 是否输入Key文件路径: n (试用)
# 3. 是否设置时区: 21 (中国标准时间)
# 4. 安装类型: 1 (典型安装)
# 5. 安装目录: /opt/dmdbms
# 6. 确认安装

# root执行安装脚本(安装完成时会提示)
# /opt/dmdbms/script/root/root_installer.sh

Step 3:初始化数据库实例

su - dmdba
cd /opt/dmdbms/bin

# 创建实例
./dminit \
    PATH=/opt/dmdbms/data \
    DB_NAME=DMDB \
    INSTANCE_NAME=DMSERVER \
    PORT_NUM=5236 \
    PAGE_SIZE=32 \
    EXTENT_SIZE=32 \
    LOG_SIZE=2048 \
    CASE_SENSITIVE=1 \
    CHARSET=1 \
    LENGTH_IN_CHAR=1 \
    BLANK_PAD_MODE=1 \
    COMPATIBLE_MODE=1

# 参数说明:
# PAGE_SIZE=32      32K页大小(OLTP推荐)
# CASE_SENSITIVE=1   大小写敏感
# CHARSET=1          UTF-8编码
# COMPATIBLE_MODE=1  Oracle兼容模式

Step 4:注册服务并启动

# root用户注册服务
cd /opt/dmdbms/script/root
./dm_service_installer.sh \
    -t dmserver \
    -p DMSERVER \
    -dm_ini /opt/dmdbms/data/DMDB/dm.ini

# 启动服务
systemctl start DmServiceDMSERVER
systemctl status DmServiceDMSERVER
systemctl enable DmServiceDMSERVER

# 验证
netstat -anp | grep 5236

Step 5:数据库初始配置

# 连接数据库
cd /opt/dmdbms/bin
./disql SYSDBA/SYSDBA@localhost:5236
-- 创建表空间
CREATE TABLESPACE TS_DATA 
  DATAFILE '/opt/dmdbms/data/DMDB/ts_data01.dbf' SIZE 1024 
  AUTOEXTEND ON NEXT 256 MAXSIZE 10240;

CREATE TABLESPACE TS_IDX
  DATAFILE '/opt/dmdbms/data/DMDB/ts_idx01.dbf' SIZE 512
  AUTOEXTEND ON NEXT 128 MAXSIZE 5120;

CREATE TABLESPACE TS_TEMP
  TEMPFILE '/opt/dmdbms/data/DMDB/ts_temp01.dbf' SIZE 512
  AUTOEXTEND ON NEXT 128 MAXSIZE 2048;

-- 创建应用用户
CREATE USER appuser IDENTIFIED BY "App@123456"
  DEFAULT TABLESPACE TS_DATA
  DEFAULT INDEX TABLESPACE TS_IDX
  TEMPORARY TABLESPACE TS_TEMP;

-- 授权
GRANT RESOURCE, CREATE SESSION, CREATE TABLE, 
      CREATE VIEW, CREATE PROCEDURE, CREATE SEQUENCE,
      CREATE TRIGGER, CREATE SYNONYM TO appuser;

-- 验证
SELECT username, account_status FROM dba_users;

-- 退出
EXIT;

4.3 验证清单

验证项 命令 预期
服务状态 systemctl status DmServiceDMSERVER active
端口监听 netstat -anp \| grep 5236 LISTEN
连接测试 ./disql SYSDBA/SYSDBA@localhost:5236 进入SQL>
表空间 SELECT name, total_size*32/1024 AS MB FROM v$tablespace; 三个表空间

实验五:达梦DM8 SQL开发与PL/SQL

课时: 4学时 | 难度: ★★★ | 类型: 开发实践

5.1 实验目的

  • 掌握达梦DM8 SQL语法(Oracle兼容模式)
  • 掌握存储过程、函数、触发器开发
  • 对比Oracle与达梦的SQL差异

5.2 创建实验数据

-- 以appuser连接
CONNECT appuser/"App@123456"@localhost:5236

-- 创建部门表
CREATE TABLE departments (
    dept_id     NUMBER(10) PRIMARY KEY,
    dept_name   VARCHAR2(100) NOT NULL,
    parent_id   NUMBER(10),
    create_date DATE DEFAULT SYSDATE
);

-- 创建员工表
CREATE TABLE employees (
    emp_id      NUMBER(10) PRIMARY KEY,
    emp_name    VARCHAR2(100) NOT NULL,
    dept_id     NUMBER(10) REFERENCES departments(dept_id),
    hire_date   DATE DEFAULT SYSDATE,
    salary      NUMBER(12,2) CHECK (salary > 0),
    email       VARCHAR2(200) UNIQUE,
    status      CHAR(1) DEFAULT '1'
);

-- 创建索引
CREATE INDEX idx_emp_dept ON employees(dept_id);
CREATE INDEX idx_emp_hire ON employees(hire_date);

-- 插入数据
INSERT INTO departments VALUES (1, '技术部', NULL, SYSDATE);
INSERT INTO departments VALUES (2, '产品部', NULL, SYSDATE);
INSERT INTO departments VALUES (3, '前端组', 1, SYSDATE);
INSERT INTO departments VALUES (4, '后端组', 1, SYSDATE);
INSERT INTO departments VALUES (5, '市场部', NULL, SYSDATE);

INSERT INTO employees VALUES (1001, '张三', 3, '2022-01-15', 15000, 'zhangsan@test.com', '1');
INSERT INTO employees VALUES (1002, '李四', 4, '2022-03-20', 18000, 'lisi@test.com', '1');
INSERT INTO employees VALUES (1003, '王五', 4, '2022-06-01', 22000, 'wangwu@test.com', '1');
INSERT INTO employees VALUES (1004, '赵六', 2, '2023-01-10', 20000, 'zhaoliu@test.com', '1');
INSERT INTO employees VALUES (1005, '钱七', 5, '2023-04-15', 16000, 'qianqi@test.com', '0');
INSERT INTO employees VALUES (1006, '孙八', 4, '2023-08-01', 25000, 'sunba@test.com', '1');
COMMIT;

5.3 SQL练习

-- ===== 练习1:分页查询 =====
-- 按工资降序,取第2页(每页3条)
-- 达梦方式(LIMIT)
SELECT * FROM employees ORDER BY salary DESC LIMIT 3, 3;

-- Oracle兼容方式(ROWNUM,仍然可用)
SELECT * FROM (
  SELECT ROWNUM rn, t.* FROM (
    SELECT * FROM employees ORDER BY salary DESC
  ) t WHERE ROWNUM <= 6
) WHERE rn > 3;

-- ===== 练习2:递归查询(CONNECT BY)=====
-- 查询部门层级树
SELECT dept_id, dept_name, parent_id, LEVEL
FROM departments
START WITH parent_id IS NULL
CONNECT BY PRIOR dept_id = parent_id;

-- ===== 练习3:分析函数 =====
-- 各部门工资排名
SELECT emp_name, dept_id, salary,
       RANK() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS rank,
       DENSE_RANK() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS dense_rk,
       ROUND(salary / SUM(salary) OVER (PARTITION BY dept_id) * 100, 2) AS pct
FROM employees
WHERE status = '1';

-- ===== 练习4:MERGE语句 =====
-- 合并员工数据
MERGE INTO employees e
USING (
    SELECT 1001 AS emp_id, '张三丰' AS emp_name, 3 AS dept_id, 17000 AS salary FROM dual
    UNION ALL
    SELECT 1007, '周九', 3, 12000 FROM dual
) src ON (e.emp_id = src.emp_id)
WHEN MATCHED THEN UPDATE SET e.emp_name = src.emp_name, e.salary = src.salary
WHEN NOT MATCHED THEN INSERT (emp_id, emp_name, dept_id, salary)
    VALUES (src.emp_id, src.emp_name, src.dept_id, src.salary);

-- 验证
SELECT * FROM employees WHERE emp_id IN (1001, 1007);
ROLLBACK;

5.4 PL/SQL开发

-- ===== 存储过程:薪资调整 =====
CREATE OR REPLACE PROCEDURE proc_salary_adjust(
    p_dept_id   IN NUMBER,
    p_rate      IN NUMBER,
    p_min_sal   IN NUMBER DEFAULT 0,
    p_out_count OUT NUMBER,
    p_out_total OUT NUMBER
)
AS
    v_count NUMBER;
BEGIN
    -- 记录日志
    DBMS_OUTPUT.PUT_LINE('开始调薪: 部门=' || p_dept_id || 
                         ', 比例=' || p_rate);

    -- 更新薪资(跳过低于最低薪资的)
    UPDATE employees
    SET salary = ROUND(salary * (1 + p_rate))
    WHERE dept_id = p_dept_id
      AND status = '1'
      AND salary >= p_min_sal;

    p_out_count := SQL%ROWCOUNT;
    SELECT NVL(SUM(salary), 0) INTO p_out_total
    FROM employees WHERE dept_id = p_dept_id AND status = '1';

    COMMIT;
    DBMS_OUTPUT.PUT_LINE('完成: 更新' || p_out_count || '人');
EXCEPTION
    WHEN OTHERS THEN
        ROLLBACK;
        DBMS_OUTPUT.PUT_LINE('错误: ' || SQLERRM);
        RAISE;
END;
/

-- 调用存储过程
DECLARE
    v_count NUMBER;
    v_total NUMBER;
BEGIN
    proc_salary_adjust(4, 0.1, 0, v_count, v_total);
    DBMS_OUTPUT.PUT_LINE('更新人数: ' || v_count);
    DBMS_OUTPUT.PUT_LINE('调薪后总额: ' || v_total);
END;
/

-- ===== 函数:获取员工层级路径 =====
CREATE OR REPLACE FUNCTION fn_get_dept_path(p_emp_id NUMBER)
RETURN VARCHAR2
AS
    v_path VARCHAR2(500);
BEGIN
    SELECT LISTAGG(dept_name, ' → ') WITHIN GROUP (ORDER BY LEVEL DESC)
    INTO v_path
    FROM departments
    START WITH dept_id = (SELECT dept_id FROM employees WHERE emp_id = p_emp_id)
    CONNECT BY PRIOR parent_id = dept_id;

    RETURN v_path;
END;
/

-- 测试
SELECT emp_name, fn_get_dept_path(emp_id) AS dept_path
FROM employees WHERE status = '1';

-- ===== 触发器:审计日志 =====
CREATE TABLE audit_log (
    log_id      NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    table_name  VARCHAR2(100),
    op_type     VARCHAR2(10),
    record_id   NUMBER,
    old_salary  NUMBER(12,2),
    new_salary  NUMBER(12,2),
    op_time     TIMESTAMP DEFAULT SYSTIMESTAMP,
    op_user     VARCHAR2(100) DEFAULT USER
);

CREATE OR REPLACE TRIGGER trg_emp_salary_change
AFTER UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
    INSERT INTO audit_log (table_name, op_type, record_id, old_salary, new_salary)
    VALUES ('EMPLOYEES', 'UPDATE', :OLD.emp_id, :OLD.salary, :NEW.salary);
END;
/

-- 测试触发器
UPDATE employees SET salary = salary * 1.1 WHERE emp_id = 1001;
SELECT * FROM audit_log;
ROLLBACK;

5.5 达梦特殊功能

-- 查看执行计划
EXPLAIN SELECT e.emp_name, d.dept_name
FROM employees e JOIN departments d ON e.dept_id = d.dept_id
WHERE e.salary > 15000;

-- 设置自动SQL跟踪
CALL SP_SET_PARA_VALUE(1, 'SQL_TRACE_MASK', ':all');
CALL SP_SET_PARA_VALUE(1, 'SVR_LOG', 1);

-- 查看慢SQL(另开session执行几条SQL后查看)
SELECT elapsed_time/1000 AS sec, 
       SUBSTR(executed_sql_text, 1, 200) AS sql_text
FROM V$LONG_EXEC_SQLS
WHERE elapsed_time > 100
ORDER BY elapsed_time DESC;

-- 关闭跟踪
CALL SP_SET_PARA_VALUE(1, 'SVR_LOG', 0);

实验六:达梦DM8备份恢复与数据守护

课时: 4学时 | 难度: ★★★★ | 类型: 运维实践

6.1 实验目的

  • 掌握DM8的物理备份与逻辑备份
  • 掌握备份恢复操作
  • 掌握数据守护(主备)的搭建

6.2 备份与恢复

物理备份

# 使用DMRMAN工具(dmdba用户)
su - dmdba
cd /opt/dmdbms/bin

# 全量备份
./dmrman CTLSTMT="BACKUP DATABASE '/opt/dmdbms/data/DMDB/dm.ini' FULL BACKUPSET '/opt/dmdbms/backup/full_$(date +%Y%m%d)'"

# 增量备份
./dmrman CTLSTMT="BACKUP DATABASE '/opt/dmdbms/data/DMDB/dm.ini' INCREMENT BACKUPSET '/opt/dmdbms/backup/incr_$(date +%Y%m%d)'"

# 查看备份集
./dmrman CTLSTMT="SHOW BACKUPSET '/opt/dmdbms/backup/full_20240601'"

SQL逻辑备份

# 逻辑导出(dexp)
./dexp appuser/\"App@123456\"@localhost:5236 \
    FILE=/opt/dmdbms/backup/appuser_export.dmp \
    DIRECTORY=/opt/dmdbms/backup \
    SCHEMAS=appuser \
    LOG=/opt/dmdbms/backup/export.log

# 逻辑导入(dimp)
./dimp appuser/\"App@123456\"@localhost:5236 \
    FILE=/opt/dmdbms/backup/appuser_export.dmp \
    SCHEMAS=appuser \
    TABLE_EXISTS_ACTION=REPLACE \
    LOG=/opt/dmdbms/backup/import.log

恢复操作

-- 表级别恢复(闪回查询)
-- 查看15分钟前的数据
SELECT * FROM employees WHEN TIMESTAMP 
    SYSDATE - INTERVAL '15' MINUTE;

-- 恢复到某个时间点的数据
-- ALTER TABLE employees ENABLE ROW MOVEMENT;
-- FLASHBACK TABLE employees TO TIMESTAMP SYSDATE - INTERVAL '10' MINUTE;

6.3 数据守护(主备)搭建

环境

角色 IP 实例名
主库 192.168.100.101 DMSERVER
备库 192.168.100.102 DMSERVER2
监视器 192.168.100.101

主库配置

# 主库(vm-db-01):开启归档
./disql SYSDBA/SYSDBA@localhost:5236
-- 开启归档
ALTER DATABASE MOUNT;
ALTER DATABASE ARCHIVELOG;
ALTER DATABASE ADD ARCHIVELOG 
    'DEST=/opt/dmdbms/arch,TYPE=LOCAL,FILE_SIZE=1024,SPACE_LIMIT=51200';
ALTER DATABASE OPEN;

-- 确认归档模式
SELECT arch_mode FROM v$database;  -- 应为 Y

-- 配置MAL(在dm.ini所在目录创建dmmal.ini)
-- 后续步骤通过编辑配置文件完成
EXIT;
# 编辑 /opt/dmdbms/data/DMDB/dmmal.ini
cat > /opt/dmdbms/data/DMDB/dmmal.ini << 'EOF'
MAL_CHECK_INTERVAL  = 5
MAL_CONN_FAIL_INTERVAL = 5
[MAL_INST1]
    MAL_INST_NAME = DMSERVER
    MAL_HOST = 192.168.100.101
    MAL_PORT = 61141
    MAL_INST_HOST = 192.168.100.101
    MAL_INST_PORT = 5236
    MAL_DW_PORT = 52141
[MAL_INST2]
    MAL_INST_NAME = DMSERVER2
    MAL_HOST = 192.168.100.102
    MAL_PORT = 61142
    MAL_INST_HOST = 192.168.100.102
    MAL_INST_PORT = 5237
    MAL_DW_PORT = 52142
EOF

备库配置

# 备库(vm-db-02):需要先初始化一个与主库同名的实例
su - dmdba
cd /opt/dmdbms/bin
./dminit PATH=/opt/dmdbms/data DB_NAME=DMDB \
    INSTANCE_NAME=DMSERVER2 PORT_NUM=5237 \
    PAGE_SIZE=32 CASE_SENSITIVE=1

# 同样配置dmmal.ini(内容同上)
# 同样开启归档

同步与验证

-- 主库设置数据守护
ALTER DATABASE ADD DATAGUARD GROUP 'DG1' 
  INSTANCE 'GRP1_DMSERVER' 
  CONNECT IDENTIFIER 'DMSERVER@192.168.100.101:5236';

ALTER DATABASE ADD DATAGUARD GROUP 'DG1' 
  INSTANCE 'GRP1_DMSERVER2' 
  CONNECT IDENTIFIER 'DMSERVER2@192.168.100.102:5237';

-- 查看数据守护状态
SELECT * FROM V$DATAGUARD;

6.4 验证清单

验证项 方法 预期
归档已开启 SELECT arch_mode FROM v$database; Y
备份成功 dmrman SHOW BACKUPSET 有备份集
导出成功 检查dmp文件 文件>0
主备状态 SELECT * FROM V$DATAGUARD; 状态正常

实验七:东方通TongWeb安装与部署

课时: 4学时 | 难度: ★★★ | 类型: 安装部署

7.1 实验目的

  • 掌握TongWeb的安装和启动
  • 掌握Web应用部署(WAR包)
  • 掌握数据源配置

7.2 实验步骤

Step 1:环境准备

# 安装毕昇JDK(华为开源,ARM优化)
# 下载地址: https://www.hikunpeng.com/developer/boostkit/jdk
# 或使用系统自带JDK

dnf install -y java-11-openjdk java-11-openjdk-devel
# 或安装毕昇JDK
# tar -zxvf bisheng-jdk-11.0.x-linux-aarch64.tar.gz -C /opt
# ln -s /opt/bisheng-jdk-11.0.x /opt/jdk

# 配置JAVA_HOME
cat >> /etc/profile.d/java.sh << 'EOF'
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk
# export JAVA_HOME=/opt/jdk  # 如果用毕昇JDK
export PATH=$JAVA_HOME/bin:$PATH
EOF
source /etc/profile.d/java.sh
java -version

Step 2:安装TongWeb

# 下载解压(以实际版本为准)
tar -zxvf TongWeb7.0.x.tar.gz -C /opt
cd /opt/TongWeb7.0

# 目录结构
ls -la
# bin/     启动脚本
# conf/    配置文件
# lib/     核心库
# autodeploy/  自动部署目录
# domains/ 域目录

Step 3:启动与访问

cd /opt/TongWeb7.0/bin

# 启动
./startserver.sh
# 等待提示 "TongWeb Server Started"

# 查看日志
tail -f /opt/TongWeb7.0/logs/server.log

# 检查端口
netstat -anp | grep -E "9060|8080"

# 访问管理控制台
# http://192.168.100.111:9060/console
# 默认用户名/密码: admin/tongweb(首次登录后修改)

Step 4:部署测试应用

4.1 创建测试WAR包

# 在vm-app上创建简单的Web应用
mkdir -p /tmp/testapp/WEB-INF
cat > /tmp/testapp/WEB-INF/web.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="4.0">
    <display-name>TestApp</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>
EOF

cat > /tmp/testapp/index.html << 'EOF'
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>信创测试</title></head>
<body>
    <h1>信创平台测试页面</h1>
    <p>服务器时间: <span id="time"></span></p>
    <p>运行环境: TongWeb + 毕昇JDK + 麒麟OS + ARM64</p>
    <script>document.getElementById('time').textContent = new Date().toLocaleString();</script>
</body>
</html>
EOF

# 打包
cd /tmp/testapp
jar -cvf /tmp/testapp.war *

4.2 部署应用

# 方式1:自动部署(复制到autodeploy目录)
cp /tmp/testapp.war /opt/TongWeb7.0/autodeploy/

# 方式2:管理控制台部署
# 登录 → 应用管理 → 部署应用 → 选择WAR包 → 部署

# 验证
curl http://localhost:8080/testapp/

Step 5:配置达梦数据源

# 复制达梦JDBC驱动到TongWeb
cp /opt/dmdbms/drivers/jdbc/DmJdbcDriver18.jar /opt/TongWeb7.0/lib/
# 重启TongWeb
cd /opt/TongWeb7.0/bin
./stopserver.sh && ./startserver.sh

通过管理控制台配置数据源,或编辑配置文件:

<!-- /opt/TongWeb7.0/conf/tongweb.xml 中添加 -->
<Resource name="jdbc/DMDS" 
    auth="Container"
    type="javax.sql.DataSource"
    factory="com.tongtech.tongweb.jdbc.DataSourceFactory"
    driverClassName="dm.jdbc.driver.DmDriver"
    url="jdbc:dm://192.168.100.101:5236/DMDB"
    username="appuser"
    password="App@123456"
    maxActive="100"
    maxIdle="30"
    maxWait="10000"
    validationQuery="select 1 from dual"
    testOnBorrow="true"/>

Step 6:创建JSP测试数据源

cat > /tmp/dstest/index.jsp << 'EOF'
<%@ page import="javax.naming.*, javax.sql.*, java.sql.*" %>
<html>
<head><meta charset="UTF-8"><title>数据源测试</title></head>
<body>
<h2>达梦数据库连接测试</h2>
<%
    Context ctx = new InitialContext();
    DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/DMDS");
    Connection conn = ds.getConnection();
    Statement stmt = conn.createStatement();
    ResultSet rs = stmt.executeQuery("SELECT count(*) FROM employees");
    rs.next();
    out.println("<p>员工总数: " + rs.getInt(1) + "</p>");
    rs.close(); stmt.close(); conn.close();
%>
<p style="color:green">✓ 数据库连接测试通过</p>
</body>
</html>
EOF
cd /tmp/dstest && jar -cvf /tmp/dstest.war *
cp /tmp/dstest.war /opt/TongWeb7.0/autodeploy/
curl http://localhost:8080/dstest/

7.3 验证清单

验证项 方法 预期
TongWeb启动 tail -f logs/server.log "Started"
控制台可访问 浏览器访问9060端口 登录页
测试应用 curl http://localhost:8080/testapp/ 返回HTML
数据源 管理控制台→数据源→测试连接 成功

实验八:TongWeb集群与会话复制

课时: 3学时 | 难度: ★★★★ | 类型: 高可用实践

8.1 实验目的

  • 掌握TongWeb集群的搭建
  • 掌握Session复制配置
  • 掌握Nginx负载均衡配置

8.2 架构

         Nginx (vm-app:80)
              │
    ┌─────────┼─────────┐
    │         │         │
TongWeb-1  TongWeb-2  (备用)
 .111:8080  .112:8080
    │         │
    └────┬────┘
         │
    达梦DM8 (vm-db-01:5236)

8.3 集群配置

TongWeb节点1和2

在vm-mw-01和vm-mw-02上各配置 tongweb.xml

<!-- 集群配置 -->
<cluster>
    <cluster-name>TongWebCluster</cluster-name>
    <cluster-mode>tcp</cluster-mode>
    <cluster-members>
        192.168.100.111:7800,192.168.100.112:7800
    </cluster-members>
    <session-replication>true</session-replication>
    <session-replication-mode>all</session-replication-mode>
</cluster>

创建Session测试应用

# 创建测试应用,验证Session复制
cat > /tmp/sessiontest/index.jsp << 'EOF'
<%@ page session="true" %>
<html>
<head><meta charset="UTF-8"><title>Session测试</title></head>
<body>
<h2>Session复制测试</h2>
<%
    String server = java.net.InetAddress.getLocalHost().getHostName();
    Integer count = (Integer) session.getAttribute("count");
    count = (count == null) ? 1 : count + 1;
    session.setAttribute("count", count);
%>
<p>访问服务器: <b><%= server %></b></p>
<p>Session ID: <b><%= session.getId() %></b></p>
<p>访问次数: <b><%= count %></b></p>
<p>创建时间: <b><%= new java.util.Date(session.getCreationTime()) %></b></p>
</body>
</html>
EOF

Nginx负载均衡配置

# vm-app上安装Nginx
dnf install -y nginx

cat > /etc/nginx/conf.d/tongweb_lb.conf << 'EOF'
upstream tongweb_cluster {
    ip_hash;  # Session保持(集群有Session复制时可用least_conn)
    server 192.168.100.111:8080 weight=1 max_fails=3 fail_timeout=30s;
    server 192.168.100.112:8080 weight=1 max_fails=3 fail_timeout=30s;
}

server {
    listen 80;
    server_name lab.local;

    location / {
        proxy_pass http://tongweb_cluster;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
EOF

systemctl restart nginx

验证Session复制

# 访问Nginx,多次刷新,观察:
# - 被分发到不同的TongWeb节点
# - 访问次数连续累加(说明Session复制生效)
curl http://192.168.100.121/sessiontest/
curl http://192.168.100.121/sessiontest/
curl http://192.168.100.121/sessiontest/

# 模拟节点故障
# 停掉vm-mw-01的TongWeb
ssh vm-mw-01 "/opt/TongWeb7.0/bin/stopserver.sh"
# 再次访问,应该无感知切换到vm-mw-02
curl http://192.168.100.121/sessiontest/

实验九:消息中间件TongLINK/Q实践

课时: 3学时 | 难度: ★★★ | 类型: 开发实践

9.1 实验目的

  • 掌握TongLINK/Q的安装配置
  • 掌握JMS消息的发送和接收
  • 理解点对点和发布订阅模式

9.2 配置消息队列

# 假设TongLINK/Q已安装于 /opt/TongLINKQ
# 创建队列和主题(通过管理工具或配置文件)

# 创建测试队列:TEST.QUEUE
# 创建测试主题:TEST.TOPIC
# 使用管理工具创建
cd /opt/TongLINKQ/bin
# ./tlqadmin create queue --name TEST.QUEUE --queueManager QM1
# ./tlqadmin create topic --name TEST.TOPIC --queueManager QM1

9.3 发送消息示例

// 保存在 /tmp/jmsdemo/Sender.java
import javax.jms.*;
import javax.naming.*;
import java.util.Properties;

public class Sender {
    public static void main(String[] args) throws Exception {
        // JNDI配置
        Properties props = new Properties();
        props.setProperty(Context.INITIAL_CONTEXT_FACTORY,
            "com.tongtech.tonglink.q.jndi.TLQInitialContextFactory");
        props.setProperty(Context.PROVIDER_URL, "tlq://192.168.100.111:10241");
        Context ctx = new InitialContext(props);

        // 获取连接工厂和队列
        ConnectionFactory factory = (ConnectionFactory) 
            ctx.lookup("TongLINKQCF");
        Queue queue = (Queue) ctx.lookup("TEST.QUEUE");

        // 创建连接
        Connection conn = factory.createConnection();
        Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);

        // 发送消息
        MessageProducer producer = session.createProducer(queue);
        for (int i = 1; i <= 10; i++) {
            TextMessage msg = session.createTextMessage(
                "消息 #" + i + " - 发送时间: " + new java.util.Date());
            producer.send(msg);
            System.out.println("已发送: " + msg.getText());
        }

        // 清理
        producer.close();
        session.close();
        conn.close();
        ctx.close();
    }
}

9.4 接收消息示例

// Receiver.java
public class Receiver {
    public static void main(String[] args) throws Exception {
        // ... 同上获取连接
        Connection conn = factory.createConnection();
        conn.start();  // 接收端需要start
        Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);

        MessageConsumer consumer = session.createConsumer(queue);
        consumer.setMessageListener(msg -> {
            if (msg instanceof TextMessage) {
                try {
                    System.out.println("收到: " + ((TextMessage) msg).getText());
                } catch (JMSException e) { e.printStackTrace(); }
            }
        });

        // 等待消息
        Thread.sleep(30000);
        consumer.close();
        session.close();
        conn.close();
    }
}

9.5 编译与运行

# 编译
javac -cp /opt/TongLINKQ/lib/tlq-jms.jar:/opt/TongLINKQ/lib/tlq-jndi.jar \
    Sender.java Receiver.java

# 先启动接收端(后台)
java -cp .:/opt/TongLINKQ/lib/* Receiver &
RECEIVER_PID=$!
sleep 2

# 发送消息
java -cp .:/opt/TongLINKQ/lib/* Sender

# 等待接收完成
sleep 5
kill $RECEIVER_PID 2>/dev/null

9.6 验证清单

验证项 预期结果
发送10条消息 发送端输出10条 "已发送"
接收10条消息 接收端输出10条 "收到"
消息无丢失 发送数 = 接收数

实验十:Oracle到达梦数据迁移实战

课时: 4学时 | 难度: ★★★★ | 类型: 迁移实践

10.1 实验目的

  • 掌握Oracle→达梦的完整迁移流程
  • 掌握DTS工具使用
  • 掌握迁移后的数据校验

10.2 准备源Oracle环境

-- 在Oracle中创建测试数据
CREATE USER migtest IDENTIFIED BY "Test@123";
GRANT CONNECT, RESOURCE, UNLIMITED TABLESPACE TO migtest;

CONNECT migtest/"Test@123"

-- 创建表和测试数据(与实验五结构类似但有更多Oracle特性)
CREATE TABLE departments (
    dept_id     NUMBER(10) PRIMARY KEY,
    dept_name   VARCHAR2(100) NOT NULL,
    parent_id   NUMBER(10),
    create_date DATE DEFAULT SYSDATE
);

CREATE TABLE employees (
    emp_id      NUMBER(10) PRIMARY KEY,
    emp_name    VARCHAR2(100),
    dept_id     NUMBER(10) REFERENCES departments(dept_id),
    hire_date   DATE DEFAULT SYSDATE,
    salary      NUMBER(12,2),
    email       VARCHAR2(200),
    resume      CLOB,
    photo       BLOB
);

-- 创建序列
CREATE SEQUENCE seq_emp_id START WITH 2000 INCREMENT BY 1;

-- 创建存储过程
CREATE OR REPLACE PROCEDURE proc_get_dept_emps(
    p_dept_id IN NUMBER,
    p_cursor  OUT SYS_REFCURSOR
) AS
BEGIN
    OPEN p_cursor FOR
        SELECT emp_id, emp_name, salary
        FROM employees WHERE dept_id = p_dept_id;
END;
/

-- 插入测试数据
INSERT INTO departments VALUES (1, '技术部', NULL, SYSDATE);
INSERT INTO departments VALUES (2, '市场部', NULL, SYSDATE);
INSERT INTO employees VALUES (101, '张三', 1, '2022-01-15', 15000, 'zhang@test.com', '工作认真负责', NULL);
INSERT INTO employees VALUES (102, '李四', 1, '2022-06-01', 22000, 'li@test.com', '技术骨干', NULL);
INSERT INTO employees VALUES (103, '王五', 2, '2023-03-10', 18000, 'wang@test.com', '市场拓展', NULL);
COMMIT;

10.3 使用达梦DTS工具迁移

# 在达梦服务器上启动DTS图形化工具
# 需要X11转发或VNC

# 方式1:图形化
cd /opt/dmdbms/tool
./dts

# 方式2:命令行迁移(通过配置文件)
cat > /tmp/dm_migration.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<migration>
    <source>
        <type>ORACLE</type>
        <host>192.168.100.200</host>
        <port>1521</port>
        <serviceName>ORCL</serviceName>
        <username>migtest</username>
        <password>Test@123</password>
    </source>
    <target>
        <type>DM</type>
        <host>192.168.100.101</host>
        <port>5236</port>
        <username>SYSDBA</username>
        <password>SYSDBA</password>
    </target>
    <options>
        <schemaMapping>MIGTEST->MIGTEST</schemaMapping>
        <tableSpaceMapping>USERS->TS_DATA</tableSpaceMapping>
        <parallel>4</parallel>
        <batchSize>10000</batchSize>
    </options>
</migration>
EOF

# 执行迁移
cd /opt/dmdbms/tool
./dts MIGRATE /tmp/dm_migration.xml

10.4 数据校验

-- 连接达梦,执行校验
CONNECT SYSDBA/SYSDBA@localhost:5236

-- 1. 表行数校验
SELECT '源库Oracle应该有: 3个部门, 3个员工' AS 说明;
SELECT 'departments' AS 表名, COUNT(*) FROM migtest.departments
UNION ALL
SELECT 'employees', COUNT(*) FROM migtest.employees;

-- 2. 数据抽样校验
SELECT emp_id, emp_name, salary 
FROM migtest.employees 
ORDER BY emp_id;

-- 3. 序列值校验
SELECT migtest.seq_emp_id.NEXTVAL FROM dual;

-- 4. 存储过程校验
DECLARE
    v_cur SYS_REFCURSOR;
    v_id NUMBER;
    v_name VARCHAR2(100);
    v_sal NUMBER;
BEGIN
    migtest.proc_get_dept_emps(1, v_cur);
    LOOP
        FETCH v_cur INTO v_id, v_name, v_sal;
        EXIT WHEN v_cur%NOTFOUND;
        DBMS_OUTPUT.PUT_LINE(v_id || ': ' || v_name || ' - ' || v_sal);
    END LOOP;
    CLOSE v_cur;
END;
/

10.5 常见迁移问题处理

问题 解决方案
Oracle特有数据类型(如BFILE) 迁移前改为BLOB存储路径
Oracle的CONNECT BY递归复杂 达梦支持但需测试边界情况
空字符串与NULL差异 DM8设置COMPATIBLE_MODE=1
CLOB字段迁移 DTS默认支持,大字段需单独配置
存储过程编译错误 检查Oracle专有包引用,寻找替代方案

实验十一:WebLogic到TongWeb应用迁移

课时: 3学时 | 难度: ★★★★ | 类型: 迁移实践

11.1 实验目的

  • 掌握WebLogic到TongWeb的应用迁移方法
  • 掌握配置文件的转换
  • 掌握常见迁移问题的处理

11.2 配置文件转换

weblogic.xml → tongweb.xml

<!-- 原WebLogic配置: weblogic.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<weblogic-web-app>
    <context-root>/myapp</context-root>
    <resource-description>
        <res-ref-name>jdbc/AppDS</res-ref-name>
        <jndi-name>jdbc/AppDS</jndi-name>
    </resource-description>
    <session-descriptor>
        <cookie-http-only>true</cookie-http-only>
        <timeout-secs>1800</timeout-secs>
    </session-descriptor>
    <container-descriptor>
        <prefer-application-packages>
            <package-name>org.apache.commons.*</package-name>
        </prefer-application-packages>
    </container-descriptor>
</weblogic-web-app>

<!-- 对应TongWeb配置: tongweb.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<tongweb-web-app>
    <context-root>/myapp</context-root>
    <resource-ref>
        <res-ref-name>jdbc/AppDS</res-ref-name>
        <jndi-name>jdbc/AppDS</jndi-name>
    </resource-ref>
    <session-config>
        <cookie-config>
            <http-only>true</http-only>
        </cookie-config>
        <session-timeout>30</session-timeout>
    </session-config>
    <class-loader>
        <delegate-first>false</delegate-first>
    </class-loader>
</tongweb-web-app>

11.3 Java代码适配

// ====== WebLogic专有API → 标准Jakarta EE ======

// 1. WebLogic Servlet认证
// 原WebLogic代码
import weblogic.servlet.security.ServletAuthentication;
// ServletAuthentication.invalidateAll(request);

// TongWeb替代(标准Jakarta EE)
request.getSession().invalidate();
request.logout();

// 2. WebLogic事务
// 原WebLogic代码  
import weblogic.transaction.TransactionHelper;
// Transaction transaction = TransactionHelper.getTransactionHelper().getTransaction();

// TongWeb替代(标准JTA)
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
// 通过JNDI获取标准TransactionManager
TransactionManager tm = (TransactionManager) 
    new InitialContext().lookup("java:comp/TransactionManager");

// 3. WebLogic专有JNDI名称调整
// 原: java:comp/env/jdbc/MyDS  (WebLogic写法,也可用)
// TongWeb: jdbc/MyDS 即可
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("jdbc/MyDS");

// 4. 日志框架统一
// 避免使用: weblogic.logging.*
// 使用标准: java.util.logging 或 SLF4J/Log4j

11.4 依赖替换清单

WebLogic依赖 TongWeb环境 说明
weblogic.jar 移除 应用不应打包
wls-api.jar 移除 替换为标准Jakarta EE API
weblogic.xml tongweb.xml 配置文件转换
weblogic-application.xml tongweb-application.xml EAR包专用
WebLogic JMS TongLINK/Q或标准JMS 消息中间件替换

11.5 迁移验证清单

# 部署后的验证步骤
# 1. 应用启动无ERROR日志
tail -100 /opt/TongWeb7.0/logs/server.log | grep ERROR

# 2. HTTP可访问
curl -I http://localhost:8080/myapp/

# 3. 数据源连接正常(通过测试页面或API)

# 4. Session功能正常(登录 → 操作 → 退出)

# 5. 定时任务正常触发(如有)

# 6. 日志输出正常(中文无乱码)

实验十二:信创系统性能调优

课时: 4学时 | 难度: ★★★★★ | 类型: 性能调优

12.1 实验目的

  • 掌握达梦数据库的性能诊断与调优
  • 掌握TongWeb JVM调优
  • 掌握操作系统级性能优化

12.2 数据库性能调优

基准测试

-- 创建测试表
CREATE TABLE perf_test (
    id NUMBER PRIMARY KEY,
    col1 VARCHAR2(500),
    col2 VARCHAR2(500),
    col3 NUMBER,
    col4 DATE
);

-- 插入100万条测试数据
BEGIN
    FOR i IN 1..1000000 LOOP
        INSERT INTO perf_test VALUES (
            i,
            'ABCDEFGHIJKLMNOPQRSTUVWXYZ' || i,
            'ZYXWVUTSRQPONMLKJIHGFEDCBA' || i,
            ROUND(DBMS_RANDOM.VALUE(1, 100000)),
            SYSDATE - ROUND(DBMS_RANDOM.VALUE(0, 3650))
        );
        IF MOD(i, 10000) = 0 THEN
            COMMIT;
            DBMS_OUTPUT.PUT_LINE('已插入: ' || i);
        END IF;
    END LOOP;
    COMMIT;
END;
/

-- 创建索引前测试
SET TIMING ON;
SELECT COUNT(*) FROM perf_test WHERE col3 BETWEEN 10000 AND 20000;

-- 创建索引
CREATE INDEX idx_perf_col3 ON perf_test(col3);
CREATE INDEX idx_perf_col4 ON perf_test(col4);
CREATE INDEX idx_perf_col1 ON perf_test(col1);

-- 索引后测试
SELECT COUNT(*) FROM perf_test WHERE col3 BETWEEN 10000 AND 20000;

-- 更新统计信息
DBMS_STATS.GATHER_TABLE_STATS('APPUSER', 'PERF_TEST', NULL, 100);

查看执行计划

-- 查看执行计划
EXPLAIN SELECT e.emp_name, d.dept_name
FROM employees e
JOIN departments d ON e.dept_id = d.dept_id
WHERE e.salary > 15000 AND e.status = '1';

-- 查看慢查询
SELECT 
    elapsed_time/1000 AS 耗时秒,
    SUBSTR(executed_sql_text, 1, 200) AS SQL文本
FROM V$LONG_EXEC_SQLS
WHERE elapsed_time > 500
ORDER BY elapsed_time DESC
LIMIT 10;

-- 查看锁等待
SELECT 
    l.session_id AS 持有会话,
    w.session_id AS 等待会话,
    l.table_id
FROM V$LOCK l
JOIN V$TRXWAIT w ON l.trx_id = w.wait_for_id;

数据库参数调优

-- 查看当前内存参数
SELECT para_name, para_value 
FROM V$DM_INI 
WHERE para_name IN ('BUFFER', 'MAX_BUFFER', 'RECYCLE', 
                     'CACHE_POOL_SIZE', 'DICT_BUF_SIZE',
                     'HJ_BUF_GLOBAL_SIZE', 'HAGR_BUF_GLOBAL_SIZE');

-- 调整缓冲池(按需调整,需重启)
-- ALTER SYSTEM SET 'BUFFER' = 4096;
-- ALTER SYSTEM SET 'MAX_BUFFER' = 8192;

-- 在线调整工作线程
ALTER SYSTEM SET 'WORKER_THREADS' = 16;
ALTER SYSTEM SET 'TASK_THREADS' = 8;

12.3 TongWeb JVM调优

# 编辑 TongWeb JVM 启动参数
# vim /opt/TongWeb7.0/bin/startserver.sh

# 推荐JVM参数(16GB内存服务器)
JAVA_OPTS="-server \
  -Xms8g -Xmx8g \
  -Xmn3g \
  -XX:+UseG1GC \
  -XX:MaxGCPauseMillis=200 \
  -XX:G1HeapRegionSize=16m \
  -XX:InitiatingHeapOccupancyPercent=45 \
  -XX:+ParallelRefProcEnabled \
  -XX:+HeapDumpOnOutOfMemoryError \
  -XX:HeapDumpPath=/opt/TongWeb7.0/logs/heapdump.hprof \
  -XX:+PrintGCDetails \
  -XX:+PrintGCDateStamps \
  -Xloggc:/opt/TongWeb7.0/logs/gc.log \
  -Dfile.encoding=UTF-8 \
  -Djava.security.egd=file:/dev/urandom"

# 重启应用
cd /opt/TongWeb7.0/bin
./stopserver.sh && ./startserver.sh

# 监控GC
tail -f /opt/TongWeb7.0/logs/gc.log
# 使用 jstat 实时监控
jstat -gcutil $(pgrep -f TongWeb) 1000

12.4 操作系统级调优

# CPU调度优化
# 查看当前调度器
cat /sys/block/sda/queue/scheduler

# 磁盘IO优化(SSD使用noop或none)
echo none > /sys/block/sda/queue/scheduler

# 文件系统挂载优化
# /etc/fstab中添加 noatime,nodiratime
# /dev/sda1 /opt/dmdbms/data xfs defaults,noatime,nodiratime 0 0

# 内核参数优化
cat >> /etc/sysctl.conf << 'EOF'
# 网络优化
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 10

# 文件句柄
fs.file-max = 6553500
fs.aio-max-nr = 1048576

# 内存
vm.swappiness = 10
vm.dirty_ratio = 15
vm.dirty_background_ratio = 5
EOF
sysctl -p

# 资源限制
cat >> /etc/security/limits.conf << 'EOF'
* soft nofile 655350
* hard nofile 655350
* soft nproc 655350
* hard nproc 655350
EOF

12.5 性能压测

# 使用Apache Bench简单压测
dnf install -y httpd-tools

# 先预热
ab -n 1000 -c 10 http://localhost:8080/testapp/

# 正式压测
ab -n 10000 -c 100 -t 60 http://localhost:8080/testapp/ | tee /tmp/ab_result.txt

# 关注指标
grep -E "Requests per second|Time per request|Failed requests" /tmp/ab_result.txt

12.6 调优验证

指标 调优前 调优后 改善
数据库查询(全表) 记录 记录
数据库查询(索引) 记录 记录
TPS 记录 记录
GC暂停时间 记录 记录
响应时间P99 记录 记录

实验十三:信创环境安全加固

课时: 3学时 | 难度: ★★★ | 类型: 安全实践

13.1 实验目的

  • 掌握操作系统的安全加固方法
  • 掌握达梦数据库的安全配置
  • 掌握TongWeb的安全配置

13.2 操作系统安全加固

# 1. 密码策略
cat >> /etc/security/pwquality.conf << 'EOF'
minlen = 12
minclass = 3
maxrepeat = 3
maxclassrepeat = 4
lcredit = -1
ucredit = -1
dcredit = -1
ocredit = -1
EOF

# 2. 登录失败锁定
cat >> /etc/pam.d/system-auth << 'EOF'
auth required pam_faillock.so preauth silent audit deny=5 unlock_time=600
auth required pam_faillock.so authfail audit deny=5 unlock_time=600
EOF

# 3. SSH安全加固
cat >> /etc/ssh/sshd_config << 'EOF'
PermitRootLogin no
PasswordAuthentication no
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
Protocol 2
EOF
systemctl restart sshd

# 4. 审计规则
cat >> /etc/audit/rules.d/audit.rules << 'EOF'
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/sudoers -p wa -k sudoers
-w /opt/TongWeb7.0/conf/ -p wa -k tongweb_config
-w /opt/dmdbms/data/ -p wa -k dm_config
EOF
systemctl restart auditd

# 5. 查看审计日志
ausearch -k identity --start today

13.3 达梦数据库安全配置

-- 1. 密码策略
-- 修改SYSDBA密码
ALTER USER SYSDBA IDENTIFIED BY "Secure@Sys2024!";

-- 设置密码复杂度
SP_SET_PARA_VALUE(1, 'PWD_POLICY', 7);
-- 7 = 1(长度) + 2(大小写) + 4(特殊字符)

-- 2. 三权分立
-- 创建安全管理员和审计管理员
CREATE USER secadmin IDENTIFIED BY "Sec@Admin2024!";
CREATE USER auditadmin IDENTIFIED BY "Audit@Admin2024!";

GRANT VTI TO secadmin;
GRANT VTI TO auditadmin;

-- 3. 开启审计
SP_AUDIT_SYSTEM('ALL', 'SYSDBA');
SP_AUDIT_STMT('ALL', 'SYSDBA');

-- 查看审计日志
SELECT * FROM V$AUDIT_RECORDS WHERE ROWNUM <= 20;

-- 4. 数据加密
-- 创建加密表空间
CREATE TABLESPACE TS_SECURE 
  DATAFILE '/opt/dmdbms/data/DMDB/ts_secure.dbf' SIZE 512
  ENCRYPT WITH AES256;

-- 将敏感表移到加密表空间
ALTER TABLE employees MOVE TABLESPACE TS_SECURE;

-- 5. 最小权限原则(回收不必要的权限)
REVOKE DBA FROM appuser;  -- 如果之前授予了
GRANT CONNECT, RESOURCE TO appuser;
GRANT SELECT, INSERT, UPDATE, DELETE ON employees TO appuser;

13.4 TongWeb安全配置

<!-- tongweb.xml 安全配置 -->
<security-config>
    <!-- 禁用目录列表 -->
    <listing>false</listing>

    <!-- Session Cookie安全 -->
    <session-config>
        <cookie-config>
            <http-only>true</http-only>
            <secure>true</secure>
            <same-site>strict</same-site>
        </cookie-config>
        <session-timeout>30</session-timeout>
    </session-config>

    <!-- 配置HTTPS -->
    <ssl-config>
        <ssl-enabled>true</ssl-enabled>
        <keystore-path>/opt/TongWeb7.0/conf/server.keystore</keystore-path>
        <keystore-password>changeit</keystore-password>
        <ssl-port>8443</ssl-port>
    </ssl-config>
</security-config>
# 生成自签名证书(测试用)
keytool -genkey -alias tongweb \
    -keyalg RSA -keysize 2048 \
    -keystore /opt/TongWeb7.0/conf/server.keystore \
    -validity 3650 \
    -dname "CN=lab.local, OU=Lab, O=Lab, L=BJ, ST=BJ, C=CN"

# 配置国密证书(生产环境)
# 需要向CA申请国密SM2证书

13.5 验证清单

验证项 方法
密码策略生效 尝试创建弱密码用户
SSH禁止root ssh root@localhost 应被拒绝
审计日志 ausearch --start today
数据库加密 检查加密表空间
HTTPS可访问 curl -k https://localhost:8443

实验十四:综合实验——信创全栈搭建

课时: 6-8学时 | 难度: ★★★★★ | 类型: 综合实践

14.1 实验目的

综合运用前13个实验的技能,从零搭建一个完整的信创Web应用系统。

14.2 系统需求

构建一个"员工管理系统",要求:

  • 前端:Vue.js(Nginx托管静态文件)
  • 后端:Spring Boot(部署于TongWeb)
  • 数据库:达梦DM8
  • 全部运行于信创平台(ARM64 + 麒麟OS)

14.3 架构图

用户浏览器
    
Nginx (vm-app:80)
    ├── /api/* → TongWeb (vm-mw-01:8080)
    └── /*     → 静态文件 (Vue.js)
         
    TongWeb (Spring Boot应用)
         
    达梦DM8 (vm-db-01:5236)

14.4 数据库设计

-- 创建应用schema
CREATE USER ems IDENTIFIED BY "Ems@2024"
  DEFAULT TABLESPACE TS_DATA
  DEFAULT INDEX TABLESPACE TS_IDX;
GRANT RESOURCE, CREATE SESSION, CREATE TABLE,
      CREATE VIEW, CREATE PROCEDURE TO ems;

CONNECT ems/"Ems@2024"@localhost:5236;

-- 用户表
CREATE TABLE sys_user (
    user_id   NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    username  VARCHAR2(50) NOT NULL UNIQUE,
    password  VARCHAR2(200) NOT NULL,  -- 加密存储
    real_name VARCHAR2(100),
    role      VARCHAR2(20) DEFAULT 'USER',
    status    CHAR(1) DEFAULT '1',
    create_time TIMESTAMP DEFAULT SYSTIMESTAMP
);

-- 员工表
CREATE TABLE employee (
    id        NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    name      VARCHAR2(100) NOT NULL,
    gender    CHAR(1),
    dept_id   NUMBER REFERENCES departments(dept_id),
    position  VARCHAR2(100),
    phone     VARCHAR2(20),
    salary    NUMBER(12,2),
    hire_date DATE
);

-- 预置数据
INSERT INTO sys_user (username, password, real_name, role) 
VALUES ('admin', 'e10adc3949ba59abbe56e057f20f883e', '管理员', 'ADMIN');
-- 密码: 123456 的MD5(仅测试用,生产需使用BCrypt等)

INSERT INTO employee (name, gender, dept_id, position, phone, salary, hire_date)
VALUES ('张三', 'M', 3, '前端开发', '13800001001', 15000, '2022-01-15');
INSERT INTO employee (name, gender, dept_id, position, phone, salary, hire_date)
VALUES ('李四', 'M', 4, '后端开发', '13800001002', 22000, '2022-06-01');
INSERT INTO employee (name, gender, dept_id, position, phone, salary, hire_date)
VALUES ('王五', 'F', 4, '高级工程师', '13800001003', 30000, '2021-03-10');
INSERT INTO employee (name, gender, dept_id, position, phone, salary, hire_date)
VALUES ('赵六', 'M', 2, '产品经理', '13800001004', 25000, '2023-01-10');
COMMIT;

-- 创建API用视图
CREATE VIEW v_employee_list AS
SELECT e.*, d.dept_name
FROM employee e
LEFT JOIN departments d ON e.dept_id = d.dept_id;

14.5 Spring Boot后端开发

项目结构

employee-manager/
├── pom.xml
├── src/main/java/com/lab/ems/
│   ├── EmsApplication.java
│   ├── controller/EmployeeController.java
│   ├── service/EmployeeService.java
│   ├── dao/EmployeeDao.java
│   └── model/Employee.java
└── src/main/resources/
    ├── application.yml
    └── tongweb.xml

pom.xml 关键依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.18</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- 排除内置Tomcat,使用TongWeb -->
</dependencies>

<build>
    <finalName>employee-manager</finalName>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

application.yml

server:
  port: 8080

spring:
  datasource:
    url: jdbc:dm://192.168.100.101:5236/DMDB
    username: ems
    password: Ems@2024
    driver-class-name: dm.jdbc.driver.DmDriver
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: Asia/Shanghai

EmployeeController.java

@RestController
@RequestMapping("/api/employees")
@CrossOrigin(origins = "*")
public class EmployeeController {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @GetMapping
    public ResponseEntity<Map<String, Object>> list(
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "10") int size,
            @RequestParam(required = false) String keyword) {

        StringBuilder sql = new StringBuilder(
            "SELECT * FROM v_employee_list WHERE 1=1");
        StringBuilder countSql = new StringBuilder(
            "SELECT COUNT(*) FROM v_employee_list WHERE 1=1");

        List<Object> params = new ArrayList<>();
        if (keyword != null && !keyword.isEmpty()) {
            sql.append(" AND (name LIKE ? OR position LIKE ?)");
            countSql.append(" AND (name LIKE ? OR position LIKE ?)");
            params.add("%" + keyword + "%");
            params.add("%" + keyword + "%");
        }

        // 分页(达梦语法)
        sql.append(" ORDER BY id LIMIT ?, ?");
        params.add((page - 1) * size);
        params.add(size);

        List<Map<String, Object>> rows = jdbcTemplate.queryForList(
            sql.toString(), params.toArray());

        int total = jdbcTemplate.queryForObject(
            countSql.toString(), Integer.class,
            params.subList(0, params.size() - 2).toArray());

        Map<String, Object> result = new HashMap<>();
        result.put("code", 0);
        result.put("data", rows);
        result.put("total", total);
        return ResponseEntity.ok(result);
    }

    @GetMapping("/{id}")
    public ResponseEntity<Map<String, Object>> getById(@PathVariable Long id) {
        Map<String, Object> emp = jdbcTemplate.queryForMap(
            "SELECT * FROM v_employee_list WHERE id = ?", id);
        return ResponseEntity.ok(Map.of("code", 0, "data", emp));
    }
}

打包与部署

# 编译打包(在开发机上)
mvn clean package -DskipTests

# 部署到TongWeb
# 方式1:直接运行(Spring Boot内嵌模式)
java -jar employee-manager.war --server.port=8080 &

# 方式2:部署到TongWeb(传统WAR部署)
# 1. 将WAR包放入 autodeploy 目录
# 2. 在 tongweb.xml 中配置数据源
# 3. application中通过JNDI获取数据源

14.6 Nginx配置(前端+反向代理)

cat > /etc/nginx/conf.d/ems.conf << 'EOF'
upstream ems_backend {
    server 192.168.100.111:8080;
}

server {
    listen 80;
    server_name ems.lab.local;

    # 前端静态文件
    root /opt/ems-frontend/dist;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }

    # API反向代理
    location /api/ {
        proxy_pass http://ems_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
EOF

systemctl restart nginx

14.7 系统验证

# 1. 验证数据库连接
echo "SELECT COUNT(*) FROM ems.employee;" | \
    /opt/dmdbms/bin/disql ems/\"Ems@2024\"@localhost:5236

# 2. 验证后端API
curl http://192.168.100.121/api/employees?page=1\&size=10
# 预期返回JSON数组

# 3. 验证前端页面
curl -I http://192.168.100.121/
# 预期200 OK

# 4. 完整功能测试
# - 登录
# - 查看员工列表
# - 搜索员工
# - 新增/编辑/删除员工

14.8 实验报告要求

完成实验后,请撰写实验报告,包含:

  1. 环境配置:各组件版本、IP、端口
  2. 架构图:系统的网络拓扑和软件栈
  3. 数据库设计:ER图
  4. 关键代码:核心接口实现
  5. 测试结果:功能测试截图、性能测试数据
  6. 遇到的问题与解决方案

附录A:快速排障手册

现象 排查方向
达梦连接不上 端口是否监听?防火墙是否放行?SELECT status FROM v$instance;
TongWeb启动慢 检查JDK版本,减少JIT编译开销 -XX:TieredStopAtLevel=1
应用部署404 检查context-root,查看日志
数据库慢查询 V$LONG_EXEC_SQLS,EXPLAIN分析,添加索引
内存溢出 jmap -heap <pid>,分析GC日志,调大-Xmx
ARM兼容问题 file <binary> 检查架构,寻找ARM64版本替代

附录B:实验评分标准

评分项 权重 满分标准
环境搭建 20% 所有组件正常运行
数据库操作 20% 完成所有SQL练习,存储过程可运行
应用部署 20% WAR包部署成功,API正常响应
集群/高可用 15% 集群搭建成功,Session复制验证通过
迁移实践 10% 完成数据/应用迁移,数据校验一致
综合实验 15% 员工管理系统完整可运行