E客开发团队-互联网架构提供服务商
设为首页 设为首页  加入收藏 加入收藏  联系我们 联系我们 
  • 首  页
  • 关于我们
  • eFrameWork框架
  • 案例鉴赏
  • 网站模板
  • 技术文档
  • 帮助中心
  • EKECMS下载
  • 在线留言
  • 联系我们
帮助中心更多...
  • 企业网站建设的重要性
  • 企业网站建设准则
  • 企业网站如何定位
  • 企业为什么要建设网站?
  • 专业术语解释
  • 选择E客开发团队有哪些优势?
  • 做网站应该注意哪些问题?
  • 做网站有哪些费用?








首 页 -> 技术文档 -> 解决访问量大的数据库模型

解决访问量大的数据库模型

作者.中国E客  日期.2012-05-10  来源.www.eketeam.com  浏览.


在使用SqlCommand对象过程中,我们需要分配Connection对象。 通常,对于大型的Entity业务模型来说分配新的SqlConnection的操作非常频繁。要利用Pool的优化功能,就要想到保持Connection对象。由此想到可以把Connection和Transaction都保存到ConnectionProxy对象中。而此对象继承IDisposable仅仅存在于一个Request过程中。作为一个适用广泛的模型,我们建立ExecutionContext对象来封装对ConnectionProxy操作。

以下是ConnectionProxy代码:


    internal class ConnectionProxy : IDisposable
    {
        private string _connectionString = null;
        private SqlConnection _connection;
        private SqlTransaction _transaction;
        private int _tranCount = 0;

        /**//// <summary>
        /// Constructs a new ConnectionProxy instance, setting the connection string
        /// </summary>
        /// <param name="ConnectionString">A valid database connection string</param>
        internal ConnectionProxy(string connectionString)
        {
            _connectionString = connectionString;
        }

        /**//// <summary>
        /// Frees any connection related resources
        /// </summary>
        public void Dispose()
        {
            // ensure that the connection does not have a pending transaction
            if (_tranCount != 0)
            {
                // rollback the transaction stack until the rollback already occurs
                while (_tranCount > 0) this.RollbackTransaction();

                throw new DataAccessException("Dispose was called on a connection with a pending transaction. The transaction will be aborted.");
            }

            // close the connection if it is open
            if ((_connection != null) && (_connection.State == ConnectionState.Open))
            {
                _connection.Close();
            }

            _connection = null;
        }

        /**//// <summary>
        /// Gets the current connection object
        /// </summary>
        internal SqlConnection Connection
        {
            get
            {
                // check that the connection string property has been set
                if (_connectionString == null)
                {
                    //throw new DataAccessException("Connection string has not been set.");
                }

                // create new connection and open if one does not yet exist
                if (_connection == null)
                {
                    _connection = new SqlConnection(_connectionString);
                    _connection.Open();
                    //while (_connection.State == ConnectionState.Open) ;
                }

                return _connection;
            }
        }

        /**//// <summary>
        /// Gets the current transaction context object
        /// </summary>
        internal SqlTransaction Transaction
        {
            get
            {
                return _transaction;
            }
        }

        /**//// <summary>
        /// Begins a new transaction
        /// </summary>
        internal void BeginTransaction()
        {
            // only actually begin a new transaction if a transaction context does not yet exist
            if (_tranCount == 0)
            {
                // create new transaction context at the specified isolation level
                _transaction = Connection.BeginTransaction(IsolationLevel.Serializable);
            }

            _tranCount++;
        }

        /**//// <summary>
        /// Commits a pending transaction
        /// </summary>
        internal void CommitTransaction()
        {
            // check that a transaction context actually exists
            if (_tranCount <= 0) throw new DataAccessException("No transaction is pending");

            _tranCount--;

            // check if an actual commit should occur
            if (_tranCount == 0)
            {
                // if trancount is zero, but we don't have a transaction then something is wrong
                if (_transaction == null)
                {
                    throw (new DataAccessException("Transaction stack indicated a commit but no transaction exists!"));
                }

                // actually commit the transaction
                _transaction.Commit();
                _transaction = null;
            }
        }

        /**//// <summary>
        /// Rolls back a pending transaction
        /// </summary>
        internal void RollbackTransaction()
        {
            // check that a transaction context actually exists
            if (_tranCount <= 0) throw new DataAccessException("No transaction is pending");

            _tranCount--;

            // check if an actual rollback should occur
            if (_tranCount == 0)
            {
                // if trancount is zero, but we don't have a transaction then something is wrong
                if (_transaction == null)
                {
                    throw (new DataAccessException("Transaction stack indicated a rollback but no transaction exists!"));
                }

                // actually rollback the transaction
                _transaction.Rollback();
                _transaction = null;
            }
        }
    }


之后我们可以建立ExecutionContext.目的是使用这个Proxy.当然也可以保存和使用其他的实例化对象:

    public sealed class ExecutionContext
    {
        private static string ConnProxy = "ConnProxy";
        private static string ConfigProxy = "Config";

        private static ConnectionProxy _ConnProxy;
        private static Config _Config;


        /**//// <summary>
        /// This class cannot be instantiated
        /// </summary>
        private ExecutionContext()
        {
        }

        /**//// <summary>
        ///
        /// </summary>
        private static ConnectionProxy ConnectionProxy
        {
            get
            {
                if (HttpContext.Current != null) //web app
                    return (ConnectionProxy)HttpContext.Current.Items[ConnProxy];
                else
                    return _ConnProxy;
            }
            set
            {
                if(HttpContext.Current != null) //web app
                    HttpContext.Current.Items.Add(ConnProxy, value);
                else
                    _ConnProxy = value;
            }
        }

        private static Config Config
        {
            get
            {
                if (HttpContext.Current != null) //web app
                    return (Config)HttpContext.Current.Items[ConfigProxy];
                else
                    return _Config;
            }
            set
            {
                if (HttpContext.Current != null) //web app
                    HttpContext.Current.Items.Add(ConfigProxy, value);
                else
                    _Config = value;
             }
         }

         /**//// <summary>
         /// Returns the connection object for the current execution context
         /// </summary>
        public static SqlConnection Connection
        {
             get
            {
                 AssertInitialisation();
                 return ConnectionProxy.Connection;
             }
         }

         /**//// <summary>
         /// Returns the current transaction object for the current execution context
         /// </summary>
        public static SqlTransaction Transaction
        {
             get
            {
                 AssertInitialisation();
                 return ConnectionProxy.Transaction;
             }
         }

         /**//// <summary>
         /// </summary>
         public static Config Configuration
        {
             get
            {
                 if (Config == null)
                     throw new Exception("Config.xml cannot be loaded!");
                 return Config;
             }
         }
         /**//// <summary>
         /// Begins a new execution context
         /// </summary>
        public static void Begin()
        {
             // cleanup from any previous Begin calls
             End();

             // create a configuration object
             Config = new Config();

             // create a new database connection proxy
             ConnectionProxy = new ConnectionProxy(Config.ConnectionString);
            
         }

         /**//// <summary>
         /// Ends the current execution context and cleans up any resources used
         /// </summary>
         public static void End()
        {
             // clean up any objects that have not been cleaned up since the last Begin call on the thread
             if (ConnectionProxy != null) ConnectionProxy.Dispose();

             if (HttpContext.Current != null) //web app
            {
                 HttpContext.Current.Items.Remove(ConnProxy);
                 HttpContext.Current.Items.Remove(ConfigProxy);
             }
         }

         /**//// <summary>
         /// Begins a new transaction
         /// </summary>
        public static void BeginTransaction()
        {
             AssertInitialisation();
             ConnectionProxy.BeginTransaction();
         }

         /**//// <summary>
         /// Commits the current transaction
         /// </summary>
        public static void CommitTransaction()
        {
             AssertInitialisation();
             ConnectionProxy.CommitTransaction();
         }

         /**//// <summary>
         /// Rolls back the current transaction
         /// </summary>
        public static void RollbackTransaction()
        {
             AssertInitialisation();
             ConnectionProxy.RollbackTransaction();
         }

         /**//// <summary>
         /// Asserts that the execution context has been correctly initialised
         /// </summary>
        private static void AssertInitialisation()
        {
             if (ConnectionProxy == null)
            {
                 throw new ExecutionContextException("Execution Context has not been initialised.");
             }
         }
     }

使用的时候,要在Global.asax的Application_BeginRequest中加入:ExecutionContext.Begin();和Application_EndRequest中加入:ExecutionContext.End();也可以在WinForm程序的Application中加入这2行。

准备工作完成后我们就可以来测试了:
             ExecutionContext.BeginTransaction();
            try
            {
                 cmd.Connection = ExecutionContext.Connection;
                 cmd.Transaction = ExecutionContext.Transaction;
                 cmd.ExecuteNonQuery();

                 ExecutionContext.CommitTransaction();
             }
            catch
            {
                 ExecutionContext.RollbackTransaction();
                 throw;
             }
总结:
非常有效的数据库/配置文件访问模型。成功使用在几万流量的网站上。任何建议欢迎大家留言交流。


  • 上一篇:ASP.NET 中通过使用 Visual C#.net 的高速缓存
  • 下一篇:没有了
【返回】 【顶部】 【关闭】

 ↓评论信息
暂时还没有评论!
 ↓发表评论
Name 您的姓名
Email 电子邮件

Comment 评论内容


Auth Code 验证码
 *


评论内容不能超过150个字符
 *  

所有评论只代表网友个人观点,不代表本站观点。请各位遵纪守法并注意语言文明。

CopyRight © 2010-2018 All EkeTeam.com rights reserved Template designed Technology report by EKETEAM. E客开发团队·官方网站 版权所有 
备案编号:滇ICP备18000718号-2