达梦数据库(DM8)完全技术指南:从入门到上手的硬核干货
安装部署、SQL实战、代码连接、架构原理——一篇讲透国产数据库怎么用
如果你用过 Oracle 或 MySQL,那么上手达梦只需要搞清楚"它和它们像在哪里、又不一样在哪里"。这篇文章就是你的对照地图。
一、达梦数据库到底是什么?(5分钟搞懂)
1.1 一句话定义
达梦数据库(DM Database)是武汉达梦公司开发的关系型数据库管理系统(RDBMS),核心代码100%自研,兼容Oracle语法,支持Windows/Linux/麒麟/UOS等主流操作系统。
你可以把它理解成:一个中国版的Oracle——功能定位相似、SQL语法高度兼容、但代码完全自主可控。
1.2 核心产品线一览
| 产品 | 定位 | 一句话说明 |
|---|---|---|
| DM8 | 新一代集中式关系型数据库 | 主力产品,支撑千亿级数据实时处理 |
| DM7 | 企业级数据库平台 | 前代产品,仍在大量生产环境运行 |
| DMDSC | 共享存储集群 | 多节点高可用,对标Oracle RAC |
| DM MPP | 分布式分析型数据库 | 海量数据分析,2025版效率提升60% |
| DMDPC | 数据库一体机 | 软硬件一体交付的开箱即用方案 |
本文所有代码示例基于 DM8(当前最广泛使用的版本)。
1.3 架构:单进程多线程 vs Oracle的多进程
这是达梦和Oracle在底层架构上的核心差异:
┌─────────────────────────────────────────────┐ │ 达梦 DM8 实例 │ │ │ │ ┌─────────┐ ┌─────────┐ ┌──────────────┐ │ │ │监听线程 │ │工作线程 │ │ IO线程 │ │ │ │(接收连接)│ │(处理SQL)│ │(磁盘读写) │ │ │ └─────────┘ └─────────┘ └──────────────┘ │ │ │ │ ┌──────────────────────┐ │ │ │ 共享内存池 │ │ │ │ (数据缓冲+日志缓冲) │ │ │ └──────────────────────┘ │ │ │ │ ┌──────────┐ ┌──────────┐ ┌───────────┐ │ │ │数据文件 │ │日志文件 │ │控制文件 │ │ │ │(.DBF) │ │(.LOG) │ │ (.CTL) │ │ │ └──────────┘ └──────────┘ └───────────┘ │ └─────────────────────────────────────────────┘ 对比 Oracle: ┌─────────────────────────────────────────────┐ │ Oracle 实例 │ │ ┌───────┐ ┌───────┐ ┌───────┐ ┌────────┐ │ │ │PMON │ │SMON │ │DBWn │ │LGWR │ │ ← 独立进程 │ │(进程) │ │(进程) │ │(进程) │ │(进程) │ │ │ └───────┘ └───────┘ └───────┘ └────────┘ │ └─────────────────────────────────────────────┘
关键区别:
-
达梦:单进程 + 多线程模型,资源开销更小,启动更快
-
Oracle:多进程模型,每个功能模块是独立进程,隔离性更好但资源消耗更大
1.4 为什么会出现达梦?
简单说三个原因:
-
安全合规:金融、党政、军工等领域要求数据库必须自主可控,不能依赖国外产品
-
成本:Oracle的授权费用极高(企业版按CPU核心收费,一套下来几百万很正常),达梦的授权成本通常只有Oracle的1/3~1/5
-
本地化服务:原厂中文技术支持,响应速度远快于国外厂商
二、安装部署:手把手教你搭一个DM8环境
2.1 环境要求
| 项目 | 最低要求 | 推荐配置(生产环境) |
|---|---|---|
| CPU | x86_64,2核以上 | 4核以上 |
| 内存 | 2GB | 16GB+ |
| 磁盘 | 10GB(安装+基础数据) | SSD,500GB+ |
| 操作系统 | CentOS 7+/RedHat 7+/Ubuntu 16.04+ / Windows Server 2012+ / 麒麟V10 / 统信UOS | 同左 |
2.2 Linux 安装步骤(CentOS 为例)
# ========== 第一步:创建专用用户 ========== groupadd dinstall useradd -g dinstall -m -d /home/dmdba -s /bin/bash dmdba echo "dmdba:Dameng@123" | chpasswd mkdir -p /dm8 chown -R dmdba:dinstall /dm8 chmod -R 755 /dm8 # ========== 第二步:上传并挂载安装包 ========== mount -o loop /path/to/dm8_xxx.iso /mnt # ========== 第三步:执行安装 ========== su - dmdba cd /mnt ./DMInstall.bin -i # 交互式命令行安装 # 或图形化方式:./DMInstall.bin (需要 X Window/VNC) # 安装过程中关键选择: # 1. 语言:中文 # 2. 类型:典型安装(Typical) # 3. 路径:/dm8/DAMENG
# ========== 第四步:初始化数据库实例 ========== cd /dm8/DAMENG/bin ./dminit \ PATH=/dm8/DAMENG/data \ DB_NAME=DAMENG \ INSTANCE_NAME=DMSERVER \ PORT_NUM=5236 \ PAGE_SIZE=16 \ # 页大小:8/16/32 CHARSET=1 \ # 0=GB18030, 1=UTF-8, 2=EUC-KR CASE_SENSITIVE=Y # 大小写敏感
# ========== 第五步:注册服务并启动 ========== # 切换 root 执行 /dm8/DAMENG/script/root/dm_service_installer.sh \ -t dmserver \ -i /dm8/DAMENG/data/DAMENG/dm.ini \ -p DMSERVER systemctl start DmServiceDMSERVER systemctl status DmServiceDMSERVER
# ========== 第六步:连接验证 ========== /dm8/DAMENG/bin/disql SYSDBA/SYSDBA # 看到 SQL> 提示符就说明成功了!
2.3 Windows 安装步骤
Windows 全程图形化向导:
-
解压
dm8_202xxxx_win64.zip→ 双击setup.exe -
选中文 → 接受协议 → 典型安装
-
指定路径(如
E:\dmdbms) -
安装完成后弹出"数据库配置助手",创建实例:
-
数据库名:
DAMENG,端口:5236,默认用户:SYSDBA/SYSDBA
-
-
开始菜单 → 打开 DM管理工具 或 disql 即可连接
2.4 安装后的目录结构速览
/dm8/DAMENG/ ├── bin/ │ ├── disql # 命令行工具(类似 sqlplus) │ ├── dmservice.sh # 服务管理 │ ├── dbca.sh # 数据库配置助手 │ └── dmrman # 备份恢复工具 ├── data/DAMENG/ │ ├── dm.ini # ★ 主配置文件(非常重要!) │ ├── SYSTEM.DBF # 系统表空间 │ ├── MAIN.DBF # 用户表空间 │ └── TEMP.DBF # 临时表空间 ├── drivers/jdbc/ │ └── DmJdbcDriver18.jar # JDBC驱动包(Java连接用!) └── tools/manager/ # DM管理器(类似 SQL Developer)
三、SQL 实战:从建库到 CRUD 全流程
3.1 DM8 数据类型速查表
| 分类 | DM8 类型 | 对应 Oracle | 对应 MySQL | 说明 |
|---|---|---|---|---|
| 整数 | INT |
NUMBER(10) |
INT |
4字节,±21亿 |
| 整数 | BIGINT |
NUMBER(19) |
BIGINT |
8字节 |
| 高精度数值 | DECIMAL(M,D) |
NUMBER(M,D) |
DECIMAL(M,D) |
如 DECIMAL(10,2) |
| 浮点数 | DOUBLE |
BINARY_DOUBLE |
DOUBLE |
双精度浮点 |
| 字符串定长 | CHAR(N) |
CHAR(N) |
CHAR(N) |
最大8188字节 |
| 字符串变长 | VARCHAR(N) |
VARCHAR2(N) |
VARCHAR(N) |
最大32767字节 |
| 大文本 | TEXT/CLOB |
CLOB |
LONGTEXT |
最大2GB |
| 二进制大对象 | BLOB |
BLOB |
LONGBLOB |
最大2GB |
| 日期时间 | DATE |
DATE |
DATETIME |
包含年月日时分秒 |
| 时间戳 | TIMESTAMP |
TIMESTAMP |
TIMESTAMP |
更高精度 |
| 布尔 | BIT |
无(用NUMBER(1)) | BOOLEAN |
0或1 |
⚠️ 注意:DM8 的
DATE类型包含时分秒(不同于 Oracle 的 DATE 只有年月日),这点更像 MySQL 的 DATETIME。
3.2 创建用户和表空间
-- ============================================= -- 以 SYSDBA 身份登录后执行 -- ============================================= -- 查看数据库状态和版本 SELECT status$ AS 状态 FROM v$instance; SELECT banner AS 版本 FROM v$version; -- ---------- 创建表空间 ---------- CREATE TABLESPACE app_tbs DATAFILE '/dm8/DAMENG/data/DAMENG/app_tbs.dbf' SIZE 128 AUTOEXTEND ON NEXT 32 MAXSIZE 10240; -- ---------- 创建用户 ---------- CREATE USER app_user IDENTIFIED BY "App@2026" DEFAULT TABLESPACE app_tbs; -- 授予权限 GRANT RESOURCE TO app_user; GRANT CREATE VIEW TO app_user; GRANT CREATE PROCEDURE TO app_user;
3.3 建表实战:电商订单系统
下面用一个完整的电商场景演示 DM8 的完整操作:
-- ============================================= -- 以下 SQL 以 app_user 身份执行 -- ============================================= -- ---------- 1. 商品分类表 ---------- CREATE TABLE product_category ( category_id INT IDENTITY(1,1) PRIMARY KEY, category_name VARCHAR(50) NOT NULL, parent_id INT DEFAULT 0, sort_order INT DEFAULT 0, status TINYINT DEFAULT 1, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- ---------- 2. 商品表 ---------- CREATE TABLE product ( product_id INT IDENTITY(1,1) PRIMARY KEY, category_id INT NOT NULL, product_name VARCHAR(200) NOT NULL, product_desc TEXT, price DECIMAL(10,2) NOT NULL, stock_qty INT DEFAULT 0, sales_count INT DEFAULT 0, status TINYINT DEFAULT 1, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP, CONSTRAINT fk_product_category FOREIGN KEY (category_id) REFERENCES product_category(category_id) ); -- 创建索引 CREATE INDEX idx_product_category ON product(category_id); CREATE INDEX idx_product_price ON product(price); -- ---------- 3. 用户表 ---------- CREATE TABLE users ( user_id INT IDENTITY(1,1) PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, email VARCHAR(100), phone VARCHAR(20), password_hash VARCHAR(256) NOT NULL, register_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, last_login TIMESTAMP, status TINYINT DEFAULT 1 ); CREATE UNIQUE INDEX idx_users_phone ON users(phone); -- ---------- 4. 订单表 ---------- CREATE TABLE orders ( order_id BIGINT IDENTITY(1,1) PRIMARY KEY, order_no VARCHAR(32) NOT NULL UNIQUE, user_id INT NOT NULL, total_amount DECIMAL(12,2) NOT NULL, pay_amount DECIMAL(12,2), order_status INT DEFAULT 0, pay_time TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_orders_user FOREIGN KEY (user_id) REFERENCES users(user_id) ); -- ---------- 5. 订单明细表 ---------- CREATE TABLE order_item ( item_id BIGINT IDENTITY(1,1) PRIMARY KEY, order_id BIGINT NOT NULL, product_id INT NOT NULL, product_name VARCHAR(200) NOT NULL, product_price DECIMAL(10,2) NOT NULL, quantity INT NOT NULL CHECK(quantity > 0), subtotal DECIMAL(12,2) NOT NULL, CONSTRAINT fk_item_order FOREIGN KEY (order_id) REFERENCES orders(order_id) ); CREATE INDEX idx_orderitem_order ON order_item(order_id);
3.4 插入数据
-- 插入分类
INSERT INTO product_category (category_name, parent_id, sort_order) VALUES
('电子产品', 0, 1), ('手机', 1, 1), ('电脑', 1, 2),
('服装', 0, 2), ('男装', 4, 1), ('女装', 4, 2);
-- 插入商品
INSERT INTO product (category_id, product_name, price, stock_qty) VALUES
(2, '华为Mate60 Pro', 6999.00, 500),
(2, 'iPhone 15 Pro Max', 9999.00, 300),
(3, 'MacBook Pro 14 M3', 16999.00, 80),
(5, '优衣库纯棉T恤', 79.00, 2000);
-- 插入用户
INSERT INTO users (username, phone, password_hash) VALUES
('zhangsan', '13800138001', 'sha256_abc123'),
('lisi', '13800138002', 'sha256_def456');
-- 插入订单
INSERT INTO orders (order_no, user_id, total_amount, pay_amount, order_status) VALUES
('ORD20260627001', 1, 13998.00, 13998.00, 3),
('ORD20260627002', 2, 16999.00, 15499.00, 2);
3.5 查询数据(SELECT 实战)
-- ---------- 基础查询与分页 ---------- SELECT TOP 10 * FROM product WHERE status = 1 ORDER BY sales_count DESC; -- 或者 MySQL 风格的分页: SELECT * FROM product ORDER BY product_id LIMIT 0, 10; -- 模糊搜索 SELECT * FROM product WHERE product_name LIKE '%iPhone%'; -- ---------- 聚合统计 ---------- SELECT c.category_name, COUNT(p.product_id) AS 商品数量, AVG(p.price) AS 平均价格, SUM(p.stock_qty) AS 总库存 FROM product_category c LEFT JOIN product p ON c.category_id = p.category_id GROUP BY c.category_id, c.category_name HAVING COUNT(p.product_id) > 0; -- ---------- 多表关联查询:订单详情 ---------- SELECT o.order_no AS 订单号, u.username AS 用户名, o.total_amount AS 订单总额, o.pay_amount AS 实付金额, o.order_status AS 状态, oi.product_name AS 商品名, oi.product_price AS 单价, oi.quantity AS 数量, oi.subtotal AS 小计 FROM orders o INNER JOIN users u ON o.user_id = u.user_id INNER JOIN order_item oi ON o.order_id = oi.order_id WHERE o.order_status >= 1 ORDER BY o.created_at DESC; -- ---------- 窗口函数(DM8 支持) ---------- -- 每个分类下价格排名前2的商品 SELECT * FROM ( SELECT product_name, price, category_name, ROW_NUMBER() OVER(PARTITION BY c.category_id ORDER BY p.price DESC) AS rn FROM product p JOIN product_category c ON p.category_id = c.category_id ) t WHERE rn <= 2; -- ---------- 子查询 + EXISTS ---------- -- 查询有订单的用户 SELECT username, email, register_time FROM users u WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.user_id AND o.order_status = 3);
3.6 更新和删除
-- ---------- UPDATE ---------- -- 更新商品价格和库存 UPDATE product SET price = 6499.00, updated_at = CURRENT_TIMESTAMP WHERE product_id = 1; -- 批量更新:某分类商品全部涨价5% UPDATE product SET price = price * 1.05, updated_at = CURRENT_TIMESTAMP WHERE category_id = 2; -- ---------- DELETE ---------- -- 删除已取消超过30天的订单 DELETE FROM orders WHERE order_status = 4 AND created_at < DATEADD(DAY, -30, CURRENT_TIMESTAMP); -- 清空表(保留结构,更快) TRUNCATE TABLE order_item;
3.7 存储过程实战
-- ---------- 存储过程1:批量插入测试数据 ----------
CREATE OR REPLACE PROCEDURE sp_gen_test_data(
p_count IN INT -- 生成条数
) AS
v_i INT;
v_product_name VARCHAR(200);
BEGIN
FOR v_i IN 1..p_count LOOP
v_product_name := '测试商品_' || v_i;
INSERT INTO product (category_id, product_name, price, stock_qty)
VALUES (2, v_product_name, ROUND(DBMS_RANDOM.VALUE(100, 10000), 2), FLOOR(DBMS_RANDOM.VALUE(1, 500)));
-- 每1000条提交一次,避免日志过大
IF MOD(v_i, 1000) = 0 THEN
COMMIT;
PRINT('已插入 ' || v_i || ' 条');
END IF;
END LOOP;
COMMIT;
PRINT('完成!共插入 ' || p_count || ' 条数据');
END;
-- 调用
CALL sp_gen_test_data(5000);
-- ---------- 存储过程2:根据员工ID查询部门(带输出参数) ----------
CREATE OR REPLACE PROCEDURE sp_get_user_order_stats(
p_user_id IN INT,
p_total OUT DECIMAL, -- 输出:总消费金额
p_order_cnt OUT INT -- 输出:订单数量
) AS
BEGIN
SELECT SUM(total_amount), COUNT(*)
INTO p_total, p_order_cnt
FROM orders
WHERE user_id = p_user_id AND order_status >= 1;
END;
-- 调用(需要用匿名块接收输出参数)
DECLARE
v_total DECIMAL(12,2);
v_cnt INT;
BEGIN
sp_get_user_order_stats(1, v_total, v_cnt);
PRINT('总消费: ' || v_total || ', 订单数: ' || v_cnt);
END;
-- ---------- 存储过程3:带异常处理 ----------
CREATE OR REPLACE PROCEDURE sp_safe_update_price(
p_product_id IN INT,
p_new_price IN DECIMAL
) AS
v_old_price DECIMAL(10,2);
BEGIN
-- 先查旧价
SELECT price INTO v_old_price FROM product WHERE product_id = p_product_id;
IF v_old_price IS NULL THEN
RAISE EXCEPTION '-20001', '商品不存在';
ELSIF p_new_price <= 0 THEN
RAISE EXCEPTION '-20002', '价格必须大于0';
ELSE
UPDATE product SET price = p_new_price, updated_at = CURRENT_TIMESTAMP
WHERE product_id = p_product_id;
PRINT('更新成功: ' || v_old_price || ' -> ' || p_new_price);
END IF;
EXCEPTION
WHEN OTHERS THEN
PRINT('错误: ' || SQLCODE || ' - ' || SQLERRM);
END;
3.8 触发器实战
-- ---------- 场景:订单状态变更时自动记录审计日志 ---------- -- 先建审计日志表 CREATE TABLE order_audit_log ( log_id BIGINT IDENTITY(1,1) PRIMARY KEY, order_id BIGINT NOT NULL, old_status INT, new_status INT, changed_by VARCHAR(50) DEFAULT 'SYSTEM', change_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, remark VARCHAR(500) ); -- 创建触发器:订单状态变更时自动记录 CREATE OR REPLACE TRIGGER trg_order_status_audit AFTER UPDATE OF order_status ON orders FOR EACH ROW DECLARE v_status_map VARCHAR(100); BEGIN -- 记录变更前后状态 INSERT INTO order_audit_log (order_id, old_status, new_status, remark) VALUES ( :OLD.order_id, :OLD.order_status, :NEW.order_status, '订单 ' || :OLD.order_no || ' 状态变更' ); -- 如果变为"已完成",自动更新商品的销量 IF :NEW.order_status = 3 AND :OLD.order_status != 3 THEN UPDATE product p SET sales_count = sales_count + ( SELECT COALESCE(SUM(oi.quantity), 0) FROM order_item oi WHERE oi.order_id = :NEW.order_id AND oi.product_id = p.product_id ) WHERE p.product_id IN (SELECT product_id FROM order_item WHERE order_id = :NEW.order_id); END IF; END; -- 测试触发器 UPDATE orders SET order_status = 3 WHERE order_id = 1; -- 查看 audit log 是否自动插入了记录 SELECT * FROM order_audit_log ORDER BY log_id DESC;
四、Java/JDBC 连接达梦数据库
4.1 准备工作
-
从达梦安装目录获取驱动包:
drivers/jdbc/DmJdbcDriver18.jar -
在项目中引入该 jar 包(Maven 项目可手动 install 到本地仓库)
<!-- pom.xml 中添加(需先将jar安装到本地Maven仓库) --> <dependency> <groupId>com.dameng</groupId> <artifactId>DmJdbcDriver18</artifactId> <version>8.1.2.138</version> </dependency>
4.2 基础 JDBC 连接代码
package com.example.dm;
import java.sql.*;
/**
* 达梦数据库 JDBC 连接示例
* 驱动类:dm.jdbc.driver.DmDriver
* 连接串格式:jdbc:dm://主机:端口
*/
public class DmJdbcDemo {
// 数据库连接信息
private static final String DRIVER = "dm.jdbc.driver.DmDriver";
private static final String URL = "jdbc:dm://192.168.1.100:5236";
private static final String USER = "app_user";
private static final String PASSWORD = "App@2026";
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 1. 加载驱动
Class.forName(DRIVER);
// 2. 建立连接
conn = DriverManager.getConnection(URL, USER, PASSWORD);
System.out.println("[OK] 连接成功!");
// 3. 执行查询
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT product_id, product_name, price FROM product");
// 4. 处理结果集
while (rs.next()) {
int id = rs.getInt("product_id");
String name = rs.getString("product_name");
double price = rs.getDouble("price");
System.out.printf("%d | %s | %.2f%n", id, name, price);
}
// 5. 执行插入(使用 PreparedStatement 防注入)
String insertSql = "INSERT INTO product (category_id, product_name, price, stock_qty) "
+ "VALUES (?, ?, ?, ?)";
try (PreparedStatement ps = conn.prepareStatement(insertSql)) {
ps.setInt(1, 2); // category_id
ps.setString(2, "小米15 Ultra"); // product_name
ps.setDouble(3, 5999.00); // price
ps.setInt(4, 200); // stock_qty
int rows = ps.executeUpdate();
System.out.println("[OK] 插入 " + rows + " 行");
}
// 6. 事务控制示例
try {
conn.setAutoCommit(false); // 开启手动事务
// 下单操作:扣库存 + 创建订单
Statement txStmt = conn.createStatement();
txStmt.executeUpdate("UPDATE product SET stock_qty = stock_qty - 1 WHERE product_id = 1");
txStmt.executeUpdate("INSERT INTO orders (order_no, user_id, total_amount, order_status) "
+ "VALUES ('ORD_JDBC_001', 1, 6499.00, 1)");
conn.commit(); // 提交事务
System.out.println("[OK] 事务提交成功");
} catch (Exception e) {
conn.rollback(); // 出错回滚
System.err.println("[ERR] 事务回滚: " + e.getMessage());
}
} catch (ClassNotFoundException e) {
System.err.println("[ERR] 驱动未找到: " + e.getMessage());
} catch (SQLException e) {
System.err.println("[ERR] SQL异常: " + e.getMessage());
} finally {
// 7. 关闭资源(按逆序关闭)
if (rs != null) try { rs.close(); } catch (SQLException ignored) {}
if (stmt != null) try { stmt.close(); } catch (SQLException ignored) {}
if (conn != null) try { conn.close(); } catch (SQLException ignored) {}
}
}
}
4.3 HikariCP 连接池配置
生产环境必须用连接池。以下是 Spring Boot + HikariCP 配置:
# application.yml spring: datasource: driver-class-name: dm.jdbc.driver.DmDriver url: jdbc:dm://192.168.1.100:5236?SCHEMA=APP_USER&loginMode=1 username: app_user password: App@2026 hikari: maximum-pool-size: 20 minimum-idle: 5 connection-timeout: 30000 idle-timeout: 600000 max-lifetime: 1800000
4.4 MyBatis 映射示例
<!-- ProductMapper.xml -->
<mapper namespace="com.example.mapper.ProductMapper">
<!-- 结果映射 -->
<resultMap id="BaseResultMap" type="com.example.entity.Product">
<id column="product_id" property="productId"/>
<result column="product_name" property="productName"/>
<result column="price" property="price"/>
<result column="stock_qty" property="stockQty"/>
<result column="sales_count" property="salesCount"/>
<result column="status" property="status"/>
<result column="created_at" property="createdAt"/>
</resultMap>
<!-- 分页查询 -->
<select id="selectByPage" resultMap="BaseResultMap">
SELECT * FROM product
WHERE status = 1
<if test="keyword != null and keyword != ''">
AND product_name LIKE CONCAT('%', #{keyword}, '%')
</if>
<if test="categoryId != null">
AND category_id = #{categoryId}
</if>
ORDER BY product_id
</select>
<!-- 批量插入 -->
<insert id="batchInsert">
INSERT INTO product (category_id, product_name, price, stock_qty)
VALUES
<foreach collection="list" item="item" separator=",">
(#{item.categoryId}, #{item.productName}, #{item.price}, #{item.stockQty})
</foreach>
</insert>
</mapper>
五、Python 连接达梦数据库
5.1 方式一:通过 JayDeBeApi(JDBC桥接)
"""
Python 通过 JDBC 连接达梦数据库
依赖:pip install JayDeBeApi Jpype1
"""
import jaydebeapi
import pandas as pd
# ======== 配置 ========
DM_HOST = "192.168.1.100"
DM_PORT = "5236"
DM_USER = "app_user"
DM_PASS = "App@2026"
JDBC_JAR = "/path/to/DmJdbcDriver18.jar" # 改为你的实际路径
def get_connection():
"""建立数据库连接"""
url = f"jdbc:dm://{DM_HOST}:{DM_PORT}"
driver = "dm.jdbc.driver.DmDriver"
conn = jaydebeapi.connect(
driver,
url,
[DM_USER, DM_PASS],
JDBC_JAR
)
return conn
def query_to_dataframe(sql: str) -> pd.DataFrame:
"""执行查询并返回 DataFrame"""
conn = get_connection()
try:
df = pd.read_sql(sql, conn)
return df
finally:
conn.close()
def execute_sql(sql: str):
"""执行增删改操作"""
conn = get_connection()
cursor = conn.cursor()
try:
rows = cursor.execute(sql)
conn.commit()
print(f"[OK] 影响 {rows} 行")
except Exception as e:
conn.rollback()
print(f"[ERR] {e}")
raise
finally:
cursor.close()
conn.close()
# ======== 使用示例 ========
if __name__ == "__main__":
# 查询所有商品
df = query_to_dataframe("""
SELECT product_id, product_name, price, stock_qty
FROM product WHERE status = 1
""")
print(df.head())
print(f"共 {len(df)} 条记录")
# 统计各分类商品数
stats = query_to_dataframe("""
SELECT c.category_name, COUNT(p.product_id) AS cnt
FROM product_category c
LEFT JOIN product p ON c.category_id = p.category_id
GROUP BY c.category_name
""")
print("\n分类统计:")
print(stats)
5.2 方式二:通过 SQLAlchemy(如果可用)
"""
注意:达梦没有官方的 Python DB-API 2.0 驱动,
目前最稳定的方式是通过 JayDeBeApi 做 JDBC 桥接。
如果项目使用了 Django/SQLAlchemy,可以封装一个自定义方言。
"""
from sqlalchemy import create_engine, text
# 使用 JayDeBeApi 的 SQLAlchemy URI 格式
engine = create_engine(
"dm+jaydebeapi://app_user:App@2026@192.168.1.100:5236/DAMENG",
connect_args={
"jar_path": "/path/to/DmJdbcDriver18.jar"
}
)
with engine.connect() as conn:
result = conn.execute(text("SELECT COUNT(*) FROM product"))
count = result.scalar()
print(f"商品总数: {count}")
六、达梦 vs Oracle vs MySQL 核心语法差异对照
这是实际迁移中最常碰到的问题,建议收藏:
| 操作 | Oracle | MySQL | 达梦 DM8 | 备注 |
|---|---|---|---|---|
| 自增主键 | SEQUENCE + TRIGGER | AUTO_INCREMENT |
IDENTITY(1,1) ✅ |
DM8 用 IDENTITY 最方便 |
| 分页 | ROWNUM / FETCH FIRST |
LIMIT offset,count |
TOP N 或 LIMIT |
三种都支持 LIMIT |
| 字符串拼接 | \|\| 或 CONCAT() |
CONCAT() |
\|\| 和 CONCAT() 都行 |
兼容 Oracle |
| 当前时间 | SYSDATE |
NOW() |
SYSDATE 和 CURRENT_TIMESTAMP |
兼容 Oracle |
| 序列 | CREATE SEQUENCE ... |
无(用AUTO_INCREMENT) | CREATE SEQUENCE ... ✅ |
完整兼容 Oracle 序列 |
| 匿名块 | BEGIN...END; |
不支持 | BEGIN...END; ✅ |
支持 PL/SQL 风格 |
| 存储过程 | CREATE PROCEDURE |
CREATE PROCEDURE |
CREATE OR REPLACE PROCEDURE ✅ |
语法几乎一致 |
| 触发器 | CREATE TRIGGER |
CREATE TRIGGER |
CREATE TRIGGER ✅ |
支持 BEFORE/AFTER/FOR EACH ROW |
| 窗口函数 | 完整支持 | 8.0+支持 | 完整支持 ✅ | ROW_NUMBER/RANK/DENSE_RANK 都有 |
| 递归CTE | WITH RECURSIVE |
8.0+ WITH | WITH ... AS 递归 ✅ |
支持 |
| JSON | 自带JSON函数 | JSON函数丰富 | 需装扩展包或用 dm_json_* 函数 |
相对较弱 |
| 日期加减 | date + num / ADD_MONTHS |
DATE_ADD() |
DATEADD() / 直接加减数字 |
注意函数名不同 |
| NVL空值处理 | NVL(), NVL2() |
IFNULL(), COALESCE() |
NVL(), COALESCE(), NULLIF() ✅ |
兼容 Oracle |
| DECODE函数 | DECODE() |
CASE WHEN | DECODE() ✅ |
DM8 特有兼容 |
| 序列取值 | NEXTVAL, CURRVAL |
NEXTVAL |
NEXTVAL, CURRVAL ✅ |
完全一致 |
| 双引号标识符 | "COLUMN" |
`COLUMN` |
"COLUMN" ✅ |
兼容 Oracle 风格 |
| 注释 | COMMENT ON |
ALTER TABLE ... COMMENT |
COMMENT ON ✅ |
兼容 Oracle |
迁移建议:如果你的系统原来跑在 Oracle 上,迁移到达梦的成本主要在自定义存储过程和复杂SQL语句的适配上。90%以上的标准SQL可以直接跑通。
七、达梦能干什么?典型应用场景
7.1 金融行业(核心交易系统)
银行核心账务系统 ├── 账户管理(储蓄、贷款、信用卡) ├── 交易流水(每秒数千笔 TPS) ├── 对账清算(日终批处理) └── 高可用要求:同城双活 + 异地灾备 → 技术选型:DM8 + DMDSC 共享存储集群 → 关键指标:故障切换 ≤ 14秒(同城)/ ≤ 32秒(异地) → 兼容性:原有 Oracle 存储过程大部分可直接迁移
7.2 电力/能源行业(SCADA数据采集)
智能电网调度系统 ├── 实时数据采集(每秒百万级测点) ├── 历史数据存储(PB级时序数据) ├── 报警与事件管理 └── 数据分析与报表 → 技术选型:DM8(OLTP)+ DM MPP(OLAP)混合架构 → 优势:列式存储加速分析查询,分布式并行处理
7.3 党政机关(OA/政务系统)
政务服务平台 ├── 用户认证与权限管理 ├── 业务办理(审批、办件) ├── 数据共享交换 └── 安全合规(等保四级认证) → 技术选型:标准 DM8 单实例或主备集群 → 优势:自主可控、安全认证齐全、本地化服务
7.4 电商/互联网业务
电商交易平台 ├── 商品管理与搜索 ├── 订单与支付 ├── 库存管理 ├── 用户中心 └── 数据分析(BI报表) → 技术选型:DM8 + 应用层缓存(Redis) → 适用规模:中小型电商平台(日订单万级~十万级) → 注意:超大规模互联网应用建议评估云原生方案
八、运维常用命令速查
-- ============================================= -- 以下为 DBA 日常运维常用 SQL -- ============================================= -- ---------- 查看实例信息 ---------- SELECT * FROM v$instance; -- 实例基本信息 SELECT * FROM v$version; -- 版本信息 SELECT name, status$, total_size, free_size FROM v$tablespace; -- 表空间使用情况 -- ---------- 查看会话和锁 ---------- SELECT * FROM v$sessions WHERE state='ACTIVE'; -- 当前活跃会话 SELECT * FROM v$trxwait; -- 等待事务 SELECT * FROM v$locks; -- 锁信息 -- ---------- 手动杀掉死锁会话 ---------- -- 先找到阻塞会话的 sess_id SELECT s.sess_id, s.sql_text, s.state, s.clnt_ip FROM v$sessions s JOIN v$trxwait w ON s.trxid = w.wait_trxid; -- 杀掉会话(替换实际的sess_id) SP_CLOSE_SESSION(123456789); -- ---------- 表空间扩容 ---------- -- 方式1:修改数据文件大小 ALTER TABLESPACE MAIN ADD DATAFILE '/dm8/DAMENG/data/DAMENG/MAIN_01.DBF' SIZE 1024 AUTOEXTEND ON NEXT 128 MAXSIZE 10240; -- 方式2:resize已有数据文件 ALTER DATABASE RESIZE DATAFILE '/dm8/DAMENG/data/DAMENG/MAIN.DBF' TO 2048; -- ---------- 用户管理 ---------- ALTER USER app_user IDENTIFIED BY "NewPassword@2026"; -- 修改密码 LOCK USER app_user; -- 锁定用户 UNLOCK USER app_user; -- 解锁用户 -- ---------- 备份与恢复 ---------- -- 全量备份(物理备份,需要在 disql 或 dmrman 中执行) BACKUP DATABASE FULL TO "full_bak_20260627" BACKUPSET '/dm8/backup/full_bak_20260627'; -- 增量备份 BACKUP DATABASE INCREMENT TO "inc_bak_20260627" BACKUPSET '/dm8/backup/inc_bak_20260627'; -- 恿复(在 dmrman 工具中执行) RESTORE DATABASE FROM BACKUPSET '/dm8/backup/full_bak_20260627'; -- ---------- 性能查看 ---------- -- 查看Top 10 慢SQL SELECT * FROM ( SELECT sql_text, executions, elapsed_time / executions AS avg_time, rows_processed FROM v$sqlstat WHERE executions > 0 ORDER BY elapsed_time DESC ) WHERE ROWNUM <= 10; -- 查看表的大小 SELECT table_name, (SELECT COUNT(*) FROM user_indexes i WHERE i.table_name = t.table_name) AS index_count FROM user_tables t ORDER BY table_name;
九、从零上手的学习路线图
如果你是第一次接触达梦数据库,推荐按以下顺序学习:
第1周:基础入门 ├─ Day 1-2:安装 DM8(Linux 或 Windows),熟悉 disql 命令行工具 ├─ Day 3-4:学习本文章第三节的 SQL CRUD 操作 └─ Day 5-7:完成一个小练习(如建一个学生成绩管理系统) 第2周:进阶操作 ├─ 学习存储过程和触发器(第三节 3.7-3.8) ├─ 学习索引优化和执行计划分析 └─ 尝试用 Java/Python 连接数据库(第四、五节) 第3周:运维与管理 ├─ 学习备份恢复策略 ├─ 了解 DMDSC 集群原理 └─ 学习性能调优方法 第4周:实战迁移 ├─ 把一个已有的 MySQL 小项目迁移到 DM8 ├─ 解决迁移过程中的语法差异问题 └─ 编写自动化迁移脚本
达梦数据库不是什么神秘的东西——它就是一个功能完整的、兼容Oracle语法的、中国人自己写的关系型数据库。
如果你已经会用 MySQL 或 Oracle,那么上手 DM8 的学习曲线大概就是 2-3天能跑起来,1-2周能熟练使用,1个月能独立完成中小项目的开发和运维。
真正有价值的不是记住每一个SQL语法,而是理解什么时候该用达梦、怎么用好达梦:
-
需要自主可控 → 达梦是首选之一
-
从Oracle迁移 → 迁移成本最低的国产数据库
-
金融/电力/党政 → 达梦在这些领域有大量成熟案例
-
全新互联网项目 → 可以考虑,但也要评估社区生态和云原生能力
希望这篇技术指南能帮你快速迈出第一步。最好的学习方法永远是动手——打开终端,敲下第一条 SQL,让数据在你的屏幕上流动起来。
本文所有代码基于 DM8 V8.1.x 版本实测编写,不同版本可能存在细微差异。如有疑问请参考达梦官方文档《DM8_SQL语言手册》。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)