要想充分发挥ADONET的优势不仅需要全面深入理解ADOnet编程模型及时总结经验技巧也十分重要ADO已经有多年的实践经验ADONET以此为基础提供了更加丰富强大的工具尽管如此ADONET的设计目标毕竟不是提供一个即插即用的工具它不会把所有的编程工作简化到仅靠鼠标点击就可以完成的程度
ADONET包含了一大堆代表数据访问模型中各种逻辑实体的对象其中尤以连接事务这两个对象最为重要连接的作用是建立一个与后端数据库通信的通道创建连接对象必须以特定的NET数据提供者为基础事务对象可以在已有的连接对象上创建也可以通过显式地执行一个BEGIN TRAN SQL语句创建虽然理论很简单但实际上围绕连接事务的不确定因素很多而且它们对应用整体的稳定性和效率有着至关紧要的影响
如何保存连接字符串保护连接字符串中可能包含的敏感信息(例如密码)?怎样设计一个完善的数据访问策略既考虑到安全性(即身份验证授权)却又不至于对性能和可伸缩性造成太大的影响?如果需要用到事务那么如何高效地实现和控制事务?采用自动事务还是手动事务?在使用ADONET时这些问题都必须仔细考虑
一连接字符串连接池
数据库连接是一种重要的有限的开销昂贵的资源因此用好连接对象是任何应用的最基本的要求使用数据库连接的要点可总结如下
保存连接字符串应注意安全
打开连接应迟关闭连接应早
连接字符串是访问数据库的钥匙连接字符串除了说明要访问的数据之外还包含了用户为什么可以访问那些数据的身份证明在执行数据库操作时用户身份证明是确定数据访问权限的最重要的因素
保存连接字符串
目前硬编码的连接字符串具有最好的性能因为它们直接编译进了应用的代码之中然而硬编码的字符串影响程序的灵活性一旦连接字符串改变应用程序必须重新编译
将连接字符串保存到外部提高了灵活性代价是访问外部字符串需要付出额外的开销但在绝大多数情况下由此导致的性能开销可以忽略不计真正需要担心的是安全问题例如攻击者可能修改窃取连接字符串将连接字符串保存到外部环境的常见途径有配置文件UDL文件Windows注册表
NET框架配置文件以纯文本文件的形式部署访问方便如果连接字符串包含密码文本格式将是最大的缺陷所在因为密码将以明文的形式保存可以考虑引入一个专用的加密/解密引擎不过这部分工作需要开发者自己完成
UDL文件是供OLE DB提供者使用的文本文件也就是说SQL Server托管提供者不支持UDL文件UDL文件也存在和前面的配置文件一样的安全问题总地看来优势不多
最后Windows注册表可以作为一个天然安全的存储场所注册表是一个保存关键信息的系统知识库如果结合运用加密技术可以达到较高的安全性使用注册表的主要缺点是部署麻烦要求创建注册键(可能还要执行加密)以及从注册表读取数据虽然NET Framework提供了一组调用底层Win API的封装类但这些类都没有提供加密功能ASPnet_setregexe工具可以用来创建HKEY_LOCAL_MACHINE下的注册键保存用户名称和密码例如aspnet_setregexe k Software\MyData u:userID p:password该命令将加密指定的用户ID和密码
连接池原理
连接池允许我们通过一个缓沖池重用现有的连接对象避免每次使用连接对象时都要新建一个对象采用连接池之后只要少量的连接对象就可以满足大量客户端的需要
每一个连接池都与一个独立的连接字符串及其事务上下文关联每次打开一个新的连接数据提供者会尝试将指定的连接字符串与连接池的字符串进行匹配如果匹配失败数据提供者创建一个新的连接并将它加入连接池连接池被创建之后除非进程结束否则不会被拆除有人认为这种处理方式会影响性能其实不然维护一个不活动的或者空的连接池不需要多少开销
连接池创建之后系统会创建一些连接对象并将它们加入连接池直至达到额定的最小连接对象数量以后系统会根据需要新建和加入连接对象一直到达最大连接对象数量限额为止如果程序请求一个连接对象时没有空闲的连接对象可用且连接池里面的对象数量已达到上限则请求被放入队列一旦有连接被释放回缓沖池就立即取出使用
避免用编程的方式构造连接字符串如果通过合并多个输入数据的方式构造出连接字符串很容易给注入式攻击以可乘之机如果必须用到用户输入的数据务必进行严格的验证
关闭连接
关闭一个连接时连接对象被返回给连接池以便重用但这时实际的数据库连接并未被拆除如果禁用了连接池则实际的数据库连接也被关闭这里必须强调的一点时连接对象使用完毕后应当显式关闭并将它返回给连接池不要依靠垃圾收集器来释放连接实际上当连接对象的引用超出有效范围时连接不一定被关闭——垃圾收集器的功能是拆除代表物理连接的NET封装对象但这并不意味着底层的连接也被关闭了
调用Close或Dispose方法可以将连接释放回连接池只有当生存期结束或出现严重错误时连接对象才会被从连接池删除
连接池与安全
如果一个应用程序的所有数据访问操作都使用同样的连接字符串连接池的优势将发挥到极限但是这只是一种理想化了的状况很可能与应用程序的其他要求存在沖突例如如果只使用一个连接字符串要在数据库这一层次上执行安全控制就很困难了
另一方面如果让每一个用户分别使用自己的连接字符串(即为每一个用户分别设定数据库帐户)势必出现大量小型的连接池许多连接根本不会被重用依照惯例这类问题的最佳解决方案是寻找两个极端之间的一个适当折衷点我们可以设置一组具有代表性的公用帐户同时修改存储过程使之接受一个表示用户标识的参数存储过程根据传入的用户标识执行不同的操作
二事务模式
分布式企业应用离不开事务在数据访问代码中加入事务管理功能主要有两种方式手动方式自动方式
在手动方式中程序员负责编写所有配置使用事务机制的代码自动(或COM+)事务则在net类中加入声明式属性指定运行时对象的事务特性自动方式方便了将多个组件配制成在同一个事务之内运行两种事务方式都支持本地的或分布式的事务但自动的事务方式极大地简化了分布式事务处理
必须注意的是事务是一种开销很大的操作所以决定使用事务之前务必再三考虑如果确实需要使用事务那就要尽量缩小事务的粒度减少对数据库的加锁时间加锁范围例如对于SQL Server单个的SQL语句不需要显式地声明事务SQL Server会自动将每一个语句作为一个独立的事务运行手动的本地事务总是比其他事务快得多因为它不需要涉及DTC(Distributed Transaction Coordinator)
手动事务自动事务应当视为两种不同的互斥的技术如果要在单个数据库上执行事务性操作优先考虑手动事务当单个事务跨越多个远程数据库或单个事务涉及多个资源管理器(例如一个数据库和一个MSMQ资源管理器)优先考虑自动事务不管怎样应当极力避免混合运用两种事务模式如果性能不是特别重要即使只对一个数据库操作也可以考虑使用自动事务使代码更加简洁(但速度略慢)
总而言之要提高数据库访问代码的质量必须深入了解ADONET对象模型根据实际情况灵活运用各种技巧ADONET是一个公用的API各种应用——不管是Windows窗体应用ASP页面还是Web服务都可以通过ADONET访问数据库但是ADONET不是一边接受输入一边吐出结果的黑箱而是一个由许多工具组成的工具箱