You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Dash调用Clickhouse二次查询报WinError 10038及属性错误求助

问题原因
  • 你使用了全局单例的Clickhouse客户端实例,主流Clickhouse Python驱动的默认客户端不是线程安全的,且默认配置下单次查询完成后会自动关闭底层socket连接
  • Dash的回调默认是多线程执行,第二个回调触发时,第一个回调已经使用完全局客户端并销毁了对应的socket连接,第二次复用已销毁的连接实例执行查询就会触发对应报错
解决方案

方案1:每次查询新建独立客户端实例(适合查询量小的场景)

将全局客户端改为每次查询时新建、查询结束主动销毁,避免连接复用冲突:

# 封装客户端初始化逻辑
def get_ch_client():
    # 替换为你自己的Clickhouse连接配置
    from clickhouse_driver import Client
    return Client(
        host='你的Clickhouse地址',
        port=9000,
        user='你的用户名',
        password='你的密码',
        database='默认数据库'
    )

def get_alldata(timestart):
    client = get_ch_client()
    try:
        statement = f""" SELECT * FROM "xxx"."xxx" WHERE timestart>=toDateTime('{timestart}')"""
        df = client.query_dataframe(statement)
        return df
    finally:
        # 查询完成主动断开连接
        client.disconnect()

def second_request(id, time, line):
    client = get_ch_client()
    try:
        # 注:如果id、time、line是列表类型,需要先转为逗号分隔的字符串
        # 示例:id_str = ','.join(map(str, id))
        statement = f'''SELECT student,class FROM "xxx"."xxx" WHERE id IN ({id}) AND time IN ({time}) AND line IN ({line})'''
        df = client.query_dataframe(statement)
        return df
    finally:
        client.disconnect()

方案2:使用线程安全的连接池(适合查询量大的场景)

如果查询频次高的场景下使用连接池复用连接,降低每次新建连接的性能开销:

from clickhouse_driver import Pool
# 全局初始化连接池,max_connections设置支持的最大连接数
ch_pool = Pool(
    host='你的Clickhouse地址',
    port=9000,
    user='你的用户名',
    password='你的密码',
    database='默认数据库',
    max_connections=10
)

def get_alldata(timestart):
    with ch_pool.get_client() as client:
        statement = f""" SELECT * FROM "xxx"."xxx" WHERE timestart>=toDateTime('{timestart}')"""
        df = client.query_dataframe(statement)
        return df

def second_request(id, time, line):
    with ch_pool.get_client() as client:
        statement = f'''SELECT student,class FROM "xxx"."xxx" WHERE id IN ({id}) AND time IN ({time}) AND line IN ({line})'''
        df = client.query_dataframe(statement)
        return df
额外注意事项
  • 你当前的SQL写法是直接拼接用户输入的参数,存在SQL注入风险,推荐使用驱动自带的参数化查询能力传入参数,示例如下:
# 参数化查询写法示例
statement = '''SELECT student,class FROM "xxx"."xxx" WHERE id IN %(id)s AND time IN %(time)s AND line IN %(line)s'''
df = client.query_dataframe(statement, parameters={'id': id, 'time': time, 'line': line})
  • 如果Dash服务开启了多进程部署模式,不要在父进程初始化客户端或连接池,需要在每个子进程中独立初始化。

内容的提问来源于stack exchange,提问作者Minecraft_Json

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 18:09:02