• 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();
    
  • 相关阅读:
    SpringBoot2.0 整合 Dubbo框架 ,实现RPC服务远程调用
    Spark家族:Win10系统下搭建Scala开发环境
    Linux系统:centos7下搭建Rocketmq4.3中间件,配置监控台
    Linux系统:Centos7环境搭建Redis单台和哨兵集群环境
    Linux系统:常用Linux系统管理命令总结
    Linux系统:centos7下安装Jdk8、Tomcat8、MySQL5.7环境
    Linux系统:centos7下搭建ZooKeeper3.4中间件,常用命令总结
    SpringBoot2.0 整合 Redis集群 ,实现消息队列场景
    SpringBoot2.0 基础案例(17):自定义启动页,项目打包和指定运行环境
    SpringBoot2.0 基础案例(16):配置Actuator组件,实现系统监控
  • 原文地址:https://www.cnblogs.com/johnsonwong/p/2056631.html
Copyright © 2020-2023  润新知