分层开发利于模块之间的解耦,一般常见的三层方式:UI层\业务逻辑层\数据访问层
这有个问题想和大家讨论学习,请高手们不吝指教:当软件有较复杂的业务需求时,可以在数据库中编写存储过程,一个存储过程中去执行多个SQL语句.
但由于分层的需求,往往也可以在业务层编写方法去逐一调用数据访问层的多个方法
但如果需要事务处理时,就出现了问题,在数据库中编写存储过程来执行事务处理.这样做的话,业务逻辑层的存在就没有了价值,瘦业务逻辑层也使数据库服务器增大了负担,应用服务器仅仅成为了UI层的平台.
如果要把事务处理放到业务层的话,本人还不知道如何实现,DbTranscation的实例化是需要一个DbConnection对象的,按分层开发的解耦原则来说,这个不可行.如果把事务处理放置到数据访问层去做的话,与直接写事务的存储过程没有区别,另外,同样也造成了瘦业务逻辑层.其他,一句话综述:
为均衡数据库服务器与应用程序服务器,并且集中软件中的逻辑处理到业务层,如何在业务层进行事务处理.当然,如果在数据层实现事务\或都在数据库编写事务存储过程,是否也合理,请有高见的谈谈.还有一点,我思索的:很多程序喜欢用SqlHelper的方式去访问处理数据层,但有些数据层在创建Connection时,习惯为每一个数据库操作创建一个Connection,并且使用完后,立即关闭和释放Connection.这种方法是不可能提供给业务层事务处理的基础的..Net事务处理的基础就是在同一个Connection上执行多个数据库操作时,才能实现Commit或Rollback的.话题比较大,讨论的重点还是在业务逻辑层实现事务处理?或是数据层实现事务?或是存储过程实现事务?若应该在业务逻辑层实现事务处理,应该如何完成?

解决方案 »

  1.   

    能否在DAL里封装一个GetTranscation的方法,让BLL里获得Connection,然后在BLL中对相应的方法进行事务处理。
    但是BLL中还真得引用System.Data.SqlClient了?
    这BLL还是BLL么?
    请高手有想法的指点指点
      

  2.   

    有人说实体、业务逻辑、数据库表结构什么的要“一一对应”(大致是这类意思,我懒得去记原话了),这实在是没有意义。设计业务实体、业务层功能接口时,就是基于表现层的针对用户操作需求的分析,分析每一个用户操作如何实现、用什么客户端组件实现、绑定到客户端组件属性上的业务实体是什么结构、如何调用业务逻辑层针对后台(近到本地磁盘远到云api的后边)如何输入输出。比如我们想做一个通过只能手机与pc平台创建公司的摄影室的项目,我们调查移动公司给我们提供哪些通讯api、其它sp提供哪些、我们自己的公司有哪些其它部门其它产品现成的互联网api可以利用,这些api如何个能够适配到我们对于这个摄影室项目的客户端实现中。我们不比把时间白白浪费在担心这些业务服务api背后用了1台还是100台服务器、用了什么操作系统之类的、是怎样实现业务逻辑处理的,只要关心它的输入输出是否正确、性能如何就行了。我们分层设计,于是做过5、6个小而灵活项目之后就能产生一个大的业务逻辑服务系统,把不稳定的界面编程与稳定可复用的业务逻辑编程组织成两个层次,我们攒下的家当更多,可以敢于快速改变我们的界面编程。
      

  3.   


    像这类话我在csdn或者其它论坛看过不少,但我始终没有看懂。不知道这是来自于哪一条“解耦原则”,甚至不知道那种所谓“解耦”的目的到底是要解决什么“耦合”。如果从最终交互界面设计需求实际出发,什么地方是内聚的什么地方是耦合的其边界很清楚,本来就是高内聚的地方也不会打折解耦的旗号去花精力想办法拆散它。
      

  4.   

    connection和transaction由BLL层向dal层提供,dal类只负责操作数据,bll负责连接和事务的管理
      

  5.   

    引用 1 楼 josxhn 的回复:
    的确是个好问题。我也碰到过类似的问题。但是被我用别的办法绕开了。
    如何绕开???求解
      

  6.   

    懂你的意思 我使用的三层模式 在逻辑层进行了事物的控制 至于如何控制 看下面代码
    第一种情况:
    Using(sqlconnection connection = new sqlconnection(strConnectString))
    {
       sqlTransaction transation = connection.BeginTransation;
       
       然后把transaction传入数据层进行数据访问,一旦抛出异常就调用transaction.rollBack();
    }第二种情况:
    如果逻辑层中还需要调用多个诸如上面第一种情况这样的已经有了sqlTransaction处理的逻辑层方法,
    那么就要使用TransactionScope(分布式事物,需要配置MTC) 在调用以上的逻辑层方法时,一旦有
    一个SqlTransaction出现异常,那么所有的sqlTransaction都会被回滚!不知道能否满足你的解耦!
      

  7.   

    如何在业务层进行事务处理.
    ---------------------
    .NET没有类似Java里的JTA之类的事务管理器吗?怎么会有人在这个总是上想解决办法呢?好奇怪啊。
    居然有人说是个好问题。
      

  8.   

    存储过程的调用难道不是相当于调用一个“sql”语句吗?
    并不是说一个存储过程就一定是一个事物吧!那只是一堆sql语句而已。
    事物的控制还是可以放在业务逻辑层啊!
    比如:开始事物:
    调用sqlA
    调用存储过程(相当于sqlB),一般来说框架都会对存储过程的调用封装的,和调用sql应该没有本质区别。
    调用sqlC
    提交或回滚事物
      

  9.   

    我来谈谈对UI层\业务逻辑层\数据访问层的理解,希望能给你带来帮助1。用户界面层(即用户接口层、UI层、Uer view层),主要职责是提供可用的功能给用户。1.1用户界面导航层(一般由CXXCtrlView),主要职责是响应(识别)用户的请求操作(包括UI层返回及用户的输入数据) 由请求操作 调用相应的CXXService(或CXXManager)完成相应的业务逻辑,根据业务逻辑成功与否,
    导航到不同的Uer view层。强调一下:导航层不进行任何的业务逻辑计算,只是判断请求操作成功与否做出相应的导航操作。2.业务逻辑模块层(一般由CXXService或 CXXManager类模块组成),主要职责执行业务逻辑的计算,业务逻辑可以很简单,简单到只是简单的调用CXXXDAO的一个save操作。也可以很复杂,复杂到要用到多个CXXXDAO(或者说是多个table表)才能完成。即使用到了多个table表,业务逻辑层也不应该直接用sql操作table表,那样会带来维护的复杂度,这时应该新建一个能操作相关table的CXXXDAO新类,让这个新类来完成业务逻辑要求的复杂的sql(或是复杂的存储过程)。------(建议复杂问题尽量简单化)。3.DAO层(即数据访问层)。主要职责完成各种各样的存储、查询操作。主要作用是 向上提供不同的存储接口及查询。如saveUserAndXxx();getUserAdnXxx()等等;以求对数据访问的简单化。提供数据的简化访问的同时也屏蔽了数据库的存在,业务逻辑层不需要知道DAO层到底在用那个数据库,或者根本就没用。这是我对UI层\业务逻辑层\数据访问层的理解,同时也说到了大家容易忽略的viewCntrl导航层,虽然这一层操作少,但我是还认为它应该算一层。好了,说了那么多希望对你能有点用处。不要你分!哈哈哈!
      

  10.   

    引用一段话,链接一个图:2.BL(Business Logic)层的职责是按预定的业务逻辑处理UI层提交的请求。
    (1)Business Function 子层负责基本业务功能的实现。
    (2)Business Flow 子层负责将Business Function子层提供的多个基本业务功能组织成一个完整的业务流。(Transaction只能在Business Flow 子层开启。)原帖请看这里:
    http://www.cnblogs.com/morningwang/archive/2008/04/14/1153518.html
      

  11.   

    用SQLHelper在数据访问层,可以传递一个事务的参数.
    用存储过程,最直接解决了事务的问题。
      

  12.   

    你对BLL理解得太死了.   如果把事务,逻辑放在存储过程中, 就是把存储过程当作BLL了,不存在所谓瘦BLL层了. 谁说BLL一定要在.NET/JAVA中实现? 放在DB中也是一样的分层 
      

  13.   

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data;
    using System.Data.Common;
    using Microsoft.Practices.EnterpriseLibrary.Data;namespace SVNGo.DAL
    {
        public class DBContext
        {
            private Database _db = null;
            private DbTransaction _transaction = null;
            private DbConnection _conn = null;
            private int _transactionRef = 0;        public static DBContext CreateDBContext(string connName)
            {
                return new DBContext(connName);
            }        public DBContext(string connName)
            {
                _db = DatabaseFactory.CreateDatabase(connName);
            }        public void BeginTransaction(IsolationLevel isolevel)
            {
                if (_transaction != null && _transactionRef > 0)
                {
                    ++_transactionRef;
                }
                else
                {
                    _conn = _db.CreateConnection();
                    _conn.Open();
                    _transaction = _conn.BeginTransaction(isolevel);
                    ++_transactionRef;
                }
            }        public void Commit()
            {
                if (_transaction != null && _transactionRef > 0)
                {
                    --_transactionRef;
                    if (_transactionRef == 0)
                    {
                        _transaction.Commit();
                        _transaction = null;
                        if (_conn != null && _conn.State == ConnectionState.Open)
                        {
                            _conn.Close();
                            _conn = null;
                        }
                    }
                }
            }        public void Rollback()
            {
                if (_transaction != null && _transactionRef > 0)
                {
                    _transaction.Rollback();
                    _transactionRef = 0;
                    _transaction = null;                if (_conn != null && _conn.State == ConnectionState.Open)
                    {
                        _conn.Close();
                        _conn = null;
                    }
                }
            }        public DbCommand GetStoredProcCommand(string storedProcedureName)
            {
                return _db.GetStoredProcCommand(storedProcedureName);
            }        public void DiscoverParameters(DbCommand dc)
            {
                _db.DiscoverParameters(dc);
            }        public int ExecuteNonQuery(DbCommand dc)
            {
                if (_transaction != null)
                {
                    return _db.ExecuteNonQuery(dc, _transaction);
                }
                else
                {
                    return _db.ExecuteNonQuery(dc);
                }
            }        public DbDataReader ExecuteReader(DbCommand dc)
            {
                DbDataReader dr = null;
                DataReaderWrapper drw = _db.ExecuteReader(dc) as DataReaderWrapper;
                if (drw != null)
                {
                    dr = drw.InnerReader as DbDataReader;
                }            return dr;
            }
        }
    }
      

  14.   

    上面的DBContext 类放在 DAL 中, 在BLL中调用,如:
                _dbContext = new DBContext(svnlib);
                _changeDAL = new ***DAL(_dbContext);            try
                {
                    _dbContext.BeginTransaction(IsolationLevel.ReadUncommitted);
                     
                    业务逻辑                _dbContext.Commit();            }
                catch (***Exception)
                {
                    _dbContext.Rollback();
                    throw;
                }
                catch (Exception e)
                {
                    _dbContext.Rollback();            }
      

  15.   

    DAL中的方法调用DBContext 中封装的方法如ExecuteNonQuery, 或ExecuteReader去执行数据访问操作
      

  16.   

    如果是 asp.net 的項目的話,可以用到asp.net頁面級別事務,