【问题标题】:Transactions across several DAL methods from the one method in the BLLBLL 中的一种方法跨多种 DAL 方法的事务
【发布时间】:2009-01-29 22:01:20
【问题描述】:

您将如何从业务逻辑层中的一个方法调用数据访问层中的多个方法,以便所有 SQL 命令都存在于一个 SQL 事务中?

每个 DAL 方法都可以从 BLL 中的其他位置单独调用,因此不能保证数据层方法始终是事务的一部分。我们需要这个功能,所以如果数据库在长时间运行的过程中脱机,就没有提交。业务层根据之前每次调用的结果编排不同的数据层方法调用。我们只想在整个过程的最后提交(从业务层)。

【问题讨论】:

    标签: c# .net sql


    【解决方案1】:

    首先,您必须遵守您在 BLL 中指定为单个方法的原子工作单元。这将(例如)创建客户、订单和订单项目。然后,您可以将这一切整齐地包装在 TransactionScope using 语句中。 TransactionScope 是这里的秘密武器。下面是一些幸运的是我现在正在处理的代码:):

    public static int InsertArtist(Artist artist)
    {
        if (artist == null)
            throw new ArgumentNullException("artist");
    
        int artistid = 0;
        using (TransactionScope scope = new TransactionScope())
        {
            // insert the master Artist
            /* 
               we plug the artistid variable into 
               any child instance where ArtistID is required
            */
            artistid = SiteProvider.Artist.InsertArtist(new ArtistDetails(
            0,
            artist.BandName,
            artist.DateAdded));
    
            // insert the child ArtistArtistGenre
            artist.ArtistArtistGenres.ForEach(item =>
            {
                var artistartistgenre = new ArtistArtistGenreDetails(
                    0,
                    artistid,
                    item.ArtistGenreID);
                SiteProvider.Artist.InsertArtistArtistGenre(artistartistgenre);
            });
    
            // insert the child ArtistLink
            artist.ArtistLinks.ForEach(item =>
            {
                var artistlink = new ArtistLinkDetails(
                    0,
                    artistid,
                    item.LinkURL);
                SiteProvider.Artist.InsertArtistLink(artistlink);
            });
    
            // insert the child ArtistProfile
            artist.ArtistProfiles.ForEach(item =>
            {
                var artistprofile = new ArtistProfileDetails(
                    0,
                    artistid,
                    item.Profile);
                SiteProvider.Artist.InsertArtistProfile(artistprofile);
            });
    
            // insert the child FestivalArtist
            artist.FestivalArtists.ForEach(item =>
            {
                var festivalartist = new FestivalArtistDetails(
                    0,
                    item.FestivalID,
                    artistid,
                    item.AvailableFromDate,
                    item.AvailableToDate,
                    item.DateAdded);
                SiteProvider.Festival.InsertFestivalArtist(festivalartist);
            });
            BizObject.PurgeCacheItems(String.Format(ARTISTARTISTGENRE_ALL_KEY, String.Empty, String.Empty));
            BizObject.PurgeCacheItems(String.Format(ARTISTLINK_ALL_KEY, String.Empty, String.Empty));
            BizObject.PurgeCacheItems(String.Format(ARTISTPROFILE_ALL_KEY, String.Empty, String.Empty));
            BizObject.PurgeCacheItems(String.Format(FESTIVALARTIST_ALL_KEY, String.Empty, String.Empty));
            BizObject.PurgeCacheItems(String.Format(ARTIST_ALL_KEY, String.Empty, String.Empty));
    
            // commit the entire transaction - all or nothing
            scope.Complete();
        }
        return artistid;
    }
    

    希望你能明白要点。基本上,这是一个成功或失败的工作,无论任何不同的数据库(即在上面的示例中,艺术家和艺术家艺术家类型可以托管在两个单独的数据库存储中,但 TransactionScope 不太关心这一点,它在 COM+ 级别工作并管理原子性它可以“看到”的范围)

    希望对你有帮助

    编辑:您可能会发现 TransactionScope 的初始调用(在应用程序启动时)可能会稍微引人注目(即在上面的示例中,如果第一次调用,可能需要2-3 秒完成),但是,后续调用几乎是瞬时的(即通常为 250-750 毫秒)。简单的接触点交易与(笨拙的)替代方案之间的权衡减轻了(对我和我的客户而言)初始“加载”延迟。

    只是想证明轻松并非没有妥协(尽管是在初始阶段)

    【讨论】:

      【解决方案2】:

      您所描述的是长事务的“定义”。

      每个 DAL 方法都可以简单地提供操作(无需任何特定提交)。您的 BLL(实际上是在您协调对 DAL 的任何调用的地方)是您可以选择提交或执行“保存点”的地方。保存点是一个可选项目,您可以使用它来允许在长时间运行的事务中“回滚”。

      因此,例如,如果我的 DAL 的方法 DAL1、DAL2、DAL3 都是可变的,它们将简单地“执行”数据更改操作(即某种类型的创建、更新、删除)。从我的 BLL 中,假设我有 BL1 和 BL2 方法(BL1 长期运行)。 BL1 调用所有上述 DAL 方法(即 DAL1...DAL3),而 BL2 仅调用 DAL3。

      因此,在执行每个业务逻辑方法时,您可能会遇到以下情况:

      BL1(长期交易)-> {savepoint} DAL1 -> {savepoint} DAL2 -> DAL3 {commit/end}

      BL2 -> DAL3 {提交/结束}

      “保存点”背后的想法是,如果数据操作出现问题,它可以允许 BL1 随时回滚。仅当所有三个操作都成功完成时,才会提交长事务。 BL2 仍然可以调用 DAL 中的任何方法,并且它负责控制提交。注意:您也可以在短期/常规交易中使用“保存点”。

      【讨论】:

        【解决方案3】:

        好问题。这触及了阻抗失配的核心。

        这是使用存储过程的最有力论据之一。原因:它们旨在将多个 SQL 语句封装在一个事务中。

        同样可以在 DAL 中按程序完成,但会导致代码不太清晰,同时通常会导致耦合/内聚平衡向错误的方向移动。

        出于这个原因,我在比简单封装表更高的抽象层次上实现 DAL。

        【讨论】:

          【解决方案4】:

          以防我在原始文章中的评论没有“坚持”,这是我作为附加信息添加的内容:

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-03-28
            • 1970-01-01
            • 2023-03-17
            • 2011-11-06
            • 2015-01-31
            • 1970-01-01
            • 2011-12-10
            • 2011-11-02
            相关资源
            最近更新 更多