SharePoint2010开发最佳实践指南(二)

摘要:

  本文将阐述在SharePoint2010里如何进行对象的缓存以及需要注意的事项,同时也会介绍优化代码的一些技术。

  缓存是传统.NET开发中一种常用的用来改善性能的开发方式,但是在SharePoint里要尤其注意缓存带来的性能改善和线程不安全之间的平衡,有些SharePoint对象并非线程安全类型,做缓存时会导致预料外的异常。比如在读取列表数据的时候将SPListItemCollection缓存起来是一种常见的思维方式,但是由于SPListItemCollection包含一个非安全线程的SPWeb对象,如果将SPListItemCollection直接缓存会导致程序运行错误或者运行异常。

  下面的例子显示了缓存SPListItemCollection是非线程安全的。

public void CacheData()
{
    SPListItemCollection items;
    items = (SPListItemCollection)Cache["AListItemCache"];
    if(items == null)
    {
        items = DoQueryToReturnItems();
        Cache.Add("AListItemCache", items, ...);
    }
}

  上面的代码里由于IIS的工作机理是多线程运行的,如果DoQueryToResturnItems()查询需要10秒钟,在这个时间段里如果有很多用户也去做同样的操作,就会导致同样的查询会被同时运行,并且会去修改同样的对象items,这不仅会导致线程不安全的问题,也会导致性能的问题。为了阻止多线程的同步问题,需要加锁:

private static object _lock = new object();
public void CacheData()
{
    SPListItemCollection items;
    lock(_lock)
    {
        items = (SPListItemCollection)Cache["AListItemCache"];
        if(items == null)
        {
            items = DoQueryToReturnItems();
            Cache.Add("AListItemCache", items, ...);
        }
    }
}

  在上面的代码里,可以将锁的位置调整的if(items == null)之后得到一定程度的性能改善:

private static object _lock = new object();
public void CacheData()
{
    SPListItemCollection items;
    items = (SPListItemCollection)Cache["AListItemCache"];
    if(items == null)
    {
        lock(_lock)
        {
            items = DoQueryToReturnItems();
            Cache.Add("AListItemCache", items, ...);
        }
    }
}

  但是这种做法会带来其他的问题,当DoQueryToReturnItems这个方法执行的时间过长的时候有可能会有多个线程在lock外等着,当第一个线程更新完Cache后,第二个线程又会进来查询数据并更新线程,如果还有第三个线程也会做同样的事情。。。可以做出如下改善:

private static object _lock =  new object();

public void CacheData()
{
   SPListItemCollection oListItems;
       oListItems = (SPListItemCollection)Cache["ListItemCacheName"];
      if(oListItems == null)
      {
         lock (_lock) 
         {
              oListItems = (SPListItemCollection)Cache[“ListItemCacheName”];
              if (oListItems == null)
              {
                   oListItems = DoQueryToReturnItems();
                   Cache.Add("ListItemCacheName", oListItems, ..);
              }
         }
     }
}

  以上的代码虽然解决了缓存的问题,但是仍然不是值得推荐的做法,因为它缓存的是一个线程不安全的对象SPListItemCollection。为了解决线程安全的问题,可以用DataTable来保存数据:

private static object _lock =  new object();

public void CacheData()
{
   DataTable oDataTable;
   SPListItemCollection oListItems;
   lock(_lock)
   {
           oDataTable = (DataTable)Cache["ListItemCacheName"];
           if(oDataTable == null)
           {
              oListItems = DoQueryToReturnItems();
              oDataTable = oListItems.GetDataTable();
              Cache.Add("ListItemCacheName", oDataTable, ..);
           }
   }
}

代码优化:

一种常见的优化:

SPWeb myWeb = SPContext.Current.Web;

myWeb.Lists["Tasks"].Title = "List_Title";
myWeb.Lists["Tasks"].Description = "List_Description";
myWeb.Lists["Tasks"].Update();

以下的改良代码只实例化tasks列表一次并存储在myList变量里面,减少了对数据库的访问,提高了性能:

SPWeb myWeb = SPContext.Current.Web;

SPList myList = myWeb.Lists["Tasks"];

myList.Title="List_Title";
myList.Description="List_Description";
myList.Update();
原文地址:https://www.cnblogs.com/johnsonwong/p/2056631.html