基礎才是重中之重~ThreadStatic靜態字段在每個線程里的唯一性


回到目錄

static修飾符我們不會陌生,它代表靜態,可以修飾你的類,方法,字段和屬性等等,今天主要說一個為靜態字段加ThreadStatic特性會給程序代來什么樣的變化。靜態字段static field,我更習慣稱它為“類的字段”,即它與類的具體實例無關,對於所有線程里,它的值都是一個,即它的唯一性。

如代碼:

class Instance
{
static DataContext context=new LinqToSql(conn);
protected static DataContext {get{return context;}}
}

上面的代碼中,context為靜態字段,它的值在所有線程中都是一樣的,換名話說,在多個用戶訪問一個頁面里,得到它的值都是一樣的。

上面代碼是一個linq to sql實現DAL層時的一個基類,它向子類公開一個數據上下文,在所有用戶訪問里(所有線程中)其值(內存地址)都是一樣的,而在LINQTOSQL架構中,這個靜態數據上下文在實現開發中會出現很多問題,所以,官方不推薦使用。

但是,如果我們引入ThreadStatic之后,結果就不同了,當字段被ThreadStatic特性修飾后,它的值在每個線程中都是不同的,即每個線程對static字段都會重新分配內存空間,就當然於一次new操作,這樣一來,由於static字段所產生的問題也就沒有了,這種static數據上下文是可以被接受的。

    internal class DbFactory
    {

        #region Fields
        /// <summary>
        /// 每個線程,一個新的DataContext實例
        /// </summary>
        [ThreadStatic]
        static readonly DataContext current = new DataClasses1DataContext();
        #endregion

        #region Contructors
        #endregion

        #region Properties
        public static DataContext Current
        {
            get { return current; }
        }
        #endregion

        #region Methods

        #endregion

        #region Events

        #endregion

    }

上面代碼是一個生成LINQ上下文的工廠,你可以為每個LINQTOSQL類新建個基類,用來得到這個上下文,而具體操作類再去繼承這個基類,這在微軟的架構中,

會很常見,如System.Web.MVC.ControllerBase,它是Controller的基類。

/// <summary>
    /// DataClasses1DataContext數據庫基類
    /// </summary>
    public abstract class DbBase
    {

        #region Fields

        #endregion

        #region Contructors

        #endregion

        #region Properties
        public DataClasses1DataContext Db = DbFactory.Current as DataClasses1DataContext;
        #endregion

        #region Methods

        #endregion

        #region Events

        #endregion

    }

而具體表的CURD操作,你可以單獨建立類文件,來做這件事

public class WebManageUsers_Ext : WebManageUsers { }
    public class UserDAL : DbBase
    {

        #region Fields

        #endregion

        #region Contructors

        #endregion

        #region Properties

        #endregion

        #region Methods
        public IQueryable<WebManageUsers> GetModel()
        {
            var linq = from data1 in base.Db.WebManageUsers
                       join data2 in new DeptDAL().GetModel() on data1.DepartmentID equals data2.DepartmentID
                       select new WebManageUsers_Ext
                       {
                           RealName = data1.RealName,
                           WebDepartments = data2,
                       };
            return linq;
        }
        #endregion

        #region Events

        #endregion

    }

OK,如果將上面代碼輸出后,它的結果是正確的

事實上,上面我使用的復雜查詢,對於這種查詢,如果你的數據上下文不是static類型,它會出現異常的,一般異常為”為不能處理不同數據上下文的引用”,當然,這個提示是正常的,因為如果你的上下文為實例對象,那么,對於每個類來說,它都是不同的,都會被new一次!

當出現上面問題后,我們往往解決方法是使用static類型的上下文,而static類型本身在LINQTOSQL上就是有問題的,在進行數據更新操作時,所有線程,所有操作的LINQ緩存都是一個,在submitChange時,會出現提求混亂的情況,錯誤是不可預知的。所以,你不得不把所有的表關系查詢都寫在DAL層,將每個業務的復雜查詢方法都重寫一次,這樣才能解決“不能數據上下文”的問題,太可怕了,呵呵。

當然,你如果提前做了表關聯,使用LINQ的“立即加載”也是一個不錯的方式,它可以為你節省不少代碼,但它產生的SQL語句,其內查詢則是select *  from table的格式,即返回了很多無用的列。

綜上所述:使用線程唯一的靜態數據上下文才是最好的解決方案!

 回到目錄


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM