代码之家  ›  专栏  ›  技术社区  ›  regex

需要中端帮助

  •  5
  • regex  · 技术社区  · 15 年前

    在一句话中,我最终需要知道的是如何在中间层函数之间共享对象,而中间层函数需要应用层传递数据模型对象。

    我正在为我工作的公司在当前环境中构建一个中端层。目前,我们主要使用.NET进行编程,并围绕各种数据库系统(从Oracle、OpenLDAP、MSSQL等)构建了自定义数据模型。

    我试图尽可能地将模型对象排除在应用程序之外,以便在更改底层数据库结构时,可以轻松地编辑和重新部署中间层,并且不需要重建多个应用程序。我将简要介绍伪代码中的问题,因为这是美国开发人员最了解的:)

    main
     {
      MidTierServices.UpdateCustomerName("testaccount", "John", "Smith");
    
      // since the data takes up to 4 seconds to be replicated from
      // write server to read server, the function below is going to
      // grab old data that does not contain the first name and last
      // name update....  John Smith will be overwritten w/ previous
      // data
    
      MidTierServices.UpdateCustomerPassword("testaccount", "jfjfjkeijfej");
     }
    
     MidTierServices
     {
      void UpdateCustomerName(string username, string first, string last)
      {
       Customer custObj = DataRepository.GetCustomer(username);
    
       /*******************
       validation checks and business logic go here...
       *******************/
    
       custObj.FirstName = first;
       custObj.LastName = last;
    
       DataRepository.Update(custObj);
      }
    
      void UpdateCustomerPassword(string username, string password)
      {
       // does not contain first and last updates
       Customer custObj = DataRepository.GetCustomer(username); 
    
       /*******************
       validation checks and business logic go here...
       *******************/
    
       custObj.Password = password;
    
       // overwrites changes made by other functions since data is stale
       DataRepository.Update(custObj); 
      }
     }
    

    另一方面,我考虑的选项是构建一个自主开发的缓存层,这需要花费大量时间,而且很难向管理层推销这一概念。使用另一个具有内置缓存支持的建模层,如nHibernate:这也很难向管理层出售,因为此选项也会花费很长时间来拆分整个定制模型,并用第三方解决方案替换它。此外,没有很多供应商支持我们的大型数据库阵列。例如,.NET具有到ActiveDirectory的LINQ,但没有到OpenLDAP的LINQ。

    无论如何,很抱歉这篇小说,但它更像是一个企业架构类型的问题,而不是一个简单的代码问题,比如“如何在.NET中获取当前日期和时间?”

    编辑

    我面临当前问题的主要原因是与数据复制有关。第一个函数对一台服务器进行写操作,然后下一个函数对另一台尚未接收到复制数据的服务器进行读操作。因此,从本质上讲,我的代码比数据复制过程要快。

    我可以通过总是对同一个LDAP服务器进行读写来解决这个问题,但是我的管理员可能会因此杀了我。特别设置了一个仅用于写入的服务器,然后在负载平衡器后面设置了4个仅用于读取的其他服务器。我绝不是LDAP管理员,所以我不知道这是否是标准过程。

    1 回复  |  直到 15 年前
        1
  •  3
  •   Glorfindel Doug L.    6 年前

    您正在描述一个非常常见的问题。

    解决这一问题的正常方法是使用 Optimistic Concurrency Control .

    问题

    当有多个写入程序时,两个更新的读写部分可能会交错。假设有A和B,它们都读取并更新数据库中的同一行。A读取数据库,B读取数据库,B更新数据库,A更新数据库。如果你有一个天真的方法,那么“最后一次写入”将获胜,而B的写入可能会被销毁。

    信任但核实 几年前的军备控制方法。实现这一点的方法是在数据库表中包含一个字段,该字段也必须包含在域对象中,它提供了一种区分db行或域对象的一个“版本”与另一个“版本”的方法。最简单的方法是使用一个名为lastUpdate的时间戳字段,它保存上次更新的时间。还有其他更复杂的方法来进行一致性检查,但时间戳字段适合用于说明。

    然后,当编写器或更新程序想要更新数据库时,它只能更新键匹配的行(无论您的键是什么) 而且

    由于开发人员理解代码,我将提供一些伪SQL。假设您有一个博客数据库,每个博客条目都有一个索引、一个标题和一些文本。您可以检索一组行(或对象)的数据,如下所示:

    SELECT ix, Created, LastUpdated, Headline, Dept FROM blogposts 
        WHERE CONVERT(Char(10),Created,102) = @targdate 
    

    这种查询可能检索数据库中某一天、某个月或任何时间的所有博客文章。

    使用简单的乐观并发,您可以更新 一排 像这样使用SQL:

    UPDATE blogposts Set Headline = @NewHeadline, LastUpdated = @NewLastUpdated
        WHERE ix=@ix AND LastUpdated = @PriorLastUpdated
    

    只有当索引匹配(我们假定这是主键),并且LastUpdated字段与读取数据时的字段相同时,才能进行更新。还要注意,您必须确保为行的每次更新更新更新LastUpdated字段。

    更严格的更新可能会坚持所有列都没有更新。在这种情况下,根本没有时间戳。大概是这样的:

    UPDATE Table1 Set Col1 = @NewCol1Value,
                  Set Col2 = @NewCol2Value,
                  Set Col3 = @NewCol3Value
    WHERE Col1 = @OldCol1Value AND
          Col2 = @OldCol2Value AND
          Col3 = @OldCol3Value
    

    OCC被用作保持数据库锁的替代方法,这是一种保持数据一致性的高压方法。DB锁可能会阻止 在保留db行的同时读取或更新db行。这显然具有巨大的性能影响。因此,OCC放松了这一点,并采取了“乐观”的行动,假定当需要更新时,表中的数据在此期间不会被更新。当然,这不是盲目乐观——你必须在更新之前检查。

    possible within the Visual Studio design experience .

    alt text
    asp.net )

    DataAdapter.RowUpdated event . (请注意,在ADO.NET模型中,每种数据库都有不同的DataAdapter。这里的链接是针对SqlDataAdapter的,SqlDataAdapter与SQLServer一起工作,但是对于不同的数据源,您需要不同的DA。)

    在RowUpdate事件中,您可以检查受影响的行数,然后在计数为零时采取一些措施。


    总结

    在写入更新之前,请验证数据库的内容是否未更改。这叫做 乐观并发控制 .