但凡用Python写过业务系统数据库连接这关基本绕不过去。我这次聊的就是Python连PostgreSQL这件事从环境准备、驱动选型到连接池、批量写入再到实际排查过的坑一次性把“python PostgreSQL 数据库连接”这条链路说透。文章适合刚入门的Python新手也适合正在写Web服务、数据处理脚本想搞清楚连接方案怎么选、代码怎么写更稳的开发者。先给个结论Python连PostgreSQL这件事本身不难难的是在不同的业务场景下选对连接方式并且把连接的生命周期管理好。新手最容易犯的错是把数据库连接代码到处复制写一段跑一段等并发一上来就报“too many connections”。这篇文章就是想让你避开这些坑把连接这件事做成工程化的标准动作。1. 先理清思路Python连接PostgreSQL到底在做什么1.1 这一步解决的问题说白了Python连接PostgreSQL就是让你的Python进程能和数据库服务通信。PostgreSQL本身是个独立的数据库服务进程监听在某个端口上Python这边通过一套数据库驱动驱动就是负责转发SQL语句、接收结果集的程序把你的SQL请求发过去再把数据库算好的结果拿回来。这个“连接”并不是一次性的动作。一次完整的数据操作流程往往是建立连接、执行SQL、获取结果、提交事务、关闭连接。连接本身是有开销的它涉及TCP握手、身份认证、内存分配、会话初始化等一系列操作。所以“怎么连、连完怎么复用、用完怎么关闭”才是真正决定程序性能的地方。我记得第一次写Python连数据库的时候图省事在循环里不断connect和close结果压测跑到200个并发数据库直接报连接数超限。从那之后我就养成了习惯任何连接操作必须考虑复用和收敛而不是临时起意随手connect。1.2 方案选型的四个维度面对Python连接PostgreSQL的各种方案我一般从四个维度来评估兼容性驱动是否支持你当前的Python版本是否能匹配PostgreSQL服务端的版本特性。这个决定了你装不装得上、连不连得通。性能是否支持连接池、批量操作、异步IO。业务并发上来之后这几个能力直接决定系统能不能扛住压力。易用性API是否简洁文档是否清晰社区是否有足够多的踩坑记录。小众驱动的坑往往只能自己硬踩。团队可维护性团队里其他人是否熟悉这个方案后续接手的人能不能看得懂。这四个维度不用追求每一项都拉满但至少要明确你的核心诉求。做数据分析脚本性能不是首要考量易用性和兼容性更重要做高并发API服务连接池和异步支持就非常关键。2. 环境准备装对Python和PostgreSQL是成功的一半2.1 Python环境版本与虚拟环境连接PostgreSQL之前先把Python环境理清楚省得后面驱动装不上、版本不兼容的时候一头雾水。我目前的建议是新项目统一用Python 3.10以上版本除非你有历史包袱必须用老版本。Python 3.8以下版本在类型注解、依赖管理、异步生态上已经有明显差距而新版驱动尤其是psycopg3这种对Python 3.8的兼容策略也比较保守没必要给自己设限。另一个一定要做的事情就是使用虚拟环境。很多新手装包直接pip install装到系统全局长期下来各种包版本互相干扰连自己的项目是用哪个环境启动的都分不清。用venv可以快速隔离项目依赖python -m venv venv # Windows venv\Scripts\activate # Linux / macOS source venv/bin/activate pip install --upgrade pip虚拟环境建好之后后续给PostgreSQL驱动专门开一个干净的安装空间出问题也好排查。我见过不少人装psycopg2失败最后发现是系统里Python环境太杂编译工具链和头文件错位用干净的venv基本能规避这类问题。2.2 PostgreSQL安装Windows与Linux两条路线PostgreSQL的安装和Python环境同样重要。这里分两条路线讲。Windows安装 直接去PostgreSQL官网下载安装包双击安装。有几个要点值得留意安装过程中会让你设置超级用户postgres的密码这个密码以后会在连接、管理里反复用到建议用一个专门记密码的工具存好。端口默认5432一般不用改。如果你本机端口被占用了改成别的端口也可以但后面所有连接串都要跟着改。安装完确认服务已经启动。打开Windows服务管理器找到postgresql相关的服务确认状态是“正在运行”。这一步经常被忽视服务没起来程序连接当然报错。安装完之后我习惯顺手验证一下服务能否正常响应。随便用一个数据库管理工具或者直接在命令行里执行psql -U postgres -p 5432能进入psql交互界面说明服务端OK。Linux安装 在Ubuntu/Debian系上安装非常简单sudo apt update sudo apt install postgresql postgresql-contrib安装完成后PostgreSQL默认只在本地监听而且默认采用peer认证。也就是说本地直接用postgres系统用户进psql不需要密码sudo -u postgres psql如果想允许远程连接要改两个地方一个是postgresql.conf里的listen_addresses一个是pg_hba.conf里的认证规则。这两个文件的具体位置可以通过以下命令确认sudo -u postgres psql -c SHOW config_file; sudo -u postgres psql -c SHOW hba_file;把listen_addresses改成*然后在pg_hba.conf里增加允许的IP段再重启服务sudo systemctl restart postgresql注意listen_addresses改成*意味着数据库会监听所有网卡生产环境务必配合防火墙白名单不要裸奔到公网。2.3 建库建用户权限问题提前解决连接之前先建好数据库和用户。别用postgres超级用户跑业务连接这是个必须养成的好习惯。超级用户权限太大万一代码里SQL写错误删数据或者改了不该改的结构哭都来不及。我通常的做法是为每个项目单独建一个用户和一个数据库CREATE USER app_user WITH PASSWORD YourStrongPassword; CREATE DATABASE mydb OWNER app_user; GRANT ALL PRIVILEGES ON DATABASE mydb TO app_user;如果需要对表做更细粒度的权限控制可以在连接后由服务端管理员继续授权。但大部分中小项目做到库和用户分离已经足够。建好之后先验证一下能不能用新用户连上psql -h 127.0.0.1 -p 5432 -U app_user -d mydb这一步经常能提前暴露认证问题。比如刚才说的peer认证远程连接时会变成scram-sha-256或md5认证。如果验证不通过就是pg_hba.conf配置的问题具体排查方法我放在第6章。3. 驱动选型psycopg2、psycopg3、asyncpg、SQLAlchemy怎么挑3.1 四大驱动横向对比Python连PostgreSQL的驱动不少但实际用到最后值得认真考虑的其实就这几个psycopg2、psycopg3、asyncpg、SQLAlchemy严格说SQLAlchemy是ORM/抽象层底层还是调用psycopg2或asyncpg。我整理过一个对比表直接贴出来驱动类型同步/异步连接池支持适用场景难度psycopg2数据库驱动同步需配合其他库传统Web应用、数据脚本低psycopg3数据库驱动同步/异步内置新项目、追求性能和现代化API中asyncpg数据库驱动异步内置高并发异步服务中高SQLAlchemyORM抽象层同步/异步内置项目需要ORM建模、多数据库迁移中对比之后你会发现没有哪个驱动是绝对的“最好”只有“当前场景下更合适的”。3.2 psycopg2为什么是默认选择psycopg2是Python社区连接PostgreSQL历史最悠久的驱动之一也长期被当作默认选择。它的API非常简单稳定可靠绝大多数教程和文档都基于它编写。如果我只需要写一个几十行的脚本从数据库拉取数据做分析首选psycopg2因为资料多、坑少、招人能看懂。不过psycopg2有个小问题它的二进制包和系统编译环境的关系比较微妙。尤其在Linux上有时需要安装libpq-dev或build-essential才能顺利装好sudo apt install libpq-dev python3-dev pip install psycopg2-binary如果有编译困难直接用psycopg2-binary最省事但生产环境我建议还是用源码版psycopg2能跟随系统libpq更新性能和安全上更稳妥。3.3 SQLAlchemy负责“偷懒”如果你要写的是业务系统频繁建表、改表、做数据迁移纯手写SQL效率很低。SQLAlchemy这类ORM框架可以把数据库表映射成Python对象让你用面向对象的方式操作数据。我自己的习惯是简单查询用原生SQL加psycopg2复杂业务建模用SQLAlchemy。SQLAlchemy的另一个重要价值是连接池管理。它内置了QueuePool可以很灵活地配置连接池大小、回收时间、溢出上限等参数。这样你在写业务代码时不需要关心连接何时创建、何时归还、何时销毁框架里都给你管好了。不过要注意SQLAlchemy的学习曲线比原生驱动陡不少尤其是会话session的生命周期管理很多新手在这里栽跟头。如果项目规模不大也没必要为了“看起来专业”硬上ORM。4. 实操走通从裸连接到可维护的封装4.1 最基础的连接代码先用psycopg2写一个最基础的连接让链路先通起来import psycopg2 conn psycopg2.connect( host127.0.0.1, port5432, dbnamemydb, userapp_user, passwordYourStrongPassword, connect_timeout10 ) cur conn.cursor() cur.execute(SELECT version();) row cur.fetchone() print(row) cur.close() conn.close()connect_timeout10是我强烈建议加的参数。不加的话默认连接超时时间可能很长一旦数据库服务端卡住你的程序会挂着半天没反应。设成10秒至少能让问题尽早暴露。cur.close()和conn.close()必须养成成对出现的习惯。只关游标不关连接连接会一直占着只关连接不关游标在多数情况下连接关闭会把游标一并清理但规范起见还是按顺序关干净。4.2 连接参数与连接串写法除了上面的关键字传参方式psycopg2还支持连接串DSN写法这个在配置化管理时非常方便import psycopg2 dsn postgresql://app_user:YourStrongPassword127.0.0.1:5432/mydb conn psycopg2.connect(dsn)连接串的格式是postgresql://用户名:密码主机地址:端口/数据库名用连接串的好处是它可以直接读取环境变量不用把密码硬编码在代码里。比如在启动脚本里设置export DATABASE_URLpostgresql://app_user:YourStrongPassword127.0.0.1:5432/mydb然后在Python里读取并连接import os import psycopg2 conn psycopg2.connect(os.environ[DATABASE_URL])这样代码仓库里就不会出现明文密码部署到不同环境时不用改代码只改环境变量即可安全性和可维护性都大幅提升。4.3 封装数据库连接工具类裸连接方式只适合一次性脚本。如果要写业务系统我建议封装一个数据库连接工具类统一管理连接的创建和释放。下面是我常用的模板import psycopg2 from psycopg2.extras import RealDictCursor class Database: def __init__(self, config: dict): self.config config def __enter__(self): self.conn psycopg2.connect(**self.config) self.cur self.conn.cursor(cursor_factoryRealDictCursor) return self def __exit__(self, exc_type, exc_val, exc_tb): if exc_type is not None: self.conn.rollback() else: self.conn.commit() self.cur.close() self.conn.close() def query_all(self, sql, paramsNone): self.cur.execute(sql, params) return self.cur.fetchall() def query_one(self, sql, paramsNone): self.cur.execute(sql, params) return self.cur.fetchone()这段代码有几个细节值得说一下RealDictCursor让查询结果以字典形式返回字段名直接作为key比默认的元组更直观尤其在写API接口时省去手动对齐索引。__enter__和__exit__是Python上下文管理器协议配合with语句使用可以保证无论代码是否报错连接都会关闭。在__exit__里做了异常判断有异常就回滚没有异常就提交。这样事务的边界很清晰不会出现数据提交了一半、另一半丢失的情况。用法是这样config { host: 127.0.0.1, port: 5432, dbname: mydb, user: app_user, password: YourStrongPassword, } with Database(config) as db: result db.query_all(SELECT * FROM users WHERE status %s, (active,)) print(result)这里顺便强调一个安全点SQL查询不要用字符串拼接的方式去拼参数务必用%s占位符把参数通过第二个参数传进去。这样能从根本上避免SQL注入风险。我之前见过有人图方便写cur.execute(fSELECT * FROM users WHERE name {name})一旦name里包含恶意构造的字符串整个表都可能被删掉。5. 进阶实战连接池、批量写入与事务控制5.1 连接池别让你的程序每次都重新握手每执行一次操作就新建一个连接成本很高。数据库连接的建立涉及TCP握手和身份认证在高并发场景下频繁建连会让数据库服务端疲于处理新连接无法专注执行SQL。解决办法是引入连接池。psycopg2本身没有内置连接池通常配合DBUtils使用pip install DBUtils使用示例from dbutils.pooled_db import PooledDB import psycopg2 pool PooledDB( creatorpsycopg2, maxconnections10, mincached2, maxcached5, blockingTrue, host127.0.0.1, port5432, dbnamemydb, userapp_user, passwordYourStrongPassword, )各参数含义maxconnections10连接池允许的最大连接数。超过这个数量时新的请求会等待开启blocking模式或者直接报错关闭blocking模式。mincached2连接池中始终保持的最小空闲连接数。程序启动后可以立刻使用不用等待建连。maxcached5连接池中最多保留的空闲连接数。空闲连接超过这个数会被关闭避免占用数据库资源。blockingTrue当连接池被占满时请求排队等待连接释放而不是直接抛异常。实际使用的时候从连接池获取连接和执行SQL的代码保持不变conn pool.connection() try: cur conn.cursor() cur.execute(SELECT * FROM users WHERE id %s, (1,)) row cur.fetchone() print(row) cur.close() finally: conn.close()注意这个conn.close()不是真正关闭连接而是把连接归还给连接池。连接池会自动判断连接是否健康不健康的连接会被丢弃重建。这个机制是连接池的核心价值我把连接池理解成“健身房的储物柜”你用完了归还让下一个人继续用而不是每次来都重新租一个。如果你用的是psycopg3新版本内置了连接池API也很简洁import psycopg from psycopg_pool import ConnectionPool pool ConnectionPool( conninfopostgresql://app_user:YourStrongPassword127.0.0.1:5432/mydb, min_size2, max_size10, )用psycopg3主要是看中它对异步的支持和更干净的连接池方案新项目值得优先考虑。5.2 批量写入从executemany到execute_values批量插入数据是数据库操作里的高频场景。初学者最容易犯的错误是在循环里一条一条insert数据量小的时候感觉不到问题等到一次性要写入几万条数据时速度慢得让人怀疑人生。psycopg2的executemany是一条进阶方案data [ (1, alice, 25), (2, bob, 30), (3, carol, 28), ] sql INSERT INTO users (id, name, age) VALUES (%s, %s, %s) cur conn.cursor() cur.executemany(sql, data) conn.commit()但实测下来executemany很多时候是把一条条SQL依次发送给数据库网络往返次数并没有减少数据量大时性能提升有限。更推荐的是execute_values它能把多行数据拼成一条多VALUES语句发送网络往返次数大幅减少from psycopg2.extras import execute_values data [ (1, alice, 25), (2, bob, 30), (3, carol, 28), ] sql INSERT INTO users (id, name, age) VALUES %s cur conn.cursor() execute_values(cur, sql, data, page_size1000) conn.commit()page_size1000表示每1000条数据拼接成一条SQL发送这个值可以按数据大小调整我一般习惯设在500到2000之间再大会导致单个SQL报文过大反而拖慢解析速度。我实测过插入10万行数据循环单条insert大约需要三四十秒executemany大约十秒左右execute_values只要两三秒。在数据导入、ETL这类场景里这个差异非常明显。5.3 事务与异常处理PostgreSQL默认每次执行完SQL就自动提交但在业务系统中一个操作往往涉及多张表的修改必须保证要么全部成功、要么全部失败这里就要用到事务。psycopg2的默认行为是连接建立后处于一个隐式事务中直到执行commit或rollback。如果连接关闭之前没有执行任何提交操作未提交的更改会被回滚。一个典型的事务控制写法conn psycopg2.connect(...) try: cur conn.cursor() cur.execute(UPDATE accounts SET balance balance - 100 WHERE id 1) cur.execute(UPDATE accounts SET balance balance 100 WHERE id 2) conn.commit() except Exception as e: conn.rollback() print(事务回滚:, e) finally: cur.close() conn.close()这段代码的核心思想是任何一步SQL执行出错整个事务回滚数据保持一致不会出现“转出成功、转入失败”的尴尬情况。还有一个常用小技巧是with conn的用法with conn: cur conn.cursor() cur.execute(...)进入with块之后自动开启事务离开with块时如果没异常就提交有异常就回滚。代码更简洁但可读性因人而异我倾向于显式写commit和rollback逻辑更清楚。另外psycopg2默认的autocommit是False。如果你执行CREATE DATABASE这类DDL语句或者需要在一个事务里做分步操作时不想被隐式事务干扰可以显式设置conn.autocommit True注意这里设置的是连接对象的属性不是cursor的很多新手会找错地方。6. 常见问题与排查技巧实录6.1 高频报错速查表连接过程中遇到的报错其实高度雷同大部分问题来来去去就那几个。我整理了一个速查表基本上可以覆盖90%的场景报错信息可能原因解决办法connection refused数据库服务没启动或监听端口不对检查服务状态确认端口和connection参数password authentication failed用户名密码错误或认证方式不匹配核对密码检查pg_hba.conf认证规则FATAL: database xxx does not exist数据库名写错或大小写不匹配用\l查看已有数据库确认名称psycopg2.OperationalError: could not connect网络不通或pg_hba.conf不允许该IP排查网络修改pg_hba.conf增加IP白名单SSL error: certificate verify failed服务端启用SSL客户端没配证书连接串加sslmodedisable测试环境或配置CA证书too many connections连接数超过max_connections调大max_connections或使用连接池current transaction is aborted事务中某条SQL出错后未回滚捕获异常执行rollbackDuplicateCursor或cursor already exist游标复用或未关闭确保每次新建cursor并close6.2 几个容易忽略的细节排查问题的时候很多人只盯着代码看却忽略了服务端的一些细节。我这里说几个我实际踩过坑的细节。第一pg_hba.conf的修改需要重启服务。很多新手改了认证方式发现不生效就是因为没有重启PostgreSQL或者只是reload没有完全生效。修改pg_hba.conf后最好执行sudo systemctl restart postgresql第二IPv4和IPv6的localhost不一定是同一个。如果连接地址写localhost有时会解析成IPv6的::1而PostgreSQL可能只监听了IPv4的127.0.0.1导致连接失败。建议直接写127.0.0.1避免解析歧义。第三密码里的特殊字符需要转义。使用连接串写法时如果密码包含、/、:等特殊字符连接串会解析错误。一个办法是使用Python的urllib.parse.quote_plus对密码编码from urllib.parse import quote_plus password quote_plus(YourPass/word) dsn fpostgresql://app_user:{password}127.0.0.1:5432/mydb6.3 实测避坑心得最后分享几个我在实际项目中踩过的坑这些教训用真金白银换回来的。一个是在Windows上装psycopg2时遇到的编译问题。如果你直接用pip安装psycopg2有时候会因为缺少Visual C编译环境而失败。这时候直接指定binary版本pip install psycopg2-binary但要注意binary版本适用于本地开发和快速验证生产环境如果追求稳定性和性能还是建议在干净的环境里用源码版本。具体取舍根据你的系统环境来定。另一个是编码问题。PostgreSQL默认客户端的编码可能和服务端不一致导致中文数据插入或查询时出现乱码。推荐的建库方式是CREATE DATABASE mydb WITH ENCODING UTF8 LC_COLLATE C LC_CTYPE C;在连接的时候也可以直接指定客户端编码conn psycopg2.connect(..., options-c client_encodingUTF8)还有一个容易踩的坑是连接池大小设置不当。很多初学者把连接池配得很大比如maxconnections100觉得这样能扛更多并发。但实际上数据库的max_connections默认是100你的应用连接池设了100数据库自己还要留连接给管理操作一旦并发上来直接把数据库打挂。我的一贯做法是应用程序连接池的大小控制在数据库max_connections的50%以内留出富余给数据库内部使用。同时应用层要设置合理的连接等待超时避免请求永远卡在连接池排队。另外用PostgreSQL的pg_stat_activity查询当前连接状态是排查连接问题的利器SELECT pid, usename, application_name, client_addr, state, query FROM pg_stat_activity WHERE datname mydb;从这个视图能看到谁在连接、连接在干嘛、有没有长时间卡住的事务。生产环境连接数异常升高时第一反应应该就是查这个视图。最后再分享一个我个人的小习惯。每次连接参数有变化时我先用psql命令行手动连一次确认服务端一切正常再去改Python代码。这个习惯帮我省掉了大量“代码没问题但连不上”的排查时间。数据库连接这套东西说到底就是“服务端配置 客户端参数”两边对齐的问题一边不对齐另一边再怎么调都白搭。
企业数字化 ERP 产品动态
相关推荐
Olla:自托管AI模型的智能代理与负载均衡器实战 前阵子帮朋友把他办公室里的三台 GPU 机器统一接入一个 AI 网关,他最初的需求特别简单:不要让产品经理每次换个模型地址就来找我改代码。结果我陪他改了三轮配置才意识到,这事情看起来是“搭个代理转发一下”,实际上牵扯到模型路由… · 2026/9/24 19:53:43
Seq2seq+LSTM+Attention:聊天机器人情绪检测系统实战 简介:这是一份用于毕业设计或NLP入门实战的聊天机器人情绪检测项目资源,面向计算机相关专业学生及自然语言处理爱好者,解决在Seq2seq框架下融合LSTM与Attention机制实现智能对话,并同步完成用户情绪状态初步检测的需求。技术栈包括… · 2026/9/24 19:53:37
拯救者玩游戏花屏闪退,不一定是显卡驱动问题 不少拯救者游戏本用户碰到这样的故障:桌面浏览网页、看视频一切正常,只要打开大型游戏,画面就出现色块、条纹、马赛克花屏,紧接着游戏闪退,严重时直接蓝屏。很多人第一反应就是显卡驱动出问题,反复卸载、重… · 2026/9/24 20:25:51
求职焦虑自救指南:用能力定位和项目思维破局就业困境 1. 焦虑人人都有,但别被"数字"牵着走我最近后台收到不少年轻朋友的留言,都在问同一个问题:大环境不好,是不是毕业就等于失业?是不是再怎么努力也没用?说实话,只要打开社交平台&#x… · 2026/9/24 20:25:51
全开源超级签名系统部署指南:iOS内部分发与UDID签名原理详解 简介:面向需要搭建iOS应用分发与签名服务的开发者和企业,这是一套全开源的APP分发系统及超级签名系统源码,基于PHP开发,具备后台管理功能,并附详细部署文档。系统方案涵盖后台账号配置、阿里云OSS存储、七牛云下载包托… · 2026/9/24 20:25:51
Edge无法发送验证码?揭秘浏览器UA检测与兼容性问题 “全国新书目-书籍-教材查询-最全面-用chrome 浏览器才能发送验证码——用edge浏览器登入提示无法发送验证码,为何?”这个标题里的问题,我太熟了。遇到这个问题的绝对不止你一个人,它背后牵扯出的其实是很多老网站做浏览器适配时留… · 2026/9/24 20:25:39
订单多了,利润却薄了?模具注塑厂的效率困局 订单量上涨,账上利润却没同步变厚,这是当下不少模具注塑厂的真实体感。旺季产线排满,淡季又空转,摊薄下来单件成本反而走高。问题往往不在订单本身,而在从开模到量产之间的衔接损耗。有行业统计显示,制造环… · 2026/9/24 20:25:39
代码只会看红色报错,用 AI 两天做了个「我来挪车啊」的小程序 本职设计师,代码水平约等于「看得懂报错是红色的」。前两天突然冒出一个想法:很多人看挪车视频时都是副驾车神,真把方向盘交到手里,左右立刻需要重新定义。于是我拉着 AI 连肝两天,做了微信小程序「我来挪车啊」。AI 负… · 2026/9/24 20:25:39
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程 简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13
1D-CNN时间序列建模实战:从Conv1d原理到工业落地 简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26
柔软的L:汉语语流中被忽视的舌肌张力控制 1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44