nHibernate和多任务
我正在努力提高nHibernate(3.3.2.4000)应用程序(.NET 4.0)的性能。目前,我们正在一个接一个地执行CRUD操作,这会占用很多时间,所以我的计划是使用ConcurrentQueue和Tasks 我将代码重构为:nHibernate和多任务,nhibernate,concurrency,task,Nhibernate,Concurrency,Task,我正在努力提高nHibernate(3.3.2.4000)应用程序(.NET 4.0)的性能。目前,我们正在一个接一个地执行CRUD操作,这会占用很多时间,所以我的计划是使用ConcurrentQueue和Tasks 我将代码重构为: public void ImportProductsFromXml(string path) { List<Product> products = Mapper.GetProducts(path); v
public void ImportProductsFromXml(string path)
{
List<Product> products = Mapper.GetProducts(path);
var addQueue = new ConcurrentQueue<Product>(productsToAddUpdate);
var updateTasks = new List<Task>();
for (int i = 0; i < 5; i++)
{
var taskId = i + 1;
updateTasks.Add(Task.Factory.StartNew(() => ProcessAddQueue(taskId, products, addQueue)));
}
}
private void ProcessAddQueue(int taskId, List<Product> products, ConcurrentQueue<Product> queue)
{
Product result = null;
while (queue.TryDequeue(out result))
{
try
{
UpdateProducts(products, result);
}
catch (Exception ex)
{
Debug.WriteLine(string.Format("ProcessAddQueue: taskId={0}, SKU={1}, ex={2}", taskId, result.ProductId, ex));
}
}
}
private void UpdateProducts(List<Product> productsFromFile, Product product)
{
...code removed...
CatalogItem parentItem = _catalogRepository.GetByCatalogItemId(category);
...code removed...
_catalogRepository.Save(parentItem);
...code removed...
}
public CatalogItem GetByCatalogItemId(string catalogItemId)
{
using (ISession session = SessionFactory.OpenSession())
{
return session
.CreateCriteria(typeof (CatalogItem))
.Add(Restrictions.Eq("CatalogItemId", catalogItemId))
.List<CatalogItem>().FirstOrDefault();
}
}
所以我的想法是创建一个包含所有产品的concurrentqueue,然后一次处理5个产品
但是,我收到一个“线程被中止异常”:
at System.WeakReference.get_Target()
at System.Transactions.Transaction.JitSafeGetContextTransaction(ContextData contextData)
at System.Transactions.Transaction.FastGetTransaction(TransactionScope currentScope, ContextData contextData, Transaction& contextTransaction)
at System.Transactions.Transaction.get_Current()
at NHibernate.Transaction.AdoNetWithDistributedTransactionFactory.EnlistInDistributedTransactionIfNeeded(ISessionImplementor session)
at NHibernate.Impl.SessionImpl.get_PersistenceContext()
at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsTransient(SaveOrUpdateEvent event)
at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event)
at NHibernate.Impl.SessionImpl.FireSave(SaveOrUpdateEvent event)
at NHibernate.Impl.SessionImpl.Save(Object obj)
我做错了什么?Hibernate会话被用作工作单元。您可以打开会话,在其上打开事务,加载实体,修改实体,调用保存,提交/回滚事务,然后处置会话 您应该使用一个会话加载实体,然后保存它。当前,您正在使用一个会话加载实体,并使用其他会话保存实体。与并发访问相结合,这可能会导致问题 尝试使用相同的hibernate会话加载和保存实体
当使用上面提到的hibernate时,它应该是完全线程安全的。请注意,单个hibernate会话不是线程安全的。我正在研究这个建议,但是它需要大量重写我当前的存储库。目前,我遇到了一些例外情况,比如“一个不同的对象和一个相同的标识符值已经与一个不同的会话相关联”,但当我验证它是否适用于其他会话时,我会将其标记为一个答案me@Hos这只是猜测。我认为这可能是问题所在。在调用存储库上的save之前,我的业务逻辑多次访问数据库。我想这就是为什么我会对属于另一个会话的对象出错。您有这样一个场景的示例代码吗?我使用这种方法重写存储库:
at System.WeakReference.get_Target()
at System.Transactions.Transaction.JitSafeGetContextTransaction(ContextData contextData)
at System.Transactions.Transaction.FastGetTransaction(TransactionScope currentScope, ContextData contextData, Transaction& contextTransaction)
at System.Transactions.Transaction.get_Current()
at NHibernate.Transaction.AdoNetWithDistributedTransactionFactory.EnlistInDistributedTransactionIfNeeded(ISessionImplementor session)
at NHibernate.Impl.SessionImpl.get_PersistenceContext()
at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsTransient(SaveOrUpdateEvent event)
at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event)
at NHibernate.Impl.SessionImpl.FireSave(SaveOrUpdateEvent event)
at NHibernate.Impl.SessionImpl.Save(Object obj)