明朝疆域面积变迁:8.1.3 数据应用类(1)

来源:百度文库 编辑:偶看新闻 时间:2024/04/29 20:11:03

8.1.3 数据应用类(1)

最后,还需要应用类来执行实际的数据库操作。该类使用在前一节列出的存储过程。

这里,数据应用类命名为EmployeeDB。它封装了所有数据访问代码以及数据库相关的细节。下面是详细的代码:

 

注解

你可能已经注意到了,EmployeeDB类使用了实例方法而不是静态方法。这是因为,尽管EmployeeDB类不保存任何数据库的状态信息,但它确实用私有成员变量保存了数据库连接字符串。因为这是一个实例化的类,连接字符串可在每次类创建的时候而不是在每个方法调用的时候获得,这样做可使代码稍微清晰一些,运行也稍微快一些(避免了多次读取web.config文件)。不过它带来的好处实在微不足道,你一样可以在数据库组件中方便地使用静态方法。

每个方法都采用同样的实现方式,完全可通过存储过程和数据库交互。下面是插入记录所需的代码,假定你已经导入System.Data.SqlClient命名空间:

 
如你所见,该方法使用EmployeeDetails数据对象接受数据。所有错误都会被捕获,内部敏感信息不会返回到网页的代码中,这就避免了网页提供一些可能会被利用的信息。报告详细错误的理想地方是日志文件或者其他数据库,可以调用日志组件中的某个方法来这么做。

GetEmployee()和GetEmployees()分别通过EmployeeDetails对象和Employee Details对象列表返回数据:

 

 

 

 

UpdateEmployee()方法的角色比较特殊。它决定了数据库组件的并发访问策略(可参考下一小节的内容)。

下面是代码:

 
最后,DeleteEmployee()方法和CountEmployees()方法完成了我们所需的全部功能:
  

8.1.3 数据应用类(2)

并发策略

所有的多用户应用程序,包括Web应用程序,都存在多个用户同时执行查询和更新的可能。这会产生潜在的混淆状况,即当出现两个用户同时拥有某一行的状态时,他们会试图提交不同的更新。第一个用户的更新总会成功,而第二个用户的更新成功还是失败就要看你的并发策略了。

有几个主要的并发访问管理方法。理解并发管理最重要的一件事是并发策略由UPDATE命令和DELETE命令的写法决定(尤其是WHERE子句的形式)。

以下是最常用的例子。

后到者胜出更新。这是不太严格的并发控制,它总是提交更新(除非原始行已被删除),每次更新提交后,值总会被更新。如果数据冲突比较少,后到者胜出会很有用。例如,当只有一个人负责更新一组特定的数据时,就可以放心地采用这个方法。通常,实现后到者更新方法时,WHERE子句通过记录的主键与要更新的记录匹配。前面示例中的UpdateEmployee()方法使用的就是后到者胜出的方式:

 完全匹配更新。实现这个策略时,UPDATE语句需要使用所有你要设置的值以及所有的原始值。使用原始值可以构建WHERE子句找到原始记录。这样即使只有一个字段值被修改了,记录也不会匹配,更新也就不会成功。这种方式的一个问题是相兼容的更新也被禁止。例如,两个用户同时更新同一记录的不同部分,尽管没有任何冲突,第二个用户的更新也会被拒。另外一个更为显著的问题是应用完全匹配的更新策略会导致冗长、低效的SQL语句。你可以使用时间戳更有效地实现等效策略(参见下一条)。
 

基于时间戳的更新。大多数数据库系统支持时间戳列,它是由数据源在记录有更新时自动更新的。你不需要手工更新时间戳。不过,你可以查看时间戳的变化以确定其他用户最近是否更新了记录。但是,如果在执行SELECT语句时获取它,可以在UPDATE语句中使用WHERE子句,那样就可以保证只在它没有被更新时更新记录,这和完全匹配更新的效果一样。不像完全匹配更新,WHERE子句更加简洁、有效,因为它需要两条信息--主键和时间戳。

变化的值更新。这种方式尝试在UPDATE命令中只更新变化了的值,因此,只要用户同时更新的是不同的字段,它就允许两个用户同时做改动。问题是这种方式会很复杂,因为需要追踪哪些值变化了(要放到WHERE子句中)哪些值没有变化。

注解

后到者胜出是完全没有并发控制的数据库访问的一个示例。匹配所有的更新、基于时间戳的更新以及变化值更新是乐观并发的示例。对于乐观并发策略,代码不需要保持使用的数据的锁--相反,你的策略是希望变更不会重叠,并且如果发生则进行相应的处理。本章稍后将会学习事务,它允许实现封闭式并发。封闭式并发通过锁定使用中的记录防止并发冲突。平衡在于可伸缩性,因为其他试图访问相同数据的用户将不得不等待。

为了更好地理解这些方法是如何工作的,想象一下,两个用户同时调用UpdateEmployee()方法提交对员工记录的不同更新时会发生什么,该方法采用了后到者胜出的更新策略。第一个用户更新了邮件地址,第二个用户本来只想更新员工的姓名却不经意间同时用旧的邮件地址覆盖了新的。问题在于UpdateEmployee()方法并不知道你究竟提交了哪些更新。这样不管原有值是否已经更新内存中所有的值,它都会重新写回到数据源(并因此覆写了其他用户的更新)。

使用大型、复杂且需要支持不同种类编辑的记录时,避免类似问题的最简单方法是创建多个针对性的方法。不再创建通用的UpdateEmployee()方法,而是提供UpdateEmployeeAddress()或ChangeEmployeeStatus()一类有针对性的方法。这些方法执行更具限制性的UPDATE语句,因而不会有重新应用旧值的风险。

你也许想要考虑多层并发并给予用户最终的决定权。比如,当用户进行编辑时,你可以试着用严格的完全匹配的或基于时间戳的并发。如果这样做不成功,那么你可以把记录中当前的数据显示给用户,并与用户正在应用的数据进行比较。这时,你可以让用户选择进一步编辑或用后到者胜出并发执行更改,覆写当前值。10.9.5节中有一个带有ASP.NET富数据控件的该技术的例子。