C# 在nhibernate中的一个会话中是否可以发生多个事务?这是个坏主意吗?
我正在考虑为NHibernate持久层创建自己的C# 在nhibernate中的一个会话中是否可以发生多个事务?这是个坏主意吗?,c#,nhibernate,transactions,unit-of-work,C#,Nhibernate,Transactions,Unit Of Work,我正在考虑为NHibernate持久层创建自己的IUnitOfWork实现 似乎正确的方法是在构造函数中实例化ISession和ITransaction,然后在析构函数或Dispose()方法中进行处理 当然,如果有人调用Save()方法,那么ISession将被刷新,ITransaction将完成,因此在调用Save()之后,将不会有一个有效的打开事务再次进入Save()。。。除非我提交了第一笔交易并立即打开了另一笔新交易。但这是个好主意吗 就设计而言,执行一个提交操作是有意义的,但我不一定能
IUnitOfWork
实现
似乎正确的方法是在构造函数中实例化ISession
和ITransaction
,然后在析构函数或Dispose()
方法中进行处理
当然,如果有人调用Save()
方法,那么ISession
将被刷新,ITransaction
将完成,因此在调用Save()
之后,将不会有一个有效的打开事务再次进入Save()
。。。除非我提交了第一笔交易并立即打开了另一笔新交易。但这是个好主意吗
就设计而言,执行一个提交操作是有意义的,但我不一定能控制代码,其他开发人员可能对遵循UnitOfWork模式的纪律性较低
通过尝试使UnitOfWork对每个会话的多个事务具有容错性,我是否会有所损失/收获?我是否应该检查一个打开的事务并在它已经提交时抛出一个异常,而不是创建一个新的事务?有多个选项可以使用工作单元实现nhibernate嵌套事务
public interface IAction
{
void Execute();
}
public abstract class Action<T> : IAction, IDisposable where T : Action<T>
{
public void Execute()
{
try
{
//Start unit of work by your unit of work pattern or
transaction.Begin();
OnExecute();
//End Unit of work
transaction.Commit();
}
catch (Exception e)
{
transaction.Rollback();
throw e;
}
}
protected abstract void OnExecute();
public void Dispose()
{
}
}
public class MyBusinessLogic : Action<MyBusinessLogic>
{
protected override void OnExecute()
{
//Implementation
}
}
public class MyAnotherBusinessLogic : Action<MyAnotherBusinessLogic>
{
protected override void OnExecute()
{
//Nested transaction
MyBusinessLogic logic = new MyBusinessLogic();
logic.Execute();
}
}
这里我使用命令模式作为工作单元
public interface IAction
{
void Execute();
}
public abstract class Action<T> : IAction, IDisposable where T : Action<T>
{
public void Execute()
{
try
{
//Start unit of work by your unit of work pattern or
transaction.Begin();
OnExecute();
//End Unit of work
transaction.Commit();
}
catch (Exception e)
{
transaction.Rollback();
throw e;
}
}
protected abstract void OnExecute();
public void Dispose()
{
}
}
public class MyBusinessLogic : Action<MyBusinessLogic>
{
protected override void OnExecute()
{
//Implementation
}
}
public class MyAnotherBusinessLogic : Action<MyAnotherBusinessLogic>
{
protected override void OnExecute()
{
//Nested transaction
MyBusinessLogic logic = new MyBusinessLogic();
logic.Execute();
}
}
公共接口接口接口
{
void Execute();
}
公共抽象集体诉讼:IAction,IDisposable,其中T:Action
{
public void Execute()
{
尝试
{
//根据您的工作单元模式或
transaction.Begin();
OnExecute();
//结束工作单位
Commit();
}
捕获(例外e)
{
transaction.Rollback();
投掷e;
}
}
受保护的抽象void OnExecute();
公共空间处置()
{
}
}
公共类MyBusinessLogic:操作
{
受保护的覆盖void OnExecute()
{
//实施
}
}
公共类MyAnotherBusinessLogic:行动
{
受保护的覆盖void OnExecute()
{
//嵌套事务
MyBusinessLogic逻辑=新的MyBusinessLogic();
logic.Execute();
}
}
我认为每个工作单元有一个事务的解决方案限制太多。在某些环境中,每个会话可能需要执行多个事务的能力。我自己明确地管理事务,这似乎是一个灵活的解决方案
public interface IUnitOfWork: IDisposable
{
IGenericTransaction BeginTransaction();
}
public interface IGenericTransaction: IDisposable
{
void Commit();
void Rollback();
}
public class NhUnitOfWork: IUnitOfWork
{
private readonly ISession _session;
public ISession Session
{
get { return _session; }
}
public NhUnitOfWork(ISession session)
{
_session = session;
}
public IGenericTransaction BeginTransaction()
{
return new NhTransaction(_session.BeginTransaction());
}
public void Dispose()
{
_session.Dispose();
}
}
public class NhTransaction: IGenericTransaction
{
private readonly ITransaction _transaction;
public NhTransaction(ITransaction transaction)
{
_transaction = transaction;
}
public void Commit()
{
_transaction.Commit();
}
public void Rollback()
{
_transaction.Rollback();
}
public void Dispose()
{
_transaction.Dispose();
}
}
用法如下所示。它很容易融入任何模式
public void Do(IUnitOfWork uow)
{
using (var tx = uow.BeginTransaction()) {
// DAL calls
tx.Commit();
}
}
回答第一个问题:是的,一个会话中可能有多个事务 这是个好主意吗?视情况而定 问题是第一个事务中更改的数据将被提交,而不确定整个工作单元(会话)是否在最后提交。比如说,当您在以后的事务中收到StaleObjectException时,您已经提交了一些数据。请注意,这种异常会使会话无法使用,因此您必须销毁它。那就很难重新开始,再试一次 我要说的是,在这种情况下,它运行良好:
- 它是一个UI应用程序
- 更改仅在最后一个事务中刷新
我将整个事务处理简化到绝对最小,以使其稳定和“防白痴”。我总是同时创建一个会话和一个事务,它要么提交,要么不提交。它是为web应用程序设计的。我的理解是,
ITransaction.Commit()
调用将刷新会话。使用同一会话实例化新的ITransaction
,紧接着Commit()
,什么情况会生成StaleObjectException
?提交事务会释放锁。这使得它更有可能获得StaleObjectException。但无论如何都可以得到它们,因为在内存中更改数据时,数据可以在数据库中更改。NH的乐观锁定至少可以检测到这些冲突。感谢您提供的详细答案。只需指出几件事:1)已经有了一个系统。操作将使名称变得混乱。2) Action类没有定义事务的来源。3) 这仍然会导致与NHibernate中嵌套事务相同的错误(提交内部事务将使外部事务抛出ObjectDisposedException)。这正是我们所做的,但在这种情况下不起作用:我想无法在注释中进行代码编辑。。。但是如果你有另一个事务在里面,它就不起作用了。但它应该这样做。嵌套事务在数据库中实现是有充分理由的。