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();

你可能感兴趣的:(SharePoint)