首页 > 编程 > .NET > 正文

效果很好的asp.net的数据库访问模型(优化,封装一体化)

2024-07-10 13:06:12
字体:
来源:转载
供稿:网友

非常有效的数据库/配置文件访问模型。成功使用在几万流量的网站上。任何建议欢迎大家交流。

在使用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;
            }
总结:
非常有效的数据库/配置文件访问模型。成功使用在几万流量的网站上。任何建议欢迎大家交流。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表