恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
Python连接SQL Server完全指南:驱动选型、连接串避坑与增删改查实战
首页
资讯中心
/
Python连接SQL Server完全指南:驱动选型、连接串避坑与增删改查实战
Python连接SQL Server完全指南:驱动选型、连接串避坑与增删改查实战
发布时间:2026/10/14 4:38:01
先说个题外话你标题里写的SQL SEVER其实是拼错了正确是SQL Server。我刚开始看到的时候还愣了一下不过也说明你确实是需要这套东西。Python连SQL Server这个需求这些年做企业级项目、做数据处理的开发基本都绕不开尤其是Windows环境之外、跑在Linux或容器里的Python服务要连SQL Server那真是每一步都有坑。这套流程我自己完整走通了不止一遍中间踩过不少坑这次干脆把从零到能跑通增删改查的整套路径、驱动选择、连接串坑点、报错排查一次讲透。这篇文章适合谁适合那种Python功底还行、但第一次要在业务里接SQL Server的人也适合那些已经用pyodbc连上了但被各种证书报错、乱码、批量插入太慢折磨过的人。如果你只是想背一段代码拿来跑通没问题直接把第3节的模板抄走就能用如果你想把这块彻底搞明白以后不再被类似问题绊住我建议你从头往下读每个小节里都有我实操后补出来的笔记。1. 方案选型Python连SQL Server到底走哪条路1.1 先搞清楚你手里的牌pyodbc / pymssql / SQLAlchemyPython连SQL Server的方案社区里主流就三条路。第一条是用pyodbc这是基于ODBC标准接口的库也是我最终长期用的方案第二条是pymssql走的是FreeTDS协议第三条是用SQLAlchemy作为上层框架但它底层引擎要么走pyodbc要么走pymssql。先说结论如果你是在写业务代码、脚本、数据处理流程pyodbc是最稳的选择。原因有几个方面。第一它遵守Python Database API 2.0规范这意味着你写的连接代码和操作代码几乎可以无缝平移到MySQL、PostgreSQL等其它数据库换库不换习惯。第二它直接走微软官方的ODBC驱动协议兼容性远好于FreeTDS这种逆向实现的尝试。第三pyodbc的维护状态稳定社区覆盖面也广你遇到报错的时候搜解决方案能搜出一堆实际案例。pymssql也不是不能用早些年它在Linux上的安装比pyodbc简单因为它不需要额外安装ODBC驱动。但pymssql历史上出现过维护停摆、老版本编译问题而且它在大批量读写场景下的表现并没有明显优势。如果你已经在项目里用了pymssql不需要急着换但如果是新项目我没理由推荐一个底层基于FreeTDS的库去对接SQL Server本身的新特性。SQLAlchemy单独拿出来说因为它是ORM层不是纯粹的数据库驱动。如果你只是做简单的数据读写SQLAlchemy那套抽象反而会带来心智负担但如果你要做复杂的数据模型映射、做查询构建、做连接池管理SQLAlchemy又是很好的基础设施。下面这段话我想强调一下即使你用SQLAlchemy底层连接串依然要遵守pyodbc那套规则所以这篇文章前半部分对SQLAlchemy用户同样成立。方案底层协议安装复杂度稳定性与生态适用场景pyodbcODBC需要额外装ODBC驱动非常稳定、资料多通用业务代码、数据迁移、脚本pymssqlFreeTDS相对简单维护起伏、资料偏旧老项目维护、SQL Server低版本兼容SQLAlchemy通过pyodbc/pymssql需配合上述驱动稳定但偏重ORM建模、复杂查询、连接池1.2 为什么不建议在连接层绕回ORM这里想说一个我在实际项目里的体会很多人一上来就想用SQLAlchemy觉得这样以后换数据库方便。但换数据库这件事本身就是个伪需求真正把Oracle切成SQL Server的项目少之又少就算有也轮不到你临时写ORM来兜底。直接用pyodbc写参数化SQL反而是最没有隔阂的路径调试起来也直观查问题的时候不用绕两层抽象。另外ORM并不是银弹它会隐式生成SQL一旦表结构设计得不好或者查询路径复杂生成的SQL性能可能远差于你手写的SQL。SQL Server的索引设计、执行计划分析这些还依赖你真正懂得SQL本身。所以我个人建议能直接用pyodbc的不要急于上ORM先把数据访问层控制在自己手里等查询逻辑确实复杂到需要对象关系映射的时候再引SQLAlchemy不迟。2. 环境准备驱动装不对后面全是白干2.1 ODBC这层到底干什么的ODBCOpen Database Connectivity是一个通用的数据库访问接口SQL Server官方驱动在Windows、Linux、macOS上都有发布。pyodbc本身只是一套Python到ODBC的桥接真正去和数据库服务器通信的是ODBC驱动。所以你的机器上如果没有装ODBC驱动pyodbc会直接报找不到驱动的错误。这个驱动没装对是新手踩坑率最高的点。很多人在Windows上跑通了代码把同样的代码扔到Linux服务器上结果连不上第一反应是以为是SQL Server配置问题其实往往是Linux上没装ODBC驱动。Windows系统通常自带面向SQL Server的ODBC驱动但Linux和macOS需要你额外安装。2.2 Windows环境装驱动Windows环境相对省心。打开ODBC数据源管理器或直接查一下已安装的驱动程序列表就能知道当前机器上有什么驱动版本。如果没有合适的驱动从微软官方下载页面把对应的ODBC Driver for SQL Server安装包下载下来一路下一步装上去就行。安装完成后在ODBC管理器里能看到ODBC Driver 18 for SQL Server这类条目。有朋友会装那种x86和x64都有的老版本驱动但既然是新项目我建议直接从新版开始。要注意一点你的Python解释器是64位的驱动就装64位的Python是32位的驱动就需要对应32位否则会报数据源名称找不到这类错误。这个位数不匹配的问题在Windows上非常容易踩我遇到不止一次值得先检查。2.3 Linux与容器环境装驱动这块是真正的大坑密集区。以Ubuntu系为例安装ODBC Driver 18需要先从微软官方源里导入签名密钥和仓库信息。你需要在官方文档中把这组命令完整找出来按文档顺序跑一遍。如果你用的是基于Linux的Docker镜像我也是建议直接把这些命令写进Dockerfile里一次性安装。装完之后有一个容易忽略的步骤安装unixODBC开发包。因为pyodbc在编译或运行时要依赖unixODBC的动态库如果你只是装了驱动而没装unixodbc、unixodbc-dev这两个包pyodbc会在运行时报底层动态库找不到的错误那个报错会让人完全摸不着头脑。我第一次在云主机上部署时就是漏了这一步排查了半天才发现根本不是代码问题是系统库缺失。CentOS系或RHEL系环境则是用yum包管理同样需要先配置官方仓库。macOS的话有人用homebrew装微软的ODBC驱动有人直接用系统自带驱动但建议也是按照官方文档走一遍比较稳妥。2.4 验证驱动是否装好了装完驱动之后最快的验证方式是用命令行工具先连一下数据库比如SQL Server自带的sqlcmd工具或者用odbcinst命令查看已安装的驱动列表。如果你命令行都连不上那问题在数据库端或网络端根本还没到Python的层面。这一步能帮你快速定位问题归属省得后面在Python代码里反复试错。3. 连接字符串每个参数都是坑拆开揉碎讲清楚3.1 一段最快能跑通的代码先给你一段最基础且能跑通的pyodbc连接代码。假设你在本地或远程有一台SQL Server数据库名testdb账号sa密码123456。注意这里的驱动名是对应你机器上装的驱动版本的。import pyodbc conn_str ( rDRIVER{ODBC Driver 18 for SQL Server}; rSERVERlocalhost,1433; rDATABASEtestdb; rUIDsa; rPWD123456; rTrustServerCertificateyes; ) conn pyodbc.connect(conn_str) cursor conn.cursor() cursor.execute(SELECT 1) print(cursor.fetchone()) conn.close()如果你现在跑不通多数情况会卡在驱动的版本、网络连通性、或者下面我要讲的证书问题这三点上。先不要急着去翻SQL Server的配置对照后面的参数说明一项一项排查。3.2 连接串里最容易被忽略的三组参数第一组是DRIVER。连接串里的DRIVER名字必须和系统中实际的驱动名精确匹配空格、括号一个都不能少。比如你装了ODBC Driver 18连接串里就要写ODBC Driver 18 for SQL Server如果写成SQL Server这种老式名称系统可能会尝试去找旧驱动导致报错。你可以在Python里通过pyodbc.drivers()这个函数来查询当前环境里到底装了什么驱动再把它动态拼进连接串这样代码换个环境也不太容易坏。第二组是SERVER。SERVER不仅写主机名或IP端口也要写对。默认端口是1433如果实例不是默认端口写的时候要用host,port这种英文逗号隔开的格式。这里有个很隐晦的坑如果你用了命名实例比如host\named_instance在连接串里反斜杠可能要写成双反斜杠或者直接在连接串前加r把它们转成原始字符串。这种反斜杠的转义问题是Python连接串里最常见的崩溃来源之一。第三组是DATABASE与连接超时。DATABASE指定你要连的库名如果你的账号在实例上连接的是默认库不写DATABASE也可以但我建议始终显式指定避免你这个账号的默认库被改掉之后代码还浑然不知。连接串里还能加Connection Timeout和Login Timeout等参数单位是秒。比如Connection Timeout5如果网络本身有问题你希望快速失败而不是傻等30秒这个参数就很有用了。3.3 Encrypt和TrustServerCertificate是重灾区ODBC Driver 18就把默认的加密行为改成了强制加密。也就是说只要你的SQL Server没有配置受信任的证书而你又在连接串里没做特殊处理连接会直接失败报错信息大概内容是关于证书链的信任问题。解决方案很简单在连接串里加上TrustServerCertificateyes;。它的意思是我信任这台服务器自己签发的证书即使证书链验证不过去也继续连。很多开发者在本地测得好好的部署到生产发现连不上多半就是这个证书参数逻辑和生产环境的证书配置不一致。如果你的环境里有人要求你把Encrypt设置为no你需要知道这是在关闭加密传输安全性会降低不建议在不可信网络上这样做。3.4 Windows认证和账号密码认证怎么选连接SQL Server有两种常规认证方式。一种是SQL Server账号认证连接串里写UID和PWD另一种是Windows集成认证连接串里使用Trusted_Connectionyes或Integrated SecurityTrue字段不写账号密码直接用运行Python进程的当前Windows身份去和数据库校验。Windows集成认证比较常见于企业内部脚本好处是不用把密码写进代码里但坏处是部署到Linux服务器之后这种认证通常就不灵了因为你没有域环境、没有Windows票据。跨平台项目就老老实实用账号密码认证把密码放在环境变量或密钥管理服务里不要硬编码到代码中。3.5 连接串里的引号与转义值得单独强调很多刚上手的朋友会困惑为什么连接串要写成r字符串或者为什么要用一对括号把几段字符串拼起来。原因就在于连接串本身包含分号和一对大括号如果你在一个普通字符串里使用这些字符Python的转义规则会给你带来不少麻烦。我个人习惯用rDRIVER{...};这种片段拼起来。r代表原始字符串反斜杠不会被转义而当你有SERVERhost\instance这类值的时候这个r前缀就极其重要。另外不要在连接串里使用中文标点那个分号必须是英文分号驱动名里的大括号也必须是英文大括号。这种低级错误在评论区里出现过不止一次。4. 完整实操从建库建表到增删改查4.1 先准备一张测试表我们先用SQL Server的SQL编辑器或脚本创建一个最简单的表用来演示Python读写。如果你已经有表了跳过这一步。CREATE DATABASE testdb; GO USE testdb; GO CREATE TABLE dbo.users ( id INT IDENTITY(1,1) PRIMARY KEY, username NVARCHAR(50) NOT NULL, email NVARCHAR(100), created_at DATETIME2 DEFAULT SYSDATETIME() );这里有一点要注意在SQL Server里NVARCHAR比VARCHAR更适合存中文等Unicode字符因为NVARCHAR按UTF-16存储能够覆盖全部字符集。即使你的库的默认排序规则支持中文用VARCHAR依然可能在某些边界场景下出现乱码所以直接养成用NVARCHAR的习惯。4.2 写一个能复用的查询封装连接数和查询逻辑分开对后续维护非常有帮助。我经常写这样一个简单的函数封装一个函数负责拿到连接对象另一个函数负责执行查询并返回结果。实际项目中你不一定需要精简到这种程度但基础结构是这样的。import pyodbc def get_connection(): conn_str ( rDRIVER{ODBC Driver 18 for SQL Server}; rSERVERlocalhost,1433; rDATABASEtestdb; rUIDsa; rPWD123456; rTrustServerCertificateyes; ) return pyodbc.connect(conn_str) def fetch_users(): with get_connection() as conn: cursor conn.cursor() cursor.execute(SELECT id, username, email FROM dbo.users ORDER BY id) rows cursor.fetchall() return rows if __name__ __main__: for row in fetch_users(): print(row.id, row.username, row.email)pyodbc游标返回的行对象支持按列名访问也支持按索引访问。在字段多且你记不住顺序的情况下按列名访问更直观。这里我还用了with语句去管理连接pyodbc连接对象在退出with块时会自动关闭这是避免连接泄漏最省心的方式。4.3 参数化查询SQL注入是个真实存在的坑有人觉得参数化查询只是安全要求不重要。实际上参数化查询还能帮助你规避SQL语句拼接时的类型转换和引号转义问题。比如你要插入一个用户名它本身就包含单引号如果你用字符串拼接SQL这会导致语法错误让你怀疑人生。正确的做法是往execute里传第二个参数也就是参数元组或字典让驱动去处理转义和类型转换。def add_user(username, email): with get_connection() as conn: cursor conn.cursor() cursor.execute( INSERT INTO dbo.users (username, email) VALUES (?, ?), (username, email) ) # 这里注意pyodbc的execute并不一定自动提交 conn.commit()有一个细节必须说明pyodbc连接对象的autocommit默认是False。也就是说你执行INSERT、UPDATE、DELETE之后必须显式调用conn.commit()数据才会真正落库。如果你没有commit然后你发现查询数据是空的请默认先怀疑这一点别去怀疑什么灵异事件。当然如果你在创建连接时传了autocommitTrue那就不用手动commit了但这种模式下每个语句都会立即提交出了错不好回滚生产环境不太建议。4.4 动态条件查询同样用参数化很多场景下你需要根据用户输入动态生成条件。比如筛选邮箱包含某个关键词的用户。这里的误区是把用户输入直接拼进SQL字符串正确做法还是用参数化。def search_users(keyword): with get_connection() as conn: cursor conn.cursor() cursor.execute( SELECT id, username, email FROM dbo.users WHERE email LIKE ?, (f%{keyword}%,) ) return cursor.fetchall()如果你要动态拼接WHERE条件本身比如根据前端勾选哪些字段来决定过滤哪个列那就需要把列名白名单化即只有在你自己预设的允许列表里的字符串才允许作为列名拼接进去而作为比较的值一律走参数。这样做既灵活又不会引入注入风险。过滤条件值走参数过滤列名走白名单这两条分工保持好基本就能杜绝SQL注入。4.5 事务控制的正确姿势事务是开发中绕不开的话题。如果你需要多个写操作要么同时生效要么全部回滚可以用pyodbc的commit和rollback来显式控制。def batch_create_users(user_list): with get_connection() as conn: cursor conn.cursor() try: for username, email in user_list: cursor.execute( INSERT INTO dbo.users (username, email) VALUES (?, ?), (username, email) ) conn.commit() except Exception as e: conn.rollback() raise这里有个容易忽略的坑如果连接断开了你调用conn.rollback()也可能报错因为底层连接已经失效。严谨的做法是先把操作完整执行完再统一提交遇到连接层面的异常时直接抛出因为此时回滚也可能失败。另外事务不要开太久所有操作完成后尽快commit避免长时间持有行锁锁太长会导致别人更新同一张表时被阻塞。SQL Server的默认隔离级别下锁这个东西很容易在那些看起来能跑、但事务特别长的业务代码里悄悄积累成性能事故。5. 高频报错实录这些错我基本都踩过这一节按实际经验整理出最常见的报错场景、原因和解决路径。你可以直接对照你的错误信息快速定位。5.1 ODBC Driver 18 for SQL Server not found这个报错翻译成大白话就是系统里根本没有这样的驱动或者驱动名写得不匹配。先检查驱动名里的大小写、空格有没有和已安装驱动完全一致。然后在Python里运行pyodbc.drivers()看输出内容是否包含你连接串里写的那个驱动名。如果这个函数返回空列表说明pyodbc可能装到了不同的环境或者系统根本找不到odbc相关配置。在Linux上还要检查一下unixODBC是否安装完整。我遇见过的实际案例里有人用conda创建了虚拟环境但conda的pyodbc和系统unixODBC版本对不上最后在conda环境里重新安装并验证才解决。5.2 Login failed for user sa这个报错有两种常见情况。第一种是密码真的错了检查一下密码里有没有特殊字符比如分号或大括号在连接串里这些字符会干扰解析。第二种是SQL Server开启了Windows身份验证模式不允许sa直接登录。你可以让数据库管理员把服务器身份验证改成SQL Server和Windows身份验证模式并确保该账号启用了。如果密码里确实有特殊字符且不好改我建议把密码放到环境变量或配置中心然后从配置系统读取后再组装连接串读取时注意不要引入多余的空格。我需要特别提醒一下不要在代码里写死密码这个习惯养成之后对团队协作和安全审计都有好处。5.3 The certificate chain was issued by an authority that is not trusted这一条我在前面已经说了不少。它本质上是因为SQL Server使用了自签名证书或证书不匹配而ODBC Driver 18默认要求验证证书。解决方式就是在连接串里加TrustServerCertificateyes。如果你已经加了还报错那就需要确认连接串里这段配置是否真的被代码读取到了有没有被拼错成TrustServerCertificat。另外有些旧项目里看到别人的代码写Encryptno但新驱动里Encryptno并不一定真的能完全关闭加密因为驱动可能忽略这个设置。所以我建议使用TrustServerCertificateyes而不是Encryptno。5.4 TCP/IP connection to host failed 或 Timeout expired这个报错需要分层次排查。先确认服务器端口是否可达用telnet或者nc命令测一下host和1433端口。如果端口不通要么是防火墙拦截要么是SQL Server没监听这个端口。如果端口通再确认实例名或端口是否写对尤其是用host,port格式的时候不要误把端口写成分号分隔。在云主机或容器里部署时还要注意SQL Server所在的容器可能需要映射端口并且容器内的实例可能配置了非默认端口这时候连接串里的端口要写映射后的外部端口而不是容器内部的监听端口。这个问题在Docker部署环境中出现相当频繁。5.5 Cannot open database xxx 或 Invalid object name dbo.xxx如果提示Cannot open database那说明连接本身没问题但这个账号在目标库里没有权限或目标库不存在。先登录数据库检查库名是否写错再检查账号有没有访问权限。如果提示Invalid object name可能是你连接时选了别的数据库导致用户在当前库里找不到这张表。这个时候要回到连接串检查DATABASE参数或者在SQL语句里显式写上数据库名加表名的完整写法。5.6 中文乱码问题乱码问题的根源通常在字符集与排序规则。对于SQL Server一个稳妥的建议是建表字段用NVARCHAR类型连接时再设置一下代码页相关选项。在pyodbc连接串里可以尝试加一个字符集参数吗严格来说pyodbc本身的连接串里没有直接指定客户端字符集的通用办法但你可以在SQL层面用SET NAMES之类的方式吗SQL Server没有这套机制。所以重点放在数据库排序规则、字段类型、以及写入前确认字符串在Python侧的编码格式是unicode。实际操作中更推荐的路径是把Python文件保存为UTF-8代码里所有字符串变量都用unicode字符串对象数据库字段用NVARCHAR。这样能覆盖绝大多数中文使用场景。如果从SQL Server读出来再到控制台打印乱码那不是数据乱码是控制台编码问题Windows控制台用chcp 65001切换到UTF-8才能正常打印。数据本身是好的别因为打印乱码而误判成数据库乱码。6. 进阶一点批量写入、连接池与日常性能细节6.1 executemany并没有想象中那么完美很多人想批量插入的时候第一反应是用cursor.executemany。它的好处是API简洁代码量少。但它底层仍然是一条一条地执行参数化SQL所以在大批量场景下性能提升有限。如果你一次要插入上万行数据executemany可能比单条逐条快但和真正的批量插入方案相比还是偏慢。另一个思路是在SQL层面使用多个VALUES元组拼接的INSERT语句。你可以自己用SQL字符串拼接参数位然后通过参数化把所有值传进去。这种方式能大幅减少SQL语句的解析开销。比如一次插入100条每条有3个字段就在一个INSERT语句里拼出100个VALUES元组参数数量是300个。SQL Server对单个INSERT语句能处理的参数个数有限制所以一次拼到几百条是比较稳妥的做法。如果要走更安全更省代码的路子可以用临时表配合批量导入但那样做你又会引入额外的表结构和数据流程复杂度不一定适合所有场景。6.2 用pandas和SQLAlchemy几行做批入表做数据分析的人可能更习惯pandas。pandas的to_sql方法可以配合SQLAlchemy的mssqlpyodbc引擎把DataFrame直接写入SQL Server。这种方式最方便但你要先安装pandas、sqlalchemy、pyodbc并且自己拼好SQLAlchemy的连接URL。连接URL的例子大概长这样。from sqlalchemy import create_engine import pandas as pd url ( mssqlpyodbc://sa:123456localhost:1433/testdb ?driverODBCDriver18forSQLServer TrustServerCertificateyes ) engine create_engine(url) df pd.DataFrame({ username: [user_a, user_b], email: [aexample.com, bexample.com] }) df.to_sql(users, engine, if_existsappend, indexFalse)这里有一点要注意URL里的driver参数中空格需要写成加号或转义后的字符因为URL本身有自己的保留字符规则。to_sql默认可能会尝试创建一个名为users的表如果表已存在就要用if_existsappend来避免覆盖。这个方法对数据量不大的批量写入非常友好代码量少出错的概率也低值得作为日常数据灌入的首选方案之一。6.3 自己实现一个轻量连接池pyodbc本身不提供连接池功能但DB-API 2.0标准下的连接对象并不总是线程安全的。如果你的应用是多线程的每个线程最好使用独立的连接对象而不要共用一个连接。如果应用有较高并发每次请求新建连接又会带来额外开销所以很多人会自己实现一个简单的连接池。实现思路不复杂用一个队列保存一定数量的现成连接队列空的时候创建新连接用完放回队列同时定期检查连接是否有效。业界也有好用的第三方库比如DBUtils提供的PooledDB。如果你不想引第三方依赖自己写一个不少于基础的队列版本也很容易但要注意连接失效后会变得非常隐蔽。比如数据库重启了池里存的旧连接其实已经断了你需要在使用前ping一下或者捕获到连接不可用错误时重建连接。这个坑在实际运维中经常出现。6.4 日常性能细节与习惯建议几个看起来不起眼但影响很大的习惯。第一查询尽量只取需要的列不要动不动就SELECT *。SQL Server在大表上的IO开销很真实少取一列在某些窄表上百条可能无所谓但在宽表上万行时差距会非常明显。第二大量只读查询时把连接的autocommit设为True避免每次查询后都在隐式事务里多绕一圈。第三所有的批量写操作尽量在同一个事务里提交但要注意控制批量大小一次性提交太多数据会在日志和锁层面产生不小的压力。我在日常使用中把连接创建成本高这个点完全接受了之后就会下意识地在写普通脚本时复用同一个连接而不是在每个函数里都新建一个连接再关闭。虽然连接开销在本地测试时好像感觉不到但在真实的生产网络环境中每次握手都意味着一次往返延迟连接多了延迟就像滚雪球一样滚起来。写在最后的几句经验这套流程我从最初照着文档装驱动、被证书报错卡住到现在已经能在新环境十分钟内配好并跑通中间花掉最多时间的环节几乎都是环境验证和参数匹配这一类基础问题。对于刚入手的朋友我建议按这个顺序排查问题先确认驱动已装且能被pyodbc检测到再确认端口能连通然后用命令行工具测试数据库账号认证最后才排查Python代码和连接串的细节。顺序反了你就会在一个隐藏很深的参数转义问题里浪费很多时间。另外每次换一台新电脑或者新部署环境时不要凭记忆敲连接串。先运行pyodbc.drivers()确认驱动列表再从环境变量读取服务器地址和密码。无论写脚本还是写应用都尽量把配置和代码剥离连接参数不该出现在代码仓库里。最后分享一个小技巧如果你实在被某种报错卡得百思不解不要只看报错里最后一行。把异常对象完整打出来打印完整的异常信息经常能发现前面有别的细节在提示你真相。我自己就遇到过因为报错提示太像密码错误结果实际是驱动名被拼错的诡异情况。技术问题往往不是玄学多打印一层信息答案就出来了。