第13讲:深入ADO.NET开发—高级数据访问技术

2005.4.8 付仲恺

基础预习

熟悉Microsoft ADO.NET

了解Web Services基础开发

了解.NET文件集操作

 

议题

并发问题

连接池

事务

可抽取的数据访问层

 

并发性问题

在可断开连接架构中必须要面对并发问题

当两个(或多个)用户获取并修改相同的记录,然后试图同时维持各自的修改时,将会发生冲突:脏读u,不可重复读,虚幻读

当提交多个更新的时候,会造成部分更新无法正确完成

悲观与乐观(ADO.NET构建)并发锁

悲观锁:无论读写都加锁

乐观锁:只有写加锁,读不加锁(ADO.NET)

 

ADO.NET中对并发性问题的处理

与DataAdapter对象相连接的DataSet对象使用乐观锁来处理记录内容冲突

DataAdapter配置向导能够修改Update和Delete语句以检测是否发生了并发问题

当ContinueUpdateOnError为false(缺省值)时,在发生第一个冲突的时候会抛出DBConcurrencyException异常

无论是true还是false,对于有并发性问题的数据行都会取消更新操作,它们之间的不同是为true时还会更新其它行,为false时会马上抛出异常。

捕获该异常并且通知用户,或者处理该异常或提示用户下一步需要做出哪些选择

 

演示一

处理并发性问题

image

image

先同时打开两个窗体,都Load出一样的数据,然后修改左边的1,2行数据保存后,修改右边的1,2行数据,这时就会抛出并发性错误的异常,并且显示0行被改变,也就是没有完成更新。

image

image

它只对于第一个并发的问题弹出对话框,而对于第二个并发问题并没有提示错误,因为它一旦抛出异常,就不会对后面的数据进行操作了。

另一种演示是把ContinueUpdateOnError的属性设置为True,然后进行更新。GetErrors()方法能获取出产生冲突的数据行。

image

image

左边更新了3行数据,右边更新了3行数据,其中有两行数据有并发冲突。

image

结果并没有抛出异常的对话框,并且没有发生并发性冲突的更新会更新成功。

 

连接池

连接池可以极大地提升性能和可扩展性

避免由创建连接所带来的大量消耗

通过在连接字符串中添加以下属性来调节连接池

Pooling=true;Max Pool Size=5;Min Pool Size=3;

上面的字符串将打开连接池,并且确保在连接池中至少存在着3个连接,并且最多为5个连接

当达到最大连接时,打开新连接的请求将排队一段可配置的时间

默认等待时间15秒,如果超过15秒还未获得连接,就会抛出超时异常。

当使用OleDbConnection时,如果要关闭连接池在连接字符串中添加"OLE DB Services=-4"

 

注意

连接是通过对连接字符串精确匹配的法则被池化的。池化机制对名称-值对间的空格敏感

例如,下面的两个连接字符串将生成单独的池,因为第二个字符串包含了一个额外的空字符。

"Integrated Security=SSPI;Database=Northwind"

"Integrated Security=SSPI ;Database=Northwind"

Close方法将连接放回连接池

Dispose方法则直接销毁连接,而不放回到连接池中

 

演示二

连接池

image

简单连接池,最后没有Close是为了演示查看连接池中的连接。打开SQL Server管理器,能看见连接池中的三个等待激活的链接。

image

高级连接池,创建多线程调用Go方法,启动线程并让线程等待。

image

image

image

image

排队超过15秒,抛出超时异常

image

我们可以通过修改连接字符串调大超时时间或者调大最大连接数

image

50个线程不停地获取SQL版本号,其中每个线程执行100次,所有线程都执行完之后,共会获取5000次SQL的版本号信息。

image

使用连接时我们不到万不得已不要打开连接,打开连接后也应该及时关闭它。

 

事务

ACID原则:原子性,一致性,隔离性,持久性

事务行为要么完成所有动作,要么不做任何动作

同时提交或者回滚所有的修改

不是所有的SQL语句都允许出现在事务中

例如创建数据库的操作、修改表的操作,是不允许出现在事务中的

ADO.NET事务只能应用于单一连接中

SqlTransaction对象从SqlConnection.BeginTransaction()方法中返回

 

SqlTransaction类

SqlTransaction trans=conn.BeginTransaction();

实例化事务对象

隔离级别枚举(IsolationLevel):Chaos,ReadCommitted,ReadUncommitted,RepeatableRead,Serializable,Unspecified

Serializable是最高级别的隔离

隔离级别越高,越能更好处理并发性问题。ADO.NET默认使用ReadCommitted级别的隔离。

处理工作:Insert,Update,Delete

要么提交所有的修改:trans.Commit();

要么如果发生错误,撤回所有的修改:trans.RollBack();

 

隔离级别

image

Serializable提供了最高的隔离级别,但却只有最低的执行效率

Serializable是序列化的方式,也就是以串行的处理方式一个挨一个进行访问,所以效率最低。

 

演示三

本地事务操作

image

image

 

高级事务

为了执行跨数据库事务,需要通过System.EnterpriseServices向分布式事务协调器(DTC)注册链接

分布式事务也能进行本地化操作,但是它会相对有较大的开销,因为本地事务处理不需要与分布式协调器进行交互。

在中间层Web服务上添加:System.EnterpriseServices.Transaction属性

TransactionOption枚举:Disable,NotSupported,Required,RequiresNew,Supported

TransactionIsolationLevel枚举:Chaos,ReadCommitted,ReadUnCommitted,RepeatableRead,Serializable

Serializable是最高级别的隔离

连接字符串中的Enlist项表明连接是否参与到事务操作中

为true表示参与事务操作

当连接字符串中Enlist=false时,可以调用SqlConnection.EnlistDistributedTransaction方法以执行事务操作

 

对分布式事务的控制方法

使用AutoComplete属性对方法进行注释。如果方法正常执行完毕,则自动提交事务,而如果发生异常则自动执行回滚操作

调用ContextUtil类的静态方法SetComplete或SetAbort来实现事务提交和回滚操作

 

演示四

跨数据库事务

image

要使用COM+事务需要添加EnterpriseServices引用。

image

image

image

image

方法上加了标签,表示需要执行事务的操作。方法的最后会抛出一个异常,让事务自动回滚。只有中间的Enlist为false且没有调用EnlistDistributedTransaction方法的操作不会回滚,其它都会随事务回滚。

 

使用事务的注意事项

在一组操作中,只有在需要保证ACID特性时才使用事务

降低事务的粒度,以最小化维持数据库锁的时间

不要为单个SQL语句使用事务处理。SQL Server自动把每个语句作为单个事务处理执行

 

层次化应用程序架构

多层应用程序将代码分为不同的逻辑代码层

非常普遍的设计方案是3层架构设计:表示层,业务逻辑层和数据访问层

合理的层次化设计带来了很多益处:代码复用,可扩展性,封装性,松散的耦合性,高聚合性

我们能够设计一个可抽取的数据访问层来完全抽象数据存储

 

层次化应用程序架构——概念

image

3层是在逻辑上划分的,在物理上不一定要按这种严格的划分。

 

数据访问层——概念

位于应用程序的业务逻辑与数据存储之间的代码层

包含了应用程序所有的数据访问代码;提供CRUD操作函数

业务逻辑层只与数据访问层有松散的耦合关系

 

可抽取数据访问层

可抽取数据访问层为应用程序提供良好的可扩展性

设计可抽取数据访问层可以很容易地修改,更新,数据存储而不需要重新编译其它层

通过接口实现松耦合度

通过基于接口的工厂模式以实现可抽取组件

将数据访问层从业务逻辑层中完全抽象出来

 

基于接口的编程——概念

接口类似于合同

基于接口的编程消除了从实际代码中实现的方法的耦合性

提供了多态机制

实现“可抽取”组件

 

可抽取组件——概念

.NET允许通过Assembly.Load()以及Assembly.CreateInstance()来动态加载文件集和类

通过配置指向具体的数据访问层类

“新的”或者“改进的”(不同)组件可以“插入”到现存的应用程序中

不需要从新编译那些依赖接口的代码

非常低的耦合意味着极大的可扩展性

 

演示五

可抽取数据访问层

image

image

GetDaL是数据访问层,它根据传入参数,动态加载文件集创建对应实例

image

imageimageimage

这三个接口的实现其实都是组件。我们把三种不同颜色访问的方法抽象成了IDaL的接口,业务逻辑层并不需要关心是访问哪一个对象或者组件,它只需调用GetDaL即可获取对应颜色。

 

总结

并发问题是在可断开链接数据模型中必须要处理的问题

连接池能够改进性能和扩展性

事务确保数据的更新的原子性,持续性,隔离性和持久性

可抽取数据访问层是通过松耦合实现可扩展性的强有力的方法

2010.10.22

posted @ 2010-10-23 00:30  山天大畜  阅读(4092)  评论(0编辑  收藏  举报