嘿,伙计们,我在这里遇到一些小问题,我正试着把头包起来。
我目前正在开始使用nHibernate,因此我必须满足工作要求,而且我对nHibernate的Sessions和多线程感到困惑。我想在这里完成的任务是让Log4Net将所有内容记录到数据库中,包括nHibernate的调试/错误等。
所以我所做的就是创建一个非常简单的Log4Net:AppenderSkeleton类,在需要它时可以完美地激活它。我遇到的最初的问题是,当我使用GetCurrentSession时,显然因为Log4Net在一个单独的线程上运行,所以它在初始线程的会话中出错了。所以我想我必须为Log4Net AppenderSkeleton类创建一个新的nHiberante Session。代码如下:
public class Custom : AppenderSkeleton
{
protected override void Append(LoggingEvent loggingEvent)
{
if (loggingEvent != null)
{
using (ISession session = NHibernateHelper.OpenSession())
{
using (ITransaction tran = session.BeginTransaction())
{
Log data = new Log
{
Date = loggingEvent.TimeStamp,
Level = loggingEvent.Level.ToString(),
Logger = loggingEvent.LoggerName,
Thread = loggingEvent.ThreadName,
Message = loggingEvent.MessageObject.ToString()
};
if (loggingEvent.ExceptionObject != null)
{
data.Exception = loggingEvent.ExceptionObject.ToString();
}
session.Save(data);
tran.Commit();
}
}
}
}
真的很简单,虽然它现在处于基本形式,但我会有更多的错误检查信息等但是现在的问题是,虽然这完美地工作但它创建了多个会话。也就是说,它会记录每个错误,因为我无法使用GetCurrentSession,因为这将获得调用Session(主程序流)。我确信有一种方法可以为Log4Net的线程全局创建一个会话,但我不确定。请记住,我已经使用Global.asax(Application_BeginRequest)中的以下内容将会话绑定到初始线程:
ISession session = NHibernateHelper.OpenSession();
CurrentSessionContext.Bind(session);
对于那些会问的人,我的助手的内容在下面(这是在DLL中):
public static class NHibernateHelper
{
private static Configuration _nHibernateConfig;
private static ISessionFactory _nHibernateSessionFactory;
private static ISessionFactory BuildNHibernateSessionFactory
{
get
{
if (_nHibernateSessionFactory == null)
{
if (_nHibernateConfig == null)
{
BuildSessionFactory();
}
_nHibernateSessionFactory = _nHibernateConfig.BuildSessionFactory();
}
return _nHibernateSessionFactory;
}
}
private static Configuration BuildNHibernateConfig
{
get
{
if (_nHibernateConfig == null)
{
_nHibernateConfig = new ConfigurationBuilder().Build();
}
return _nHibernateConfig;
}
}
public static Configuration nHibernateConfig
{
get
{
return _nHibernateConfig;
}
}
public static ISessionFactory nHibernateSessionFactory
{
get
{
return _nHibernateSessionFactory;
}
}
public static Configuration BuildConfiguration()
{
return BuildNHibernateConfig;
}
public static ISessionFactory BuildSessionFactory()
{
return BuildNHibernateSessionFactory;
}
public static ISession OpenSession()
{
return _nHibernateSessionFactory.OpenSession();
}
public static ISession GetCurrentSession()
{
try
{
return _nHibernateSessionFactory.GetCurrentSession();
}
catch (HibernateException ex)
{
if(ex.Message == "No session bound to the current context")
{
// See if we can bind a session before complete failure
return _nHibernateSessionFactory.OpenSession();
}
else
{
throw;
}
}
catch (Exception ex)
{
throw;
}
}
}
我意识到我可以在log4net中使用ADO appender,但我希望直接使用nHibernate将数据添加到数据库中。原因是当nHibernate已经工作时我不想乱用连接线等。
与往常一样,任何帮助都会受到赞赏。
- 修改: -
因此,基于我最初告诉我的内容,我修改了自定义Log4Net记录器代码。下面有两个版本。我的问题,哪个最好还是有更好的方法?
根据nHibernate教授的说法,第一个只创建两个会话 - 初始会话用于主程序流程,第二个用于我的Log4Net记录器代码。然而,在第二次会议中有数百个企业,抱怨有太多的企业家和许多人打电话到数据库。
第二个,nHibernate教授显示了许多会话,与主程序流的记录器+1调用一样多的会话。然而,在nHprof上没有任何投诉。虽然我有这样的感觉,即举行那么多会议会让人皱眉或任务太多。
无论如何代码:
代码1 -
protected override void Append(LoggingEvent loggingEvent)
{
if (!System.Web.HttpContext.Current.Items.Contains("Log4Net nHibernate Session"))
{
System.Web.HttpContext.Current.Items.Add("Log4Net nHibernate Session", NHibernateHelper.OpenStatelessSession());
}
IStatelessSession statelessSession = System.Web.HttpContext.Current.Items["Log4Net nHibernate Session"] as IStatelessSession;
if (statelessSession != null && loggingEvent != null)
{
using (ITransaction tran = statelessSession.BeginTransaction())
{
Log data = new Log
{
Id = Guid.NewGuid(),
Date = loggingEvent.TimeStamp,
Level = loggingEvent.Level.ToString(),
Logger = loggingEvent.LoggerName,
Thread = loggingEvent.ThreadName,
Message = loggingEvent.MessageObject.ToString()
};
if (loggingEvent.ExceptionObject != null)
{
data.Exception = loggingEvent.ExceptionObject.ToString();
}
statelessSession.Insert(data);
tran.Commit();
}
}
}
代码2 -
protected override void Append(LoggingEvent loggingEvent)
{
if (loggingEvent != null)
{
using (IStatelessSession statelessSession = NHibernateHelper.OpenStatelessSession())
using (ITransaction tran = statelessSession.BeginTransaction())
{
Log data = new Log
{
Id = Guid.NewGuid(),
Date = loggingEvent.TimeStamp,
Level = loggingEvent.Level.ToString(),
Logger = loggingEvent.LoggerName,
Thread = loggingEvent.ThreadName,
Message = loggingEvent.MessageObject.ToString()
};
if (loggingEvent.ExceptionObject != null)
{
data.Exception = loggingEvent.ExceptionObject.ToString();
}
statelessSession.Insert(data);
tran.Commit();
}
}
}
答案 0 :(得分:1)
你是关于创建一个新会话的。你绝对不希望跨线程共享同一个会话。在您的日志记录实例中,我甚至会说使用IStatelessSession。会话也应该相当轻量级,所以每次记录语句时我都不会担心创建新的会话。
答案 1 :(得分:1)
NHibernate已在内部使用Log4Net,因此您只需启用记录器并使用AdoNetAppender将日志发送到您的数据库。
<log4net>
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
...
</appender>
<logger name="NHibernate">
<level value="WARN"/>
<appender-ref ref="AdoNetAppender"/>
</logger>
</log4net>