【问题标题】:Will a transaction always commit (making sure file is imported only once)?事务是否总是提交(确保文件只导入一次)?
【发布时间】:2013-09-04 12:39:18
【问题描述】:

我提出的问题需要一些介绍。我有一个应用程序,它每 5 分钟从一个文件夹中将小文件和电子邮件导入到它自己的 SQL Server 数据库中。

  1. 每个文件都必须导入
  2. 每个文件只能导入一次

现在第 1 部分没什么大不了的。然而,第 2 部分提出了一些担忧。如果文件在成功导入后无法删除(例如由于缺少访问权限),并且下次我的应用程序查看该文件夹时,文件将一次又一次地导入,直到有人修复访问权限问题。

因此我想知道以下方法是否可以安全工作,而不会丢失数据:

  1. 开始交易
  2. 将文件导入数据库
  3. 从文件夹中删除文件
  4. 提交事务(如果有错误则回滚)

这是我到达问题标题的地方:如果前面的步骤没有引发异常,最后一个提交步骤是否总是成功?在提交之前删除文件是否安全,而不冒丢失文件的风险?如果 SQL Server 在事务期间关闭怎么办?或者如果文件删除失败,我应该从数据库中删除记录吗?

【问题讨论】:

  • 在触发条件下 - 这将是一个 POST 提交操作。
  • 还要考虑一些唯一性,您可以在其上放置一个 UNIQUE 键以避免多次插入。

标签: c# sql sql-server transactions


【解决方案1】:

您所说的“事务”仅用于确保数据完全提交到数据库。为了增加持久性以确保文件不能多次导入,您有很多选项,但让我们考虑以下几点:

  1. 导入文件时,将文件名添加到作为唯一约束的表中,这样 SQL INSERT 就会失败,从而回滚整个“事务”。当然,这只有在文件名实际上是唯一的情况下才有效。如果文件名不是唯一的,那么看看你是否能找到足够的信息。通常,您可以添加其他域信息(例如发票编号、客户编号等)以使其独一无二,因此 INSERT 仍然失败。
  2. 保留所有已处理文件的列表,不再处理它们。您可以使用 XML 文件,甚至在内存中执行此操作,但这仍然存在风险,因为如果用户将一个同名的 新文件 放在那里 - 那么您实际上 想要 导入那个。我认为选项 1 是最好的选择。

您需要意识到的一件事是,您要管理两种不同的技术。文件的删除,或者我应该说是您的尝试,与数据库事务没有任何关系,除非您制作它。所以,假设你有这样的流程:

using (SqlConnection c ...)
using (SqlCommand cmd ...)
{
    SqlTransaction t = c.BeginTransaction();
    try
    {
        // update database

        // try to delete file

        t.Commit();
    }
    catch (Exception ex)
    {
        // you know something failed
        // you can catch more specific exceptions and respond here
    }
}

如果未达到t.Commit(),则数据库将不会更新。

【讨论】:

  • 这是否意味着只有在提交(第 4 步)之后,我才能 100% 确定文件已进入数据库?什么会导致提交失败?
  • @Daniel,是的,在Commit 成功之后,您知道它已进入数据库。然后,通过利用唯一键,您可以确保不会生成相同的文件,因为在更新期间将引发唯一约束错误,Commit 将失败。
  • @Daniel,有关流程的更多详细信息,请参阅我的编辑。
  • 感谢您的编辑。问题是:将 t.Commit();如果update和delete没有抛出异常,总是成功?
  • @Daniel,当然。它正在提交数据库事务。
【解决方案2】:

通常我会先将文件存档到另一个位置。然后我会设置一个地方来存储有关导入的元数据,该位置将存储文件名和文件日期以及导入的成功或失败。然后,您实际上可以证明每个文件都已导入,并且仍然会有任何失败的文件的副本。

然后我将在事务中运行该过程以导入文件。我会在开始导入事务之前将有关文件的元数据放入数据库(因此它不会;不会在失败时回滚),然后在提交之后,我会将信息添加到元数据以让我知道文件已成功进口的。当然,作为一名数据人员,我会在 SSIS 中完成所有这些工作,在那里我可以使用本机日志记录来帮助我记录每个步骤(有助于查看发生故障的位置)。导入完成后,我会从处理位置删除文件,但我会在存档位置保留一段时间。 (后来有一些关于为什么数据看起来像这样的问题,这有助于手头有实际文件向他们展示他们以这种方式发送给您的!)

【讨论】:

  • 恕我直言,将文件存档到另一个位置只会带来更多麻烦:另一个文件夹需要维护并担心其访问权限。文件名也不是唯一的(同名文件可以在几天后复制到文件夹中)。导入错误由应用程序处理。我无法解决的唯一问题是如果我无法删除文件会发生什么。
  • 如果你不归档文件,你会后悔的。我可以保证。您可以在归档时将日期时间添加到文件名中。访问权限通常不是问题。
【解决方案3】:

假设您使用的是较新版本的 windows (Vista+) 并且使用的是 NTFS,您可以在事务中登记文件操作。

我认为 .NET 库中尚不支持此功能,但有一个第三方库 here 可以让您执行以下操作:

// Wrap a file copy and a database insert in the same transaction
TxFileManager fileMgr = new TxFileManager();
using (TransactionScope scope1 = new TransactionScope())
{
    // Delete the file
    fileMgr.DeleteFile(fileName);

    // Do some database stuff
    dbMgr.ExecuteNonQuery(insertSql);

    scope1.Complete();
} 

【讨论】:

    猜你喜欢
    • 2021-12-13
    • 2017-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-03
    • 2015-08-04
    • 1970-01-01
    相关资源
    最近更新 更多