先介绍安装odbc驱动,如果已安装跳过次环节
参考链接:linux环境odbc驱动安装 - 哔哩哔哩
也可参考微软官网(Windows驱动也有介绍):安装 Microsoft ODBC Driver for SQL Server (Linux) - ODBC Driver for SQL Server | Microsoft Learn
ODBC Driver是一种动态链接库 (DLL),支持 ODBC 的应用程序(如 Excel)可以用它来访问 ODBC 数据源。每个 ODBC 驱动程序针对一个数据库管理系统 (DBMS),如 SQL Server、Access 等等。
[root@dca01 tmp]# rpm -qa | egrep 'gcc|make'
# 如果没有以上工具,可以搭建yum源快速安装
[root@dca01 tmp]# yum -y install gcc make
下载地址:http://ftp.unixodbc.org/
[root@loaclhost ~]# tar -xvf unixODBC-2.3.1.tar.gz
[root@loaclhost ~]# cd unixODBC-2.3.1/
#--prefix=/test指定安装目录为/test,如果不指定会默认安装到/usr/local,根据需要确定是否指定其他安装目录;如果是arm架构机器,执行 . /configure --prefix=/test --build=arm-linux,高版本unixODBC不区分架构使用./configure --prefix=/test即可
[root@loaclhost unixODBC-2.3.1]# ./configure --prefix=/test
[root@localhost unixODBC-2.3.1]# make
[root@localhost unixODBC-2.3.1]# make install
# 输出odbc driver配置项路径等内容,注意下方截图为2.3.1版本,重点关注 unixODBC 2.3.1所在行下面的内容;如果执行后发现drivers,system data sources等项配置的路径跟实际情况不符合,可以执行export ODBCSYSINI=/test/etc ,重新执行odbcinst -j后如果没有问题,更新至环境变量
[root@localhost unixODBC-2.3.1]# odbcinst -j
USER DATA SOURCES 对应的文件里面内容为空,不需要写配置项
#此处的odbc.ini路径是通过odbcinst -j输出的SYSTEM DATA DOURCES项的路径
vim /usr/local/etc/odbc.ini
#将以下内容根据实际情况填写
[dm8] #driver name 用于isql 测试
Description = DM ODBC DSND
# 这里填的驱动需与 odbcinst.ini 中的节点名称相同
Driver = DM8 ODBC DRIVER
# 达梦数据库的地址,也可以填写具体ip,例127.0.0.1
SERVER = localhost
# 数据库用户名,根据数据库的实际情况填写
UID = SYSDBA
# 数据库密码,根据实际情况填写
PWD = Dameng123
# 达梦数据库端口,根据实际情况填写
TCP_PORT = 5238
#此处的odbc.ini路径是通过odbcinst -j输出的DRIVERS项的路径
vim /usr/local/etc/odbcinst.ini
#将以下内容根据实际情况填写
[DM8 ODBC DRIVER]
Description = ODBC DRIVER FOR DM8
#此处填写的地址是{DM_HOME}/bin/libdodbc.so,按照实际情况填写,{DM_HOME}为达梦数据库安装目录,举个例子:/test/dmdba/dmdbms/bin/libdodbc.so
DRIVER = /test/dmdba/dmdbms/bin/libdodbc.so
#如果输出结果为下图,表示连接成功
isql dm8 -v
a. 配置文件odbcinst.ini和odbc.ini路径是否正确,配置项是否正确
b. 配置文件odbcinst.ini和odbc.ini中每一行的开头不允许有空格
c. 如果发现odbcinst.ini路径不符合预期,可以通过export ODBCSYSINI=/DCE/rc110/etc/进行变更,注意后面的路径前缀根据实际情况变更
a. 检查odbcinst.ini文件配置的driver路径是否存在,注意指向的是libdodbc.so的path
a. 使用root账户编辑/etc/profile ,将odbcinst所在目录追加到环境变量
a. 配置环境变量LD_LIBRARY_PATH
#以root身份编辑
vim /etc/profile
#/dm8/dmdba/dmdbms为达梦数据库安装目录即前面提到的{DM_HOME}
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/dm8/dmdba/dmdbms/bin/"
export PATH=$PATH:/dm8/dmdba/dmdbms/bin
#在对应用户身份下的目录执行
source /etc/profile
b. 确认libdodbc.so所在路径当前用户有权限,如果没有权限需要切换到root用户修改一下文件夹权限
#注意此处的路径根据实际安装情况来
chmod 755 {DM_HOME}
a. 检查环境变量,一般是LD_LIBRARY_PATH环境变量配置问题;目前遇到这个问题是在非root用户下,发现/etc/profile中设置的环境变量,和 ~/.bashrc中设置有冲突,删除/etc/profile下对应内容,并在~/.bashrc中设置即可
参考链接:使用ODBC连接db2数据库_zwwangoo的博客-CSDN博客
import sys
import traceback
import pandas as pd
import pyodbc
from urllib.parse import quote_plus as urlquote
# 数据库信息示例
from sqlalchemy import create_engine
def db_query(sql, dbtype='doris', conp=None):
"""
执行sql返回DataFrame类型数据
conp= [user,passwd,host,port, db]
create_engine 还有很多可选参数,这里介绍几个重要的参数:
echo :为 True 时候会把sql语句打印出来,当然,你可以通过配置logger来控制输出,这里不做讨论。
pool_size: 是连接池的大小,默认为5个,0表示连接数无限制
pool_recycle: MySQL 默认情况下如果一个连接8小时内容没有任何动作(查询请求)就会自动断开链接,出现 MySQL has gone away的错误。设置了 pool_recycle 后 SQLAlchemy 就会在指定时间内回收连接。如果设置为3600 就表示 1小时后该连接会被自动回收。
pool_pre_ping : 这是1.2新增的参数,如果值为True,那么每次从连接池中拿连接的时候,都会向数据库发送一个类似 select 1 的测试查询语句来判断服务器是否正常运行。当该连接出现 disconnect 的情况时,该连接连同pool中的其它连接都会被回收。
:param sql:
:param dbtype:
:param conp:
:return:
"""
con = None
df = pd.DataFrame()
err = None
sql = sql.replace("'null'", 'null')
if not conp: return None, 0
try:
if dbtype == 'postgresql':
con = create_engine("postgresql://%s:%s@%s:%s/%s" % (
conp[0], conp[1], conp[2], conp[3], conp[4]), echo=True,
pool_pre_ping=True, encoding='utf-8')
if len(conp) == 5: conp.append('public')
sql = "set search_path to %s;" % conp[5] + sql
elif dbtype == 'oracle':
con = create_engine('oracle://%s:%s@%s:%s/%s' % (
conp[0], conp[1], conp[2], conp[3], conp[4]), echo=True,
pool_pre_ping=True, encoding='utf-8')
elif dbtype == 'sqlite':
con = create_engine('sqlite:///%s' % conp)
elif dbtype == 'doris':
con = create_engine('mysql+pymysql://%s:%s@%s:%s/%s?charset=utf8' % (
conp[0], conp[1], conp[2], conp[3], conp[4]), echo=True,
pool_pre_ping=True, encoding='utf-8')
elif dbtype == 'sqlserver':
params = urlquote((f"DRIVER={{SQL Server}};SERVER={conp[2]};PORT={conp[3]};DATABASE={conp[4]};UID={conp[0]};PWD={conp[1]}"))
connect_string = (f"mssql+pyodbc:///?odbc_connect={params}")
con = create_engine(connect_string, echo=True, pool_pre_ping=True, encoding='utf-8')
elif dbtype == 'db2':
con = create_engine("db2+ibm_db://%s:%s@%s:%s/%s?charset=utf8" % (conp[0], conp[1], conp[2], conp[3], conp[4]), echo=True, pool_pre_ping=True, encoding='utf-8')
else:
con = create_engine('mysql+pymysql://%s:%s@%s:%s/%s?charset=utf8' % (
conp[0], conp[1], conp[2], conp[3], conp[4]), echo=True, pool_pre_ping=True, encoding='utf-8')
df = pd.read_sql(sql, con)
con.dispose()
return df, 1
except Exception as e:
err = traceback.format_exc()
print(err)
finally:
if con is not None: con.dispose()
if not df.empty and len(df) != 0:
return df, 1
else:
return err, 0