在NHibernate中为长时间运行的任务确定事务和会话的范围

在NHibernate中为长时间运行的任务确定事务和会话的范围,nhibernate,transactions,unit-of-work,Nhibernate,Transactions,Unit Of Work,在web应用程序中使用NHibernate时,我通常会让我的IoC容器根据请求打开和关闭ISession,并提交/回滚事务。HTTP的性质使得在此类应用程序中定义清晰的工作单元非常容易 现在,我的任务是编写一个小程序,由任务调度器定期调用,用于发送新闻稿。在我们的领域模型中,时事通讯和订户的概念已经是定义良好的实体,向所有订户发送时事通讯将涉及到类似的操作: var subscribers = _session .QueryOver<Subscription>() .

在web应用程序中使用NHibernate时,我通常会让我的IoC容器根据请求打开和关闭
ISession
,并提交/回滚事务。HTTP的性质使得在此类应用程序中定义清晰的工作单元非常容易

现在,我的任务是编写一个小程序,由任务调度器定期调用,用于发送新闻稿。在我们的领域模型中,时事通讯和订户的概念已经是定义良好的实体,向所有订户发送时事通讯将涉及到类似的操作:

var subscribers = _session
    .QueryOver<Subscription>()
    .Where(s => !s.HasReceivedNewsletter)
    .List();

foreach (var subscriber in subscribers)
{
    SendNewsletterTo(subscriber);
    subscriber.HasReceivedNewsletter = true;
}
var订户=\u会话
.QueryOver()
.其中(s=>!s.HasReceivedNewsletter)
.List();
foreach(订阅服务器中的var订阅服务器)
{
发送至(订户);
subscriber.HasReceivedNewsletter=true;
}
请注意,每个
订阅者
对象在循环中是如何更新的,记录下她现在已经收到了时事通讯。这个想法是,如果邮件发送程序崩溃,它可以重新启动,并从停止的地方继续发送新闻稿

我面临的问题是在这里定义和实现工作单元模式。我可能需要在循环的每个迭代结束时提交对数据库的更改。使用(var trans=\u session.BeginTransaction())块简单地用
包装循环体在运行时间上似乎非常昂贵,而且我似乎还遇到了这个长时间运行的进程与使用相同数据库的其他(web)应用程序之间的锁定问题

在阅读了一些关于NHibernate事务的文章和文档之后,我开始思考,我可能需要从会话中分离订阅者列表以避免锁定问题,并将每个订阅者重新附加到循环体中的新会话。不过,我不确定这对性能有何影响


那么,NHibernate专家,您将如何设计和实现这样一个长时间运行的任务?

您不认为没有事务的无状态会话在这里会更好吗?

您不想在这里使用异步持久消息传递吗?像NServiceBus、Rhino Service Bus或MassTransit之类的服务。似乎您不必尽快发送大量消息,因此我认为您应该异步发送,每个用户发送一条持久消息

在一个会话中有多个事务是没有问题的。在这里,将事务范围限定为更新单个订户是合适的,因为它是一个独立的操作。根据订阅者的数量和失败的可能性,最好一次抓住一小部分订阅者

foreach (var subscriber in subscribers)
{
    using (var txn = _session.BeginTransaction())
    {
        try
        {
            SendNewsletterTo(subscriber);
            subscriber.HasReceivedNewsletter = true;
            txn.Commit();
        }
        catch (Exception ex)
        {
            txn.Rollback();
            // log exception, clean up any actions SendNewsletterTo has taken if needed
            // Dispose of session and start over
        }   
    }
}

以前从未听说过,但从谷歌的前几行来看,情况可能就是这样。请告诉我更多关于它将如何以及为什么解决我的问题:)由于“无状态会话”提示,我将接受这个答案。然而,我保留了我的投票权,希望@Sly(或其他任何人)能在这个主题上做一些扩展,为了社区的利益:)无状态会话不能只对HasReceivedNewsletter标志进行动态更新,稍后将对完整订户行进行更新,或者您必须手动更新,可能是通过HQL更新。无状态会话就像根本没有会话一样,只使用NHibernate将数据库行强制转换为NHibernate对象。对此,您可能不需要显式事务-此循环将创建原子单更新命令。