Web应用中优化IBatis性能
在我的一个项目中应用了IBatis.Net这个工具作为数据访问层,因为项目规模不大,尽量根据实际应用情况作业一些简化。比如,我们将IBastis.Net作为DAO层,而如果是面向不同的数据库,则直接每个数据库编写特定的映射文件;中间层并未采用IoC机制,采用最直接的new来实例化业务逻辑对象。
IBatis.Net的使用,采用一个非常常见的封装格式:
 internal class MyMapper
    {
        private static volatile SqlMapper _Mapper;
        /// <summary>
        /// static Configure constructor that can be
        /// used for callback
        /// </summary>
        /// <param name="obj"></param>
        protected static void Configure(object obj)
        {
            _Mapper = null;
        }
        /// <summary>
        /// Init the 'default' SqlMapper defined by the SqlMap.Config file.
        /// </summary>
        protected static void InitMapper()
        {
            DomSqlMapBuilder builder = new DomSqlMapBuilder();
            XmlDocument sqlMapConfig = Resources.GetEmbeddedResourceAsXmlDocument("gsh.Endow.SqlMap.config");
            _Mapper = (SqlMapper) builder.Configure(sqlMapConfig);
            _Mapper.SessionStore =new IBatisNet.DataMapper.SessionStore.HybridWebThreadSessionStore(_Mapper.Id);
            string DBConnectstring = ConfigurationManager.ConnectionStrings[ConfigClass.Instance().ConnectionString].ConnectionString;
            _Mapper.DataSource.ConnectionString = DBConnectstring;
        }
        /// <summary>
        /// Get the instance of the SqlMapper defined by the SqlMap.Config file.
        /// </summary>
        /// <returns>A SqlMapper initalized via the SqlMap.Config file.</returns>
        public static SqlMapper Instance()
        {
            if (_Mapper == null)
            {
                lock (typeof (SqlMapper))
                {
                    if (_Mapper == null) // double-check
                    {
                        InitMapper();
                    }
                }
            }
            return _Mapper;
        }
        /// <summary>
        /// Get the instance of the SqlMapper defined by the SqlMap.Config file. (Convenience form of Instance method.)
        /// </summary>
        /// <returns>A SqlMapper initalized via the SqlMap.Config file.</returns>
        public static SqlMapper Get()
        {
            return Instance();
        }
    }
未完成一个业务逻辑也许会多次调用MyMapper的实例方法,而在默认情况下,IBatis.Net会为每次调用单独维护一个数据库的连接。也就是调用方法时,首先打开连接,然后执行Sql语句,最后关闭连接。是一个典型的短连接的场景。
  /// <summary>
        /// Executes a Sql SELECT statement that returns that returns data 
        /// to populate a single object instance.
        /// <p/>
        /// The parameter object is generally used to supply the input
        /// data for the WHERE clause parameter(s) of the SELECT statement.
        /// </summary>
        /// <param name="statementName">The name of the sql statement to execute.</param>
        /// <param name="parameterObject">The object used to set the parameters in the SQL.</param>
        /// <returns> The single result object populated with the result set data.</returns>
        public T QueryForObject<T>(string statementName, object parameterObject)
        {
            bool isSessionLocal = false;
            ISqlMapSession session = _sessionStore.LocalSession;
            T result;
            if (session == null)
            {
                session = CreateSqlMapSession();
                isSessionLocal = true;
            }
            try
            {
                IMappedStatement statement = GetMappedStatement(statementName);
                result = statement.ExecuteQueryForObject<T>(session, parameterObject);
            }
            catch
            {
                throw;
            }
            finally
            {
                if (isSessionLocal)
                {
                    session.CloseConnection();
                }
            }
            return result;
        }
然而在访问量交大的时候,这种持续不断地连接、断开、再连接、再断开的场景对应用本身和数据库的性能都有一定的影响。因此我们能否在一个Http请求过程中只打开一个数据库连接呢?答案是肯定的,做起来也相当简单,我们可以做一个HttpModule,在BeginRequest中打开一个连接在EndRequest中关闭连接即可:
public class MyMapperModule : IHttpModule
    {
        /// <summary>
        /// 您将需要在您网站的 web.config 文件中配置此模块,
        /// 并向 IIS 注册此模块,然后才能使用。有关详细信息,
        /// 请参见下面的链接: http://go.microsoft.com/?linkid=8101007
        /// </summary>
        #region IHttpModule Members
        public void Dispose()
        {
            //此处放置清除代码。
        }
        public void Init(HttpApplication context)
        {
            // 下面是如何处理 LogRequest 事件并为其
            // 提供自定义日志记录实现的示例
            //context.LogRequest += new EventHandler(OnLogRequest);
            context.BeginRequest += new EventHandler(context_BeginRequest);
            context.EndRequest += new EventHandler(context_EndRequest);
        }
        void context_EndRequest(object sender, EventArgs e)
        {
            if(MyMapper.Instance().LocalSession!=null)
                MyMapper.Instance().CloseConnection();
        }
        void context_BeginRequest(object sender, EventArgs e)
        {
            HttpApplication application = (HttpApplication)sender;
            HttpContext context = application.Context;
            string filePath = context.Request.FilePath;
            string fileExtension =
                VirtualPathUtility.GetExtension(filePath);
            if(fileExtension==".aspx" || fileExtension==".ascx" || fileExtension==".asxd" || fileExtension==".ashx")
                MyMapper.Instance().OpenConnection();
        }
        #endregion
        public void OnLogRequest(Object source, EventArgs e)
        {
            //可以在此放置自定义日志记录逻辑
        }
    }
                    
                
                
            
        
浙公网安备 33010602011771号