目前在我们的ASP.NET应用程序中,每个请求有1个会话,每次加载或更新和对象时都会创建一个事务。见下文:
public static T FindById<T>(object id)
{
ISession session = NHibernateHelper.GetCurrentSession();
ITransaction tx = session.BeginTransaction();
try
{
obj = session.Get<T>(id);
tx.Commit();
}
catch
{
session.Close();
throw;
}
finally
{
tx.Dispose();
}
return obj;
}
public virtual void Save()
{
ISession session = NHibernateHelper.GetCurrentSession();
ITransaction transaction = session.BeginTransaction();
try
{
if (!IsPersisted)
{
session.Save(this);
}
else
{
session.SaveOrUpdateCopy(this);
}
transaction.Commit();
}
catch (HibernateException)
{
if (transaction != null)
{
transaction.Rollback();
}
if (session.IsOpen)
{
session.Close();
}
throw;
}
finally
{
transaction.Dispose();
}
}
显然这并不理想,因为这意味着每次加载或保存对象时都会创建与数据库的新连接,从而导致性能开销。
问题:
不幸的是,应用程序代码可能过于成熟,无法构建所有内容(在同一事务中使用get和update all):
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction())
{
var post = session.Get<Post>(1);
// do something with post
tx.Commit();
}
为每个请求创建一个事务并在请求结束时提交它会是一个可怕的想法吗?我猜不到的缺点是它会在非数据库操作发生时占用一个数据库连接。
答案 0 :(得分:5)
每个请求的一个事务被认为是NHibernate的最佳实践。此模式在Sharp Architecture中实现。
但是在Nhibernate方法BeginTransaction()
中,doest打开与DB的连接。连接在第一个真正的sql请求时打开,并在执行查询后立即关闭。所以Nhibernate持有开放连接几秒钟来执行查询。您可以通过SQL事件探查器验证它。
此外,NHiberante总是尝试使用Sql Servers连接池,并且为什么打开连接可能不会那么昂贵。
答案 1 :(得分:2)
为每个请求创建一个事务并在请求结束时提交它是否是一个可怕的想法
这不会很糟糕,但我认为这是一种糟糕的做法。如果出现错误并且事务被回滚,我宁愿在页面上处理它,然后在请求结束时处理它。我希望每个请求使用一个会话,并在请求期间使用尽可能多的事务(通常是一个)。
NHibernate非常认真地管理数据库连接,在大多数情况下你不必担心它。
我不喜欢你的事务逻辑,特别是因为如果事务失败就会终止会话。而且我不确定你为什么要调用SaveOrUpdateCopy。 NHibernate将检测是否需要持久保存对象,因此可能不需要进行IsPersisted检查。我使用这种模式:
using (var txn = session.BeginTransaction())
{
try
{
session.SaveOrUpdate(this);
txn.Commit();
}
catch (Exception ex)
{
txn.Rollback();
// log
// handle, wrap, or throw
}
}