在我的一个项目中应用了IBatis.Net这个工具作为数据访问层,因为项目规模不大,尽量根据实际应用情况作业一些简化。比如,我们将IBastis.Net作为DAO层,而如果是面向不同的数据库,则直接每个数据库编写特定的映射文件;中间层并未采用IoC机制,采用最直接的new来实例化业务逻辑对象。
IBatis.Net的使用,采用一个非常常见的封装格式:internal class MyMapper
{
private static volatile SqlMapper _Mapper;
///
/// static Configure constructor that can be
/// used for callback
///
///
protected static void Configure(object obj)
{
_Mapper = null;
}
///
/// Init the 'default' SqlMapper defined by the SqlMap.Config file.
///
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;
}
///
/// Get the instance of the SqlMapper defined by the SqlMap.Config file.
///
/// A SqlMapper initalized via the SqlMap.Config file.
public static SqlMapper Instance()
{
if (_Mapper == null)
{
lock (typeof (SqlMapper))
{
if (_Mapper == null) // double-check
{
InitMapper();
}
}
}
return _Mapper;
}
///
/// Get the instance of the SqlMapper defined by the SqlMap.Config file. (Convenience form of Instance method.)
///
/// A SqlMapper initalized via the SqlMap.Config file.
public static SqlMapper Get()
{
return Instance();
}
}
未完成一个业务逻辑也许会多次调用MyMapper的实例方法,而在默认情况下,IBatis.Net会为每次调用单独维护一个数据库的连接。也就是调用方法时,首先打开连接,然后执行Sql语句,最后关闭连接。是一个典型的短连接的场景。///
/// Executes a Sql SELECT statement that returns that returns data
/// to populate a single object instance.
///
/// The parameter object is generally used to supply the input
/// data for the WHERE clause parameter(s) of the SELECT statement.
///
/// The name of the sql statement to execute.
/// The object used to set the parameters in the SQL.
/// The single result object populated with the result set data.
public T QueryForObject(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(session, parameterObject);
}
catch
{
throw;
}
finally
{
if (isSessionLocal)
{
session.CloseConnection();
}
}
return result;
}
然而在访问量交大的时候,这种持续不断地连接、断开、再连接、再断开的场景对应用本身和数据库的性能都有一定的影响。因此我们能否在一个Http请求过程中只打开一个数据库连接呢?答案是肯定的,做起来也相当简单,我们可以做一个HttpModule,在BeginRequest中打开一个连接在EndRequest中关闭连接即可:public class MyMapperModule : IHttpModule
{
///
/// 您将需要在您网站的 web.config 文件中配置此模块,
/// 并向 IIS 注册此模块,然后才能使用。有关详细信息,
/// 请参见下面的链接: http://go.microsoft.com/?linkid=8101007
///
#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)
{
//可以在此放置自定义日志记录逻辑
}
}