这是建立在"Should I always use transactions in nhibernate (even for simple reads and writes)? "上的。
要点是,即使对于这样的简单获取,我们也应该始终使用交易:
using (ITransaction transaction = session.BeginTransaction())
{
var printerJob2 = (PrinterJob) session.Get(typeof (PrinterJob), id);
transaction.Commit();
return printerJob2;
}
让我们考虑以下代码:
User user = session.Get<User>(userId);
if(user == null) return UnAuthorizedResult();
Order order = session.Get<Order>(orderId);
if(order == null) return BadRequestResult();
session.Delete<Order>(order);
transaction.Commit();
return OkResult();
我假设我不是要为每个数据库访问创建一个新的事务,因为那样会变得很混乱:
User user;
using (ITransaction transaction = session.BeginTransaction())
{
user = session.Get<User>(userId);
transaction.Commit();
}
if(user == null) return UnAuthorizedResult();
Order order;
using (ITransaction transaction = session.BeginTransaction())
{
order = session.Get<Order>(orderId);
transaction.Commit();
}
if(order == null) return BadRequestResult();
using (ITransaction transaction = session.BeginTransaction())
{
session.Delete<Order>(order);
transaction.Commit();
return OkResult();
}
我假设所有事情都应该进行一次交易。
有限制吗?
在一笔交易以某种方式“崩溃”之前,我可以投入多少钱?
答案 0 :(得分:1)
当您希望一堆更新全部成功或全部失败时,可以使用事务。通常,事情开始以一种惯常的方式从它那里移开,而转向容错的操作,如果再次尝试(而不是插入重复的记录-查找幂等性),则从失败的地方继续操作,并且通常更宽容这个世界充满了延迟,瞬态和变化无常的网络可靠性,不同的系统以及无法建立统一的事务(查找sagas)等问题,但从本质上讲,当您希望将其视为一次成功操作时就使用事务算了,还是没有。
进行读取交易毫无意义,并且一次更新几乎没有意义(除非您希望以后能够撤消该更新),但是如果您必须收集有关一个人并将其插入到17个不同的表中,您可以使用事务来确保所有工作都成功或全部失败,因此您不会有任何局部数据。如果出现故障,您不必担心会从17个插入中选择9个。您只是回滚了事务,这是因为插入从未发生过,尽管自动递增的数字可能仍然保持不变
在交易中可以收集多少数据是否有限制?从技术上讲是可以的,但是我认为如果您遵循下一个经验法则,那就是您不太可能用企业数据库破坏它们。
实际上,您可能希望使事务集尽可能小,以使某人在出错时将事情整理出去的麻烦最小。不要在同一笔交易中保存您整整一年获得的每个新客户,然后仅仅因为圣诞节就决定进行交易;一万个刀片插入的名称过长或圣诞节前夕服务器崩溃不理想
答案 1 :(得分:1)
因此,您示例中的代码有点混乱,在给定的控制器方法中,事务打开和关闭。您的示例中的代码基本上与不使用任何事务相同,因为每个步骤都会提交自己。我假设使用的是MVC应用程序,因为我在代码结尾附近看到了OKResult。
交易是工作的原子单位。如果您有3个步骤,但有一个步骤失败,则应在事务开始之前将所有内容回滚到最后一个已知状态。在Web场景中,这通常是请求。您会在Google“ hibernate per request”休眠状态中看到很多信息。话虽如此,我做了两件事以确保我坚持这种模式。
在global.asax中,我有这些帮助方法
public static ISession CurrentSession
{
get { return (ISession) HttpContext.Current.Items[Sessionkey]; }
private set { HttpContext.Current.Items[Sessionkey] = value; }
}
protected void Application_BeginRequest() { CurrentSession = SessionFactory.OpenSession(); }
protected void Application_EndRequest()
{
if (CurrentSession != null)
CurrentSession.Dispose();
}
然后,我也具有此属性,可以在方法或控制器级别使用该属性,以确保每个控制器动作在事务上都是正确的
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class TransactionAttribute : ActionFilterAttribute
{
private ITransaction Transaction { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
Transaction = MvcApplication.CurrentSession.BeginTransaction(System.Data.IsolationLevel.ReadCommitted);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (!Transaction.IsActive)
return;
if (filterContext.Exception == null)
{
Transaction.Commit();
return;
}
Transaction.Rollback();
}
}
现在我的交易代码包含得很好,不必在您的控制器方法中乱七八糟。