非常有效的數(shù)據(jù)庫(kù)/配置文件訪問(wèn)模型。成功使用在幾萬(wàn)流量的網(wǎng)站上。任何建議歡迎大家交流。
在使用sqlcommand對(duì)象過(guò)程中,我們需要分配connection對(duì)象。 通常,對(duì)于大型的entity業(yè)務(wù)模型來(lái)說(shuō)分配新的sqlconnection的操作非常頻繁。要利用pool的優(yōu)化功能,就要想到保持connection對(duì)象。由此想到可以把connection和transaction都保存到connectionproxy對(duì)象中。而此對(duì)象繼承idisposable僅僅存在于一個(gè)request過(guò)程中。作為一個(gè)適用廣泛的模型,我們建立executioncontext對(duì)象來(lái)封裝對(duì)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.目的是使用這個(gè)proxy.當(dāng)然也可以保存和使用其他的實(shí)例化對(duì)象:
    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.");
            }
        }
    }
使用的時(shí)候,要在global.asax的application_beginrequest中加入:executioncontext.begin();和application_endrequest中加入:executioncontext.end();也可以在winform程序的application中加入這2行。
準(zhǔn)備工作完成后我們就可以來(lái)測(cè)試了:
            executioncontext.begintransaction();
            try
            ...{
                cmd.connection = executioncontext.connection;
                cmd.transaction = executioncontext.transaction;
                cmd.executenonquery();
                executioncontext.committransaction();
            }
            catch
            ...{
                executioncontext.rollbacktransaction();
                throw;
            }
總結(jié):
非常有效的數(shù)據(jù)庫(kù)/配置文件訪問(wèn)模型。成功使用在幾萬(wàn)流量的網(wǎng)站上。任何建議歡迎大家交流。
| 
 
 | 
新聞熱點(diǎn)
疑難解答
圖片精選