基(ji)礎才是重中之重~ThreadStatic靜態字段在每(mei)個(ge)線(xian)程里的唯(wei)一性
static修(xiu)飾符我們不會陌生,它代(dai)表(biao)靜(jing)態,可以修(xiu)飾你的(de)(de)(de)類(lei)(lei),方法,字段和屬性(xing)等等,今天主要(yao)說一(yi)個(ge)為靜(jing)態字段加ThreadStatic特性(xing)會給(gei)程序(xu)代(dai)來什么樣的(de)(de)(de)變化。靜(jing)態字段static field,我更習慣稱(cheng)它為“類(lei)(lei)的(de)(de)(de)字段”,即它與類(lei)(lei)的(de)(de)(de)具體實例無關,對(dui)于所(suo)有線程里,它的(de)(de)(de)值都(dou)是一(yi)個(ge),即它的(de)(de)(de)唯一(yi)性(xing)。
如代碼:
class Instance
{ static DataContext context=new LinqToSql(conn);
protected static DataContext {get{return context;}}
}
上面的(de)(de)代碼(ma)中,context為(wei)靜態(tai)字段,它(ta)的(de)(de)值在(zai)所有線程中都是(shi)一(yi)樣(yang)的(de)(de),換名話說,在(zai)多個用戶訪問一(yi)個頁(ye)面里,得(de)到它(ta)的(de)(de)值都是(shi)一(yi)樣(yang)的(de)(de)。
上面代碼是一個linq to sql實現DAL層時的一個基類,它向子類公開一個數據上下文,在所有用戶訪問里(所有線程中)其值(內存地址)都是一樣的,而在LINQTOSQL架構中,這個(ge)靜態數據上下文在(zai)實現(xian)開發中會出現(xian)很(hen)多問題,所以,官方(fang)不推薦使用。
但是(shi),如果我們引入(ru)ThreadStatic之后(hou),結(jie)果就不(bu)同(tong)了,當(dang)字(zi)段被ThreadStatic特性修飾后(hou),它的(de)值(zhi)在每(mei)個線程中都(dou)是(shi)不(bu)同(tong)的(de),即每(mei)個線程對static字(zi)段都(dou)會重(zhong)新分配內存空間,就當(dang)然于(yu)一次new操(cao)作(zuo),這樣一來,由(you)于(yu)static字(zi)段所(suo)產生的(de)問題也(ye)就沒有了,這種(zhong)static數(shu)據上下文是(shi)可以被接受的(de)。
internal class DbFactory { #region Fields /// <summary> /// 每(mei)個線程(cheng),一個新的DataContext實(shi)例 /// </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 }
上(shang)面代碼是一個(ge)(ge)生成LINQ上(shang)下文的工廠(chang),你可以(yi)為每(mei)個(ge)(ge)LINQTOSQL類(lei)(lei)新建個(ge)(ge)基類(lei)(lei),用來得到這(zhe)個(ge)(ge)上(shang)下文,而具體操作(zuo)類(lei)(lei)再去繼承(cheng)這(zhe)個(ge)(ge)基類(lei)(lei),這(zhe)在微軟的架(jia)構中,
會很常(chang)見,如System.Web.MVC.ControllerBase,它是(shi)Controller的基類。
/// <summary> /// DataClasses1DataContext數據(ju)庫基類 /// </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 }
而具體表(biao)的CURD操作,你可(ke)以單(dan)獨建(jian)立類文件,來做這(zhe)件事
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,如果將上面(mian)代碼(ma)輸出后,它的結果是正確(que)的
事實上(shang),上(shang)面(mian)我(wo)使用(yong)(yong)的(de)復雜(za)查(cha)詢,對(dui)于這種查(cha)詢,如(ru)果(guo)你(ni)的(de)數據上(shang)下文不是(shi)static類型,它會出(chu)現異(yi)常(chang)的(de),一般異(yi)常(chang)為(wei)(wei)”為(wei)(wei)不能處理不同(tong)(tong)數據上(shang)下文的(de)引用(yong)(yong)”,當然,這個提示是(shi)正常(chang)的(de),因為(wei)(wei)如(ru)果(guo)你(ni)的(de)上(shang)下文為(wei)(wei)實例對(dui)象,那(nei)么,對(dui)于每個類來說,它都(dou)是(shi)不同(tong)(tong)的(de),都(dou)會被new一次!
當出現上面問題后,我們往往解決方法是使用static類型的上下文,而static類型本身在LINQTOSQL上就是有問題的,在進行數據更新操作時,所有線程,所有操作的LINQ緩存都是一個,在submitChange時,會出現提求混亂的情況,錯誤是不可預知的。所以,你不得不把所有的表關系查詢都寫在DAL層,將每個業務的復雜查詢方法都重寫一次,這樣才能解決“不能數據上下文”的問題,太可怕了,呵(he)呵(he)。
當然,你如果(guo)提前(qian)做了表(biao)關(guan)聯,使用LINQ的“立(li)即(ji)加載”也是一個不錯的方式,它(ta)(ta)可以(yi)為你節省不少代碼,但它(ta)(ta)產生的SQL語句,其內查詢(xun)則(ze)是select * from table的格式,即(ji)返回了很多無用的列。
綜上所(suo)述(shu):使用線程唯一的靜(jing)態(tai)數據上下文才是最好的解決(jue)方案!