游客发表
WCF Web Server 和数据库之间的数据关系,很多人第一次接触时容易搞混。数据WCF 本身不存数据,数据它只是数据把数据从一端搬到另一端。真正的数据存储要靠 ADO.NET 或 Entity Framework 去连 SQL Server、MySQL 或者 Oracle。数据我见过一个项目,数据服务端用 WCF 暴露了二十多个接口,数据每个接口背后都在操作同一个数据库,数据结果并发一上来,数据连接池直接爆掉。数据
那会儿我们用的数据是 `basicHttpBinding`,图它兼容性好,数据客户端什么都能调。数据问题是数据这个绑定默认不开事务流,数据库那边一旦有多个表的写入操作,中间失败就回滚不干净。后来换成 `wsHttpBinding` 加 `TransactionFlow`,才把订单和库存的写入绑到一个事务里。代价是配置复杂度翻倍,`web.config` 里光绑定配置就写了八十多行。
数据库连接字符串放在 WCF 服务的 `web.config` 里,这个做法本身没问题。但有人图省事,直接把连接字符串硬编码在 `.svc.cs` 文件里。换测试环境的时候,得重新编译整个服务。我接手那个项目时,第一件事就是把连接字符串抽到配置文件,再用 `ConnectionStringSettings` 读出来。省事多了。
WCF 服务操作数据库,最怕的是长连接。有个同事写了个查询,`SqlConnection` 打开之后忘了关,只在 `Dispose` 里处理。平时访问量小,看不出问题。上线第三天,数据库连接数冲到五百多,SQL Server 直接拒绝新连接。排查了一下午,最后用 `using` 包起来才解决。这种坑,文档里不会写,只有踩过才知道。
并发控制也是个麻烦事。WCF 默认的实例化模式是 `PerCall`,每个调用创建一个服务实例。听起来很干净,但数据库那边不一定扛得住。我们有个统计接口,每次调用都要扫一遍百万行的表。`PerCall` 模式下,十个并发请求就是十次全表扫描。后来改成 `Single` 加 `ConcurrencyMode.Multiple`,再配合数据库的查询缓存,才把 CPU 压下来。不过 `Single` 模式要小心状态管理,服务实例里的字段会跨调用共享,不小心就串数据。
数据传输对象的设计也影响数据库性能。有人喜欢把整个 `DataTable` 直接序列化返回。`DataTable` 的 XML 序列化体积大得离谱,一个一千行的结果集,序列化后能到几兆。客户端反序列化再解析,慢得让人想砸键盘。后来我们全部改成 `List<T>`,T 是简单的 POCO 类,体积缩小到原来的十分之一。数据库那边也配合,只 `SELECT` 需要的列,不用 `SELECT *`。
异常处理要特别小心。WCF 默认会把 .NET 异常直接抛给客户端,包括 `SqlException` 的详细信息。这等于把数据库结构、表名、甚至连接字符串的一部分暴露出去。正确的做法是捕获 `SqlException`,包装成 `FaultException`,只返回一个通用的错误码。客户端拿到错误码去查日志,而不是直接看到“列名 ‘user_password’ 无效”这种消息。
还有个细节:WCF 的 `maxReceivedMessageSize` 默认是 65536 字节。数据库里如果有 `varchar(max)` 或者 `text` 字段,稍微大一点的数据就传不过去。报错信息是“已超过传入消息的最大消息大小配额”,新手根本看不懂。改配置就行,但得知道改哪里。`binding` 节点下加 `maxReceivedMessageSize="10485760"`,十兆应该够用了。
数据库连接池的配置也值得说一句。默认最大池大小是 100。WCF 服务如果并发高,100 个连接很快用完。但盲目调大也不对,SQL Server 那边每个连接都要占内存。我们最后设成 200,配合 `Connect Timeout=30`,基本够用。监控的时候看 `NumberOfActiveConnections` 和 `NumberOfPooledConnections` 两个性能计数器,比猜靠谱。
说到底,WCF Web Server 和数据库的配合,核心就一句话:服务层管通信,数据库层管存储,中间的连接、事务、并发、异常,每一样都得手动处理好。框架不会帮你兜底。
友情链接