一区二区久久-一区二区三区www-一区二区三区久久-一区二区三区久久精品-麻豆国产一区二区在线观看-麻豆国产视频

一步一步學(xué)Linq to sql(七):并發(fā)與事務(wù)

系列文章導(dǎo)航:

一步一步學(xué)Linq to sql(一):預(yù)備知識(shí)

一步一步學(xué)Linq to sql(二):DataContext與實(shí)體

一步一步學(xué)Linq to sql(三):增刪改

一步一步學(xué)Linq to sql(四):查詢句法

一步一步學(xué)Linq to sql(五):存儲(chǔ)過程

一步一步學(xué)Linq to sql(六):探究特性

一步一步學(xué)Linq to sql(七):并發(fā)與事務(wù)

一步一步學(xué)Linq to sql(八):繼承與關(guān)系

一步一步學(xué)Linq to sql(九):其它補(bǔ)充

一步一步學(xué)Linq to sql(十):分層構(gòu)架的例子


檢測(cè)并發(fā)

       首先使用下面的SQL語句查詢數(shù)據(jù)庫的產(chǎn)品表:

select * from products where categoryid=1

       查詢結(jié)果如下圖:

 

       為了看起來清晰,我已經(jīng)事先把所有分類為1產(chǎn)品的價(jià)格和庫存修改為相同值了。然后執(zhí)行下面的程序:

        var query = from p in ctx.Products where p.CategoryID == 1 select p;

        foreach (var p in query)

            p.UnitsInStock = Convert.ToInt16(p.UnitsInStock - 1);

        ctx.SubmitChanges(); // 在這里設(shè)斷點(diǎn)

       我們使用調(diào)試方式啟動(dòng),由于設(shè)置了斷點(diǎn),程序并沒有進(jìn)行更新操作。此時(shí),我們?cè)跀?shù)據(jù)庫中運(yùn)行下面的語句:

update products

set unitsinstock = unitsinstock -2, unitprice= unitprice + 1

where categoryid = 1

       然后在繼續(xù)程序,會(huì)得到修改并發(fā)(樂觀并發(fā)沖突)的異常,提示要修改的行不存在或者已經(jīng)被改動(dòng)。當(dāng)客戶端提交的修改對(duì)象自讀取之后已經(jīng)在數(shù)據(jù)庫中發(fā)生改動(dòng),就產(chǎn)生了修改并發(fā)。解決并發(fā)的包括兩步,一是查明哪些對(duì)象發(fā)生并發(fā),二是解決并發(fā)。如果你僅僅是希望更新時(shí)不考慮并發(fā)的話可以關(guān)閉相關(guān)列的更新驗(yàn)證,這樣在這些列上發(fā)生并發(fā)就不會(huì)出現(xiàn)異常:

[Column(Storage="_UnitsInStock", DbType="SmallInt", UpdateCheck = UpdateCheck.Never)]

[Column(Storage="_UnitPrice", DbType="Money", UpdateCheck = UpdateCheck.Never)]

       為這兩列標(biāo)注不需要進(jìn)行更新檢測(cè)。假設(shè)現(xiàn)在產(chǎn)品價(jià)格和庫存分別是2732。那么,我們啟動(dòng)程序(設(shè)置端點(diǎn)),然后運(yùn)行UPDATE語句,把價(jià)格+1,庫存-2,然后價(jià)格和庫存分別為2830了,繼續(xù)程序可以發(fā)現(xiàn)價(jià)格和庫存分別是2831。價(jià)格+1是之前更新的功勞,庫存最終是-1是我們程序之后更新的功勞。當(dāng)在同一個(gè)字段上(庫存)發(fā)生并發(fā)沖突的時(shí)候,默認(rèn)是最后的那次更新獲勝。

系列文章導(dǎo)航:

一步一步學(xué)Linq to sql(一):預(yù)備知識(shí)

一步一步學(xué)Linq to sql(二):DataContext與實(shí)體

一步一步學(xué)Linq to sql(三):增刪改

一步一步學(xué)Linq to sql(四):查詢句法

一步一步學(xué)Linq to sql(五):存儲(chǔ)過程

一步一步學(xué)Linq to sql(六):探究特性

一步一步學(xué)Linq to sql(七):并發(fā)與事務(wù)

一步一步學(xué)Linq to sql(八):繼承與關(guān)系

一步一步學(xué)Linq to sql(九):其它補(bǔ)充

一步一步學(xué)Linq to sql(十):分層構(gòu)架的例子


解決并發(fā)

       如果你希望自己處理并發(fā)的話可以把前面對(duì)列的定義修改先改回來,看下面的例子:

        var query = from p in ctx.Products where p.CategoryID == 1 select p;

        foreach (var p in query)

            p.UnitsInStock = Convert.ToInt16(p.UnitsInStock - 1);

        try

        {

            ctx.SubmitChanges(ConflictMode.ContinueOnConflict);

        }

        catch (ChangeConflictException)

        {

            foreach (ObjectChangeConflict cc in ctx.ChangeConflicts)

            {

                Product p = (Product)cc.Object;

                Response.Write(p.ProductID + "<br/>");

                cc.Resolve(RefreshMode.OverwriteCurrentValues); // 放棄當(dāng)前更新,所有更新以原先更新為準(zhǔn)

            }

        }

        ctx.SubmitChanges();

       首先可以看到,我們使用try{}catch{}來捕捉并發(fā)沖突的異常。在SubmitChanges的時(shí)候,我們選擇了ConflictMode.ContinueOnConflict選項(xiàng)。也就是說遇到并發(fā)了還是繼續(xù)。在catch{}中,我們從ChangeConflicts中獲取了并發(fā)的對(duì)象,然后經(jīng)過類型轉(zhuǎn)化后輸出了產(chǎn)品ID,然后選擇的解決方案是RefreshMode.OverwriteCurrentValues。也就是說,放棄當(dāng)前的更新,所有更新以原先更新為準(zhǔn)。

       我們來測(cè)試一下,假設(shè)現(xiàn)在產(chǎn)品價(jià)格和庫存分別是2732。那么,我們啟動(dòng)程序(在ctx.SubmitChanges(ConflictMode.ContinueOnConflict)這里設(shè)置端點(diǎn)),然后運(yùn)行UPDATE語句,把價(jià)格+1,庫存-2,然后價(jià)格和庫存分別為2830了,繼續(xù)程序可以發(fā)現(xiàn)價(jià)格和庫存分別是2830。之前SQL語句庫存-2生效了,而我們程序的更新(庫存-1)被放棄了。在頁面上也顯示了所有分類為1的產(chǎn)品ID(因?yàn)槲覀冎暗?/span>SQL語句是對(duì)所有分類為1的產(chǎn)品都進(jìn)行修改的)。

       然后,我們來修改一下解決并發(fā)的方式:

cc.Resolve(RefreshMode.KeepCurrentValues); // 放棄原先更新,所有更新以當(dāng)前更新為準(zhǔn)

       來測(cè)試一下,假設(shè)現(xiàn)在產(chǎn)品價(jià)格和庫存分別是2732。那么,我們啟動(dòng)程序(在ctx.SubmitChanges(ConflictMode.ContinueOnConflict)這里設(shè)置端點(diǎn)),然后運(yùn)行UPDATE語句,把價(jià)格+1,庫存-2,然后價(jià)格和庫存分別為2830了,繼續(xù)程序可以發(fā)現(xiàn)價(jià)格和庫存分別是2731。產(chǎn)品價(jià)格沒有變化,庫存-1了,都是我們程序的功勞,SQL語句的更新被放棄了。

       然后,我們?cè)賮硇薷囊幌陆鉀Q并發(fā)的方式:

cc.Resolve(RefreshMode.KeepChanges); // 原先更新有效,沖突字段以當(dāng)前更新為準(zhǔn)

       來測(cè)試一下,假設(shè)現(xiàn)在產(chǎn)品價(jià)格和庫存分別是2732。那么,我們啟動(dòng)程序(在ctx.SubmitChanges(ConflictMode.ContinueOnConflict)這里設(shè)置端點(diǎn)),然后運(yùn)行UPDATE語句,把價(jià)格+1,庫存-2,然后價(jià)格和庫存分別為2830了,繼續(xù)程序可以發(fā)現(xiàn)價(jià)格和庫存分別是2831。這就是默認(rèn)方式,在保持原先更新的基礎(chǔ)上,對(duì)于發(fā)生沖突的字段以最后更新為準(zhǔn)。

       我們甚至還可以針對(duì)不同的字段進(jìn)行不同的處理策略:

foreach (ObjectChangeConflict cc in ctx.ChangeConflicts)

{

    Product p = (Product)cc.Object;

    foreach (MemberChangeConflict mc in cc.MemberConflicts)

    {

        string currVal = mc.CurrentValue.ToString();

        string origVal = mc.OriginalValue.ToString();

        string databaseVal = mc.DatabaseValue.ToString();

        MemberInfo mi = mc.Member;

        string memberName = mi.Name;

        Response.Write(p.ProductID + " " + mi.Name + " " + currVal + " " + origVal +" "+ databaseVal + "<br/>");

        if (memberName == "UnitsInStock")

            mc.Resolve(RefreshMode.KeepCurrentValues); // 放棄原先更新,所有更新以當(dāng)前更新為準(zhǔn)

        else if (memberName == "UnitPrice")

            mc.Resolve(RefreshMode.OverwriteCurrentValues); // 放棄當(dāng)前更新,所有更新以原先更新為準(zhǔn)

        else

            mc.Resolve(RefreshMode.KeepChanges); // 原先更新有效,沖突字段以當(dāng)前更新為準(zhǔn)

 

    }

}

       比如上述代碼就對(duì)庫存字段作放棄原先更新處理,對(duì)價(jià)格字段作放棄當(dāng)前更新處理。我們來測(cè)試一下,假設(shè)現(xiàn)在產(chǎn)品價(jià)格和庫存分別是2732。那么,我們啟動(dòng)程序(在ctx.SubmitChanges(ConflictMode.ContinueOnConflict)這里設(shè)置端點(diǎn)),然后運(yùn)行UPDATE語句,把價(jià)格+1,庫存-2,然后價(jià)格和庫存分別為2830了,繼續(xù)程序可以發(fā)現(xiàn)價(jià)格和庫存分別為2831了。說明對(duì)價(jià)格的處理確實(shí)保留了原先的更新,對(duì)庫存的處理保留了當(dāng)前的更新。頁面上顯示的結(jié)果如下圖:

最后,我們把提交語句修改為:

ctx.SubmitChanges(ConflictMode.FailOnFirstConflict);

       表示第一次發(fā)生沖突的時(shí)候就不再繼續(xù)了,然后并且去除最后的ctx.SubmitChanges();語句。來測(cè)試一下,在執(zhí)行了SQL后再繼續(xù)程序可以發(fā)現(xiàn)界面上只輸出了數(shù)字1,說明在第一條記錄失敗后,后續(xù)的并發(fā)沖突就不再處理了。

系列文章導(dǎo)航:

一步一步學(xué)Linq to sql(一):預(yù)備知識(shí)

一步一步學(xué)Linq to sql(二):DataContext與實(shí)體

一步一步學(xué)Linq to sql(三):增刪改

一步一步學(xué)Linq to sql(四):查詢句法

一步一步學(xué)Linq to sql(五):存儲(chǔ)過程

一步一步學(xué)Linq to sql(六):探究特性

一步一步學(xué)Linq to sql(七):并發(fā)與事務(wù)

一步一步學(xué)Linq to sql(八):繼承與關(guān)系

一步一步學(xué)Linq to sql(九):其它補(bǔ)充

一步一步學(xué)Linq to sql(十):分層構(gòu)架的例子


事務(wù)處理

       Linq to sql在提交更新的時(shí)候默認(rèn)會(huì)創(chuàng)建事務(wù),一部分修改發(fā)生錯(cuò)誤的話其它修改也不會(huì)生效:

        ctx.Customers.Add(new Customer { CustomerID = "abcdf", CompanyName = "zhuye" });

        ctx.Customers.Add(new Customer { CustomerID = "abcde", CompanyName = "zhuye" });

        ctx.SubmitChanges();

       假設(shè)數(shù)據(jù)庫中已經(jīng)存在顧客ID為“abcde”的記錄,那么第二次插入操作失敗將會(huì)導(dǎo)致第一次的插入操作失效。執(zhí)行程序后會(huì)得到一個(gè)異常,查詢數(shù)據(jù)庫發(fā)現(xiàn)“abcdf”這個(gè)顧客也沒有插入到數(shù)據(jù)庫中。

       如果每次更新后直接提交修改,那么我們可以使用下面的方式做事務(wù):

        if (ctx.Connection != null) ctx.Connection.Open();

        DbTransaction tran = ctx.Connection.BeginTransaction();

        ctx.Transaction = tran;

        try

        {

            CreateCustomer(new Customer { CustomerID = "abcdf", CompanyName = "zhuye" });

            CreateCustomer(new Customer { CustomerID = "abcde", CompanyName = "zhuye" });

            tran.Commit();

        }

        catch

        {

            tran.Rollback();

        }

 

    private void CreateCustomer(Customer c)

    {

        ctx.Customers.Add(c);

        ctx.SubmitChanges();

    }

       運(yùn)行程序后發(fā)現(xiàn)增加顧客abcdf的操作并沒有成功。或者,我們還可以通過TransactionScope實(shí)現(xiàn)事務(wù):

        using (TransactionScope scope = new TransactionScope())

        {

            CreateCustomer(new Customer { CustomerID = "abcdf", CompanyName = "zhuye" });

            CreateCustomer(new Customer { CustomerID = "abcde", CompanyName = "zhuye" });

            scope.Complete();

        }

      

it知識(shí)庫一步一步學(xué)Linq to sql(七):并發(fā)與事務(wù),轉(zhuǎn)載需保留來源!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。

主站蜘蛛池模板: 久久男女 | 国产在线视频网址 | 天天欧美| 免费在线观看色 | 亚洲天堂一区二区在线观看 | 精品免费久久 | 伊人网综合视频 | 欧美人体大胆做受 | 日本三级一区二区三区 | 成人午夜免费视频 | 成人午夜无人区一区二区 | 福利片在线看 | 91福利视频一区 | wwwav在线| 日韩一级片网址 | 999精品免费视频观看 | 国产精品美女免费视频观看 | 2021在线永久免费视频 | 欧美亚洲激情视频 | 亚洲香蕉在线 | 亚洲精品国产综合久久一线 | 久久亚洲欧美成人精品 | 一区二区三区四区在线视频 | aa级国产女人毛片水真多 | 巨臀中文字幕一区二区视频 | 亚洲精品第一页中文字幕 | 国产乱码一区二区三区四川人 | 看全色黄大色大片免费久久怂 | 91福利视频网 | 日韩午夜免费 | 五月婷婷六月丁香在线 | 91色国产 | 美女视频黄.免费网址 | 日本一区二区免费看 | 欧美成人三级网站在线观看 | 精品国产第一页 | 韩国美女爽快一级毛片黄 | 91在线精品 | 一区在线播放 | 黄网站免费在线观看 | 日韩a无v码在线播放免费 |