我可以一笔交易付多少钱?

时间:2019-09-19 16:36:02

标签: c# nhibernate

这是建立在"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();
}

我假设所有事情都应该进行一次交易。 有限制吗?
在一笔交易以某种方式“崩溃”之前,我可以投入多少钱?

2 个答案:

答案 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();
    }
}

现在我的交易代码包含得很好,不必在您的控制器方法中乱七八糟。