2016-08-13 41 views
0

客户端提交提交语句,并收到一条消息,指出通信失败。出现这种类型的故障有几个原因,包括数据库实例故障或网络中断。在这种情况下,客户端不知道事务的状态。如何InnoDB的决心飞行交易?

如何InnoDB的解决这样的飞行交易? 交易是成功还是失败?

+0

在理论上忽略你对innodb和思考的具体问题,失败可能发生在请求处理的任何一个步骤,因此不会建议依赖数据库在发生故障时能够做什么。想象一下,当数据库希望告诉你“是的,我做到了”时,你发送一个请求并且通信失败(此外,假设你中间有一个**中介器**,并且中介器之间的通信失败和客户)。 – FDavidov

回答

1

从InnoDB的角度来看,一个事务正在运行或不。如果没有,它已被提交或回滚。

从客户端的角度来看,这确实是一个不明确的情况。

客户端恢复会话是不可能的,因为导致条件严重的网络错误的定义也严重到足以使会话(即拥有该事务的数据库连接)不可恢复。

如果服务器收到的提交,并用OK包回应,但网络错误从接收到OK防止客户端,然后在错误发生之前事务提交。向客户端发送OK数据包的网络错误预计会强制关闭连接,但事务已被提交,所以它当然会保留。

在另一方面,如果网络的错误到达服务器防止客户端的COMMIT消息,则两种状态是可能的:

  • 网络误差也导致TCP连接到服务器被关闭从服务器的角度来看 - 在这种情况下,交易立即回滚;或

  • 网络错误没有导致TCP连接到服务器被关闭,例如,如果有状态网络设备失去了它的状态表可能是这种情况。在这种情况下,连接将不可用并且不可恢复。该连接没有进一步的业务 - 无论是正版还是由网络基础设施欺骗 - 可能会被服务器接受,所以交易仍然未提交的,跑步,抱着什么锁可能已经举行,因为服务器是,首先,不知道客户事实上已经消失了。当服务器超时客户端连接或服务器主机上的IP堆栈强制连接发生错误时,事务将回滚,因为TCP保持活动失败。

这两种情况都会立即回滚事务,最终会一次回滚事务。

如果之前的错误,客户端就已经意识到它的连接标识符(SELECT CONNECTION_ID())的,如果连接然后恢复,它可以重新连接到服务器和查询内部INFORMATION_SCHEMAPROCESSLISTINNODB_TRX表,以发现是否其以前的连接仍然存在,并且连接是否有正在运行的事务。

  • 如果旧的连接仍然存在,且具有交易运行时,交易没有提交。应该使用KILL [connection_id]杀死旧线程,以便事务立即回滚。

  • 如果旧连接仍然存在,并且没有正在运行的事务,则提交成功,因为如果连接仍然存在,则没有其他原因会丢失事务,因为服务器不知道的网络错误(否则连接将会消失)。

  • 如果旧的连接不存在,前一个事务的状态是未知的,除了我们知道它不能继续运行;它可能已经提交或可能已经回滚。在保留了上一次交易中收集的其他信息(例如已分配的自动增量值)后,客户可以启发式地确定交易是否已完成。

但这种积极的后续一种罕见的发生似乎有些过度了许多环境中,类似这样的回复就足够(一个Web“我们很抱歉,您订货出了错”站点)或500 Internal Server Error可能足够用于API。

在API的情况下,幂等标记有时用于允许调用者安全地重试失败模糊的操作。

例如,考虑Amazon EC2“运行实例”API。 (这与问题没有直接关系,但它是我想要说明的行为的一个详尽记录的示例,即使您不使用或不熟悉Amazon EC2,原则上也应该有意义)。这个API允许你启动虚拟机,这当然会花费你的钱。如果在尝试启动机器时遇到网络超时,该怎么办?那么500 Internal Server Error响应呢?你应该再问一次吗?你现在是否有两台虚拟机,支付的金额是预期的两倍?不,你不会,因为那个API supports an idempotent token。这个令牌让您可以再次尝试 - 如果您使用相同的标记来制作语义相同的请求 - 而不会被误解为想要启动两台计算机。当他们试图处理你的请求时,他们检查他们是否已经用相同的标记处理了一个请求。如果他们有,并且如果这是对同一件事的请求,他们会返回他们打算第一次返回的相同成功响应,因为无论出于何种原因,您都不应该看到响应。同样,两个相同的请求与两个不同的标记都被非正式地解释为意味着你确实想要启动两台机器。

您可以使用唯一的键约束和唯一标识符(如UUID)在MySQL数据库中完成类似的操作,您可以在事务正在执行(或重试)时插入该UUID。

如果在您重新连接并重试时使用该唯一ID修改的表中有一行,则知道该事务实际上已提交(假设您使用的隔离级别为READ COMMITTED或更高)。

如果该行不存在,则知道事务已回退 - 或者在服务器尚未意识到连接已被放弃的情况下将回滚。如果其他事务仍在运行,那么该行看起来并不存在(也许取决于您的隔离级别 - 您可能会看到它),但是当您尝试重复插入时,您的事务应该阻止,因为原始(仍在运行但注定失败)事务在唯一索引中的行上存在冲突排他锁。尝试将重复行插入唯一键将阻塞,直到释放冲突锁,此时插入将成功,如果没有违反约束。

这确实是一个凌乱的边缘情况,需要处理,这是适当的过程 受影响的重要性。如果发生这样的错误,没有干净,优雅,简单,直接的出路,但希望以上是有用的信息。