MySQL 事务 : reads while writing

标签 mysql transactions locking

我正在我正在开发的网站中实现 PayPal 付款标准。这个问题与PayPal无关,我只是想通过我的真实问题来提出这个问题。

PayPal 可以通过两种方式通知您的服务器有关付款的信息:

  1. PayPal IPN - 每次付款后,PayPal 都会向网址(由您选择)发送包含交易详细信息的(服务器到服务器)通知。
  2. PayPal PDT - 付款后(如果您在 PP 帐户中设置了此项)PayPal 会将用户重定向回您的网站,并在网址中传递交易 ID,以便您可以查询 PayPal 有关该交易的信息,以获取详细信息.

问题是,您无法确定哪一个先发生:

  • 您的服务器是否会收到 IPN 通知
  • 将用户重定向回您的网站

无论哪一个先发生,我都想确保我不会处理两次交易。 因此,在这两种情况下,我都会根据来自 paypal 的交易 ID(以及实际上的付款状态......但现在不重要)查询我的数据库,以查看我是否已经保存并处理了该交易。如果没有,我会对其进行处理,并将交易 ID 和其他交易详细信息保存到我的数据库中。

问题

如果我开始处理第一个请求(让它成为 PDT..因此用户被重定向回我的网站,但 IPN 尚未通知我的服务器),但在我实际将事务保存到之前,会发生什么数据库中,第二个(IPN)请求到达,它也会尝试处理事务,因为它在数据库中找不到它。

我很想确保当我将事务写入数据库时​​,没有其他查询可以读取该表,查找给定的事务 ID。

我正在使用 InnoDB,并且不想在写入时锁定整个表。 这可以简单地通过事务来解决吗?我必须“手动”锁定该行吗?我真的很困惑,我希望一些更有经验的mysql开发人员可以帮助我弄清楚这一点并解决问题。

最佳答案

native 数据库锁在 Web 上下文中几乎毫无用处,尤其是在这种情况下。 MySQL 连接通常不会以持久方式完成 - 当脚本关闭时,MySQL 连接也会关闭,所有锁都会被释放,并且任何正在进行的事务都会回滚。

例如

情况 1:您引导用户访问 PayPal 网站以完成购买

当他们离开 paypal 时,通过 http 重定向发送的脚本将终止并关闭。锁/事务被释放/回滚,并且就数据库而言,它们回到“原始”状态。他们的记录不再被锁定。

情况 2:Paypal 进行服务器到服务器响应。这将通过完全独立的 HTTP 连接来完成,与用户与服务器建立的连接完全不同。这意味着您在 yourserver<->user 连接中建立的任何锁定都将与 paypal<->yourserver session 不同,并且 paypal 响应将遇到锁定的表。当然,无法预测 PayPal 响应何时到来。如果网络之神向您微笑并且 PayPal 没有被淹没,您会很快收到响应,并且可能在用户<->您的连接仍然处于打开状态时得到响应。如果速度缓慢且响应延迟,则该响应可能会遇到未锁定的表/行,因为用户<->服务器 session 已完成。

可以使用持久的 MySQL 连接,但它们打开了另一个痛苦的世界。例如考虑这样的情况:您的脚本有一个错误,该错误在处理过程中被触发。你连接,做一些事务工作,设置一些锁......然后脚本就死了。因为 MySQL 连接是持久的,MySQL 将不会看到客户端脚本已终止,并且它将保持事务/锁定进行中。但连接仍然位于共享池中,等待另一个 session 来接收它。当它总是如此时,新脚本并不知道它已经获得了这种旧的“陈旧”连接。它将陷入一堆它不知道存在的锁和事务中。您很容易陷入这样的死锁情况,因为您的有缺陷的脚本已将垃圾转储到整个系统,而其他脚本无法处理这些垃圾。

基本上,除非您在系统顶部实现自己的锁定机制,例如UPDATE users SET Locked=1 WHERE id=XXX,您无法在 Web 上下文中使用 native 数据库锁定机制,除非在 1-shot-per-script 上下文中。绝不应该在多个独立请求上尝试锁定。

关于MySQL 事务 : reads while writing,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16342292/

相关文章:

MySQL 空间扩展 : Getting records that fall with in a certain area

java - 添加到表后读取数据返回零

database - 长期大量交易不好吗

java - Java 中的信号条件变量触发等待

multithreading - 使用依赖注入(inject)时如何使共享资源线程安全?

mysql - : proxy,端口和服务器有什么区别

mysql - 我什么时候应该将 JSON 存储在数据库中?

系统启动时 MySQL 同步

Spring:@Transactional with readonly=true 不调用 conn.setReadOnly(true)

SQLITE ODBC 驱动程序和数据库锁定