DM 数据库的 Python 接口 dmPython,包括了 dmPython 的安装、dmPython 接口与一些使用案例。
dmPython 是达梦数据库官方提供的 Python 编程接口,是 Python 应用访问 DM 数据库的推荐方式。使用 dmPython,开发人员可以在 Python 程序中完成连接数据库、执行 SQL 语句、处理结果集、调用存储过程、操作大对象等数据库开发工作。
dmPython 遵循 Python 数据库 API 规范 2.0(PEP 249),符合该规范的应用可以以极低的成本从其他数据库迁移到达梦数据库。
dmPython 采用"Python 模块 + DPI 动态库"的两层结构:
┌─────────────────────┐
│ Python 应用程序 │
├─────────────────────┤
│ dmPython(模块) │ ← Python 层,遵循 DB-API 2.0
├─────────────────────┤
│ DPI 动态库 │ ← libdmdpi.so(Linux)/ libdmdpi.dll(Windows)
├─────────────────────┤
│ DM 数据库服务器 │ ← 默认端口 5236
└─────────────────────┘
dmPython 模块本身不直接实现网络协议,而是调用达梦通用的 DPI(DM Programming Interface)动态库与数据库通信。因此:
apilevel = '2.0';qmark(问号 ?)风格的参数占位符;executemany)、存储过程调用;dmPython 可以运行在任何安装了 Python 的平台上。安装前请确认下表所述的环境要求:
| 项目 | 要求 |
|---|---|
| 操作系统 | Windows / Linux(x86_64、ARM 等主流架构) |
| Python | 2.7 或 3.x 均可,建议 3.6 及以上版本 |
| setuptools | Python 版本 ≥ 3.12 时,必须确保 Python 同时安装了 setuptools 库 |
| DM 软件 | 已安装达梦数据库,或已获取达梦驱动压缩包(用于提供 DPI 动态库与 dmPython 源码) |
| 编译环境 | 源码安装时需要:Linux 下 gcc 与 python3-devel(python3-dev);Windows 下 Visual Studio Build Tools |
Python 软件请用户自行前往 Python 官网下载。安装任何一个版本 Python 均可。如果 Python 版本大于等于 3.12,请务必确保 Python 同时安装了 setuptools 库:
pip install setuptools
安装时注意事项:
成功安装 Python 之后,可查看 Python 版本号:
# Windows
python --version
# Linux
python3 --version
提示:一台机器上可能同时存在多个 Python 版本。后续安装 dmPython 时,请务必使用与运行应用相同的那个解释器(例如统一使用
python3 -m pip install .),否则会出现 "No module named dmPython" 的问题(见第 6 章 FAQ)。
第一步,安装达梦数据库或者下载达梦驱动压缩包。
方式一:安装达梦数据库,具体的安装步骤可参考《DM8 安装手册》。安装完成后,dmPython 源码位于 DM 安装目录 dmdbms/drivers/python/dmPython 中(Windows 下形如 C:\dmdbms\drivers\python\dmPython,Linux 下形如 /dm/dmdbms/drivers/python/dmPython)。
方式二:从达梦官方技术服务网站下载对应平台、对应数据库版本的驱动压缩包,解压后同样可得到 drivers/python/dmPython 源码目录及 DPI 动态库。
提示:部分版本的驱动包中,
drivers/python目录下按 Python 版本细分为多个子目录(并可能提供预编译的 whl 文件),请选择与当前 Python 版本匹配的目录。
dmPython 的运行需要使用 DPI 动态库。因此用户需提前配置好环境变量,使用环境变量指定 DPI 的位置。
Linux 环境下,用户须手动将 DPI 动态库所在目录(即 DM 安装目录中的 BIN 目录,或者 drivers 目录中的 dpi 目录)加入到 LD_LIBRARY_PATH 环境变量中,并设置环境变量 DM_HOME 等于 DM 安装目录或者 drivers 目录。
# 方式一:数据库安装目录的 bin 目录(推荐)
export DM_HOME=/dm/dmdbms
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$DM_HOME/bin
# 方式二:仅使用驱动包时,指向 drivers 下的 dpi 目录
export DM_HOME=/dm8/drivers
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/dm8/drivers/dpi
若希望重启后仍然生效,可将上述命令写入 /etc/profile(所有用户生效)或 ~/.bash_profile(当前用户生效),然后执行 source 使其立即生效:
echo 'export DM_HOME=/dm/dmdbms' >> ~/.bash_profile
echo 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$DM_HOME/bin' >> ~/.bash_profile
source ~/.bash_profile
配置完成后可验证 DPI 动态库是否存在:
ls -l $DM_HOME/bin/libdmdpi.so
Windows 环境下,将 DM 安装目录的 bin 目录(其中包含 DPI 动态库 libdmdpi.dll)加入系统 PATH 环境变量,并新建 DM_HOME 变量指向 DM 安装目录:
DM_HOME,变量值 C:\dmdbms;Path 中追加:%DM_HOME%\bin;命令行临时生效的方式:
set DM_HOME=C:\dmdbms
set PATH=%PATH%;%DM_HOME%\bin
dmPython 源码位于达梦安装目录 dmdbms\drivers\python\dmPython 中,安装程序为 setup.py。
进入到 setup.py 所在的源码目录,执行命令:
cd /dm/dmdbms/drivers/python/dmPython
# 方式一:传统安装(需要已配置好 DPI 环境变量)
python3 setup.py install
也可以使用 pip 进行安装(便于后续统一卸载、管理依赖,推荐):
# 方式二:pip 源码安装
python3 -m pip install .
# 方式三:若驱动包中提供了预编译 whl 文件,直接安装
python3 -m pip install dmPython-*.whl
卸载方式:
python3 -m pip uninstall dmPython
注意:
- 安装前请先完成 2.2 节的环境变量配置,并重新打开终端,否则安装程序找不到 DPI 动态库会报错
cannot locate an Dameng software installation;- 源码安装需要编译环境(Linux 需要 gcc 与 python3-devel;Windows 需要 VS Build Tools),若缺少编译环境请优先使用 whl 方式安装;
- Linux 下普通用户对 site-packages 无写权限时会报权限错误,处理方式见第 6 章 FAQ。
第一步,验证模块可正常导入:
python3 -c "import dmPython; print(dmPython.apilevel, dmPython.paramstyle)"
**第二步**,验证可正常连接数据库(数据库服务已启动,账号密码请按实际情况修改):
```bash
python3 -c "import dmPython; conn = dmPython.connect(user='SYSDBA', password='SYSDBA001', server='127.0.0.1', port=5236); print('连接成功'); conn.close()"
正常输出:
连接成功
两步均通过,说明 dmPython 安装成功。
新建 test_dmpython.py:
python3 test_dmpython.py
dmPython 遵循 DB-API 2.0 规范,接口分为三个层次:模块级接口(建立连接)、连接对象 Connection(管理连接与事务)、游标对象 Cursor(执行 SQL 与处理结果集)。
| 接口 / 属性 | 说明 |
|---|---|
dmPython.connect(...) |
创建数据库连接,返回 Connection 对象 |
dmPython.apilevel |
常量 '2.0',表示支持的 DB-API 版本 |
dmPython.threadsafety |
模块线程安全级别 |
dmPython.paramstyle |
常量 'qmark',参数占位符风格为 ? |
dmPython.STRING / BINARY / NUMBER / DATETIME / ROWID |
类型常量,用于与 description 中的列类型比较 |
dmPython.PG_UTF8 / dmPython.PG_GBK |
客户端编码常量,供 local_code 参数使用 |
dmPython.connect 常用参数:
| 参数 | 说明 | 默认值 |
|---|---|---|
user |
登录用户名 | 无,必填 |
password |
登录密码 | 无,必填 |
server |
数据库服务器 IP 或主机名 | localhost |
port |
数据库监听端口 | 5236 |
local_code |
客户端字符集编码,中文环境建议显式指定为 dmPython.PG_UTF8 |
与操作系统环境相关 |
login_timeout |
登录超时时间(秒) | 驱动默认值 |
dsn |
以连接串方式传入连接信息(与服务名方式二选一) | 无 |
其余连接属性(如通信加密、超时控制等)请以驱动源码目录中随附的官方文档为准。
示例:
conn = dmPython.connect(user='SYSDBA', password='SYSDBA001',
server='192.168.10.101', port=5236,
local_code=dmPython.PG_UTF8)
| 方法 | 说明 |
|---|---|
cursor() |
创建并返回一个游标对象 |
commit() |
提交当前事务 |
rollback() |
回滚当前事务 |
close() |
关闭连接,释放资源 |
事务说明:
INSERT / UPDATE / DELETE 后需要显式调用 commit(),否则连接关闭时未提交的修改将丢失;rollback() 回滚,可保证数据的原子性与一致性(用法见 5.4 节);close(),推荐使用 try...finally 保证资源释放。| 方法 / 属性 | 说明 |
|---|---|
execute(sql[, parameters]) |
执行一条 SQL 语句,占位符使用 ?,返回受影响行数(可由 rowcount 获取) |
executemany(sql, seq_of_parameters) |
批量执行同一条 SQL,参数为"参数元组"的序列,常用于批量增删改 |
fetchone() |
获取结果集下一行,无数据返回 None |
fetchmany(size) |
获取结果集下若干行 |
fetchall() |
获取结果集剩余全部行 |
description |
只读属性,结果集列描述信息(列名、类型等 7 元组组成的列表),仅 SELECT 后有效 |
rowcount |
只读属性,上一次 execute 影响(或返回)的行数 |
callproc(procname[, parameters]) |
调用存储过程 |
close() |
关闭游标 |
重要:dmPython 的
paramstyle为qmark,SQL 中使用?作为参数占位符(而不是%s):
cur.execute("select * from emp where dept_id = ? and salary > ?", (10, 5000))
dmPython 与 Python 3 内置类型之间的常用映射如下(完整映射见附录 A):
| DM 类型 | Python 写入类型 | Python 读取返回类型 |
|---|---|---|
| CHAR / VARCHAR / TEXT | str |
str |
| TINYINT / SMALLINT / INT / BIGINT | int |
int |
| DEC / DECIMAL / NUMERIC | decimal.Decimal |
decimal.Decimal |
| FLOAT / DOUBLE / REAL | float |
float |
| BIT | bool |
bool |
| DATE | datetime.date |
datetime.date |
| TIME | datetime.time |
datetime.time |
| TIMESTAMP | datetime.datetime |
datetime.datetime |
| BINARY / VARBINARY | bytes |
bytes |
| BLOB | bytes |
bytes |
| CLOB | str |
str |
dmPython 遵循 DB-API 2.0 的异常层次结构,可通过捕获相应异常进行错误处理:
Error
├── InterfaceError # 接口本身错误(如连接已关闭)
└── DatabaseError # 数据库相关错误
├── DataError # 数据处理错误(如数值溢出、除零)
├── OperationalError # 操作错误(如连接断开、网络异常)
├── IntegrityError # 完整性约束错误(如违反主键/唯一约束)
├── InternalError # 数据库内部错误
├── ProgrammingError # SQL 错误(如语法错误、表不存在)
└── NotSupportedError # 不支持的接口或操作
以下案例均假设已通过 4.1 节的方式建立连接 conn,并已创建游标 cur = conn.cursor()。
始终使用 ? 占位符绑定参数,不要用字符串拼接 SQL,既安全又能提升执行效率:
# 反例:存在 SQL 注入风险
# sql = "select * from emp where name = '" + name + "'"
# 正例:参数化查询
name = '张三'
cur.execute("select id, name, salary from emp where name = ?", (name,))
print(cur.fetchall())
# LIKE 模糊查询
cur.execute("select id, name from emp where name like ?", ('张%',))
print(cur.fetchall())
批量写入时应使用 executemany 代替循环 execute,可显著减少交互次数、提升性能:
data = [(i, '员工%03d' % i, 5000 + i) for i in range(1, 10001)]
cur.executemany("insert into emp(id, name, salary) values(?, ?, ?)", data)
conn.commit()
print('插入行数:', cur.rowcount)
性能建议:
executemany 而非逐条 execute;cur.execute("select id, name, salary from emp where dept_id = ? order by id", (10,))
# 逐行处理(推荐,内存占用小)
row = cur.fetchone()
while row:
emp_id, emp_name, salary = row
print(emp_id, emp_name, salary)
row = cur.fetchone()
# 一次性取回全部(结果集较大时慎用)
cur.execute("select count(*) from emp")
(total,) = cur.fetchone()
print('总行数:', total)
利用 commit / rollback 保证一组操作的原子性:
try:
cur.execute("update account set balance = balance - 100 where id = ?", (1,))
cur.execute("update account set balance = balance + 100 where id = ?", (2,))
conn.commit() # 两条同时成功,提交
print('转账成功')
except dmPython.DatabaseError as e:
conn.rollback() # 任一条失败,全部回滚
print('转账失败,已回滚:', e)
# 写入 BLOB:以二进制方式读取文件
with open('photo.jpg', 'rb') as f:
blob_data = f.read()
cur.execute("insert into t_file(id, content) values(?, ?)", (1, blob_data))
# 写入 CLOB:以文本方式读取文件
with open('readme.txt', 'r', encoding='utf-8') as f:
clob_data = f.read()
cur.execute("insert into t_doc(id, content) values(?, ?)", (1, clob_data))
conn.commit()
# 读取 BLOB
cur.execute("select content from t_file where id = ?", (1,))
(data,) = cur.fetchone()
with open('photo_copy.jpg', 'wb') as f:
f.write(data)
准备数据:
create table emp(id int primary key, salary numeric(10, 2));
insert into emp values(1, 5000);
commit;
create or replace procedure raise_salary(p_id int, p_raise numeric)
as
begin
update emp set salary = salary + p_raise where id = p_id;
commit;
end;
/
Python 中调用:
cur.callproc('RAISE_SALARY', (1, 1000))
# 验证结果
cur.execute("select salary from emp where id = ?", (1,))
print(cur.fetchone()) # 输出: (Decimal('6000'),)
说明:对于含 OUT 参数的存储过程,
callproc按照 DB-API 2.0 约定返回参数新值序列,不同驱动版本的实现细节略有差异,建议以随驱动文档为准;也可以改用"存储过程写入结果表 + SELECT 查询"的方式获取输出。
函数可以直接在 SELECT 语句中调用:
cur.execute("select my_func(?)", (1,))
dmPython 遵循 DB-API 2.0 规范,可作为 pandas 的数据源直接使用:
import pandas as pd
import dmPython
conn = dmPython.connect(user='SYSDBA', password='SYSDBA001',
server='127.0.0.1', port=5236)
df = pd.read_sql('select id, name, salary from emp', conn)
print(df.head())
conn.close()
将常用操作封装成工具类,便于工程化使用:
# -*- coding: utf-8 -*-
import dmPython
class DmDb:
"""dmPython 数据库操作简单封装"""
def __init__(self, host, port, user, password):
self.conn = dmPython.connect(server=host, port=port,
user=user, password=password,
local_code=dmPython.PG_UTF8)
def query(self, sql, params=None):
"""查询,返回全部结果行"""
cur = self.conn.cursor()
try:
cur.execute(sql, params or ())
return cur.fetchall()
finally:
cur.close()
def execute(self, sql, params=None):
"""执行增删改,返回受影响行数;失败自动回滚"""
cur = self.conn.cursor()
try:
cur.execute(sql, params or ())
self.conn.commit()
return cur.rowcount
except Exception:
self.conn.rollback()
raise
finally:
cur.close()
def close(self):
self.conn.close()
if __name__ == '__main__':
db = DmDb('127.0.0.1', 5236, 'SYSDBA', 'SYSDBA001')
try:
print(db.query('select id, name from test_dmpython'))
finally:
db.close()
error: can't create or remove files in install directory错误原因:操作系统目录权限问题,dmdba 用户对 Python 的 site-packages 目录没有写权限。
解决方案:使用 root 用户修改该目录权限,使 dmdba 用户对该目录有写权限:
[root@localhost ~]# mkdir -p /usr/local/lib64/python3.7/site-packages/
[root@localhost ~]# chmod 777 /usr/local/lib64/python3.7/site-packages/
更推荐的做法(避免放宽系统目录权限):
# 使用 pip 的用户级安装
python3 -m pip install . --user
# 或使用虚拟环境
python3 -m venv venv
source venv/bin/activate
python3 -m pip install .
cannot locate an Dameng software installation错误原因:这是 DPI 环境问题,因为 dmPython 的运行需要使用 DPI 动态库,需要将 DPI 所在目录(通常是数据库安装目录的 bin 目录)加入系统的环境变量。
解决方法:设置 PATH 包含 DPI 驱动,如下:
[root@localhost ~]# export PATH=$PATH:/dm/dmdbms/bin
同时按 2.2.1 节配置 DM_HOME 与 LD_LIBRARY_PATH,并重新执行安装命令。
No module named 'setuptools'(或 pkg_resources 相关错误)错误原因:Python 3.12 起不再默认捆绑 setuptools。
解决方法:
pip install setuptools
然后重新执行安装。
Python.h: No such file or directory错误原因:缺少 Python 头文件开发包。
解决方法:
# CentOS / RHEL / 麒麟
yum install -y python3-devel gcc
# Ubuntu / Debian
apt-get install -y python3-dev build-essential
Unable to find vcvarsall.bat;Linux:gcc: command not found)错误原因:源码安装 dmPython 需要本机编译环境。
解决方法:Windows 安装 Visual Studio Build Tools;Linux 安装 gcc;或直接使用驱动包中提供的预编译 whl 文件安装(见 2.3 节方式三)。
import dmPython 报错:No module named dmPython错误原因:没有成功安装 dmPython,或安装到的 Python 环境与运行程序的环境不一致。
解决方法:
① 如果没有成功安装 dmPython,请按第 2 章步骤安装 dmPython;
② 机器上存在多个 Python 版本时,请确认安装与运行使用的是同一个解释器。统一使用以下方式安装可避免该问题:
python3 -m pip install .
import dmPython 报错:ImportError: libdmdpi.so: cannot open shared object file(Linux)或 DLL load failed(Windows)错误原因:dmPython 的运行需要使用 DPI 动态库,应该将 DPI 所在目录(通常是 $DM_HOME/bin 目录)加入系统的环境变量。
解决方法:
[root@localhost ~]# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/dm/dmdbms/bin
Windows 下将 C:\dmdbms\bin 加入 PATH。配置后需重新打开终端窗口再运行程序(见 2.2 节)。
错误原因:数据库服务未启动、IP 或端口不正确、网络不通或被防火墙拦截。
解决方法:
① 确认数据库实例已启动:
# Linux 下查看服务状态
systemctl status DmServiceDMSERVER.service
② 确认 server、port 参数正确(DM 默认端口 5236);
③ 测试网络连通性:ping 主机、telnet 127.0.0.1 5236;
④ 检查防火墙是否放通了数据库端口。
错误原因:账号密码不正确,或安装数据库后已修改过 SYSDBA 默认密码。
解决方法:确认使用正确的用户名与密码。达梦初始默认口令为 SYSDBA/SYSDBA(实际以安装时的设置为准)。若密码中含有特殊字符,注意代码中的转义。
错误原因:客户端编码与数据库字符集不一致。
解决方法:连接时显式指定 local_code 参数,使其与数据库字符集匹配(UTF-8 字符集的库指定为 PG_UTF8):
conn = dmPython.connect(user='SYSDBA', password='SYSDBA001',
server='127.0.0.1', port=5236,
local_code=dmPython.PG_UTF8)
以下两个问题属于 ODBC 环境配置问题,与 dmPython 无直接关系,但经常在搭建达梦开发环境时一并遇到,故一并收录。
Can't open lib '/dm8/drivers/odbc/libdodbc.so': file not found错误原因:没有配置 LD_LIBRARY_PATH 环境变量。
解决方案:配置 LD_LIBRARY_PATH 环境变量:
[root@localhost ~]# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/dm8/drivers/odbc/
Data source name not found[dmdba@localhost ~]$ isql dm -v
错误原因:数据源名称 DSN 不正确。
解决方法:检查 odbc.ini 中配置的数据源名称,输入正确的数据源名称。
| DM 类型 | Python 写入类型 | Python 读取返回类型 |
|---|---|---|
| CHAR / CHARACTER | str |
str |
| VARCHAR / VARCHAR2 | str |
str |
| TEXT / LONGVARCHAR | str |
str |
| TINYINT / SMALLINT / INT / INTEGER / BIGINT | int |
int |
| DEC / DECIMAL / NUMBER / NUMERIC | decimal.Decimal |
decimal.Decimal |
| FLOAT / DOUBLE / REAL / DOUBLE PRECISION | float |
float |
| BIT | bool |
bool |
| DATE | datetime.date |
datetime.date |
| TIME / TIME(p) | datetime.time |
datetime.time |
| TIMESTAMP / TIMESTAMP(p) | datetime.datetime |
datetime.datetime |
| BINARY / VARBINARY | bytes |
bytes |
| BLOB / IMAGE | bytes |
bytes |
| CLOB / TEXT(大对象) | str |
str |
| 参数 | 类型 | 说明 | 默认值 |
|---|---|---|---|
user |
str | 登录用户名 | 必填 |
password |
str | 登录密码 | 必填 |
server |
str | 服务器地址(IP 或主机名) | localhost |
port |
int | 服务器端口 | 5236 |
local_code |
int | 客户端编码(dmPython.PG_UTF8 / dmPython.PG_GBK) |
与系统环境相关 |
login_timeout |
int | 登录超时时间(秒) | 驱动默认 |
dsn |
str | 连接串形式的连接描述 | 无 |
文章
阅读量
获赞
