MySQL MyISAM/InnoDB更新在两个连接上不是原子的(强制写入?)


MySQL MyISAM/InnoDB updates are not atomic across two connections (force write?)

更新:我们尝试简单地将数据库转换为InnoDB,但我们仍然遇到同样的问题。 autocommit开启。是否需要一些额外的语句来确保另一个连接可以看到更改?

更新2:通过将表设置为InnoDB并将全局事务隔离级别设置为SERIALIZABLE,我们设法使事情正常工作,但是这明显减慢了速度。此外,并非所有人都完全相信这已经解决了问题,因为减速可能只是给了竞争条件足够的时间以正确的顺序执行。无论如何,我们正在继续调查。


我在MySQL中遇到了一个问题,即从一个连接进行的写入没有立即从另一个连接中看到(这恰好是SOLR更新查询)。

它是这样的:

  1. 用户在 Web 应用中进行更改。
  2. 我们注意到当前的修订号r1。
  3. MySQL表(MyISAM)是用更改和下一个修订版r2编写的。[此时在代码中,更改应该已写入数据库,如果我们从同一连接再次查询它,我们将看到它。
  4. 我们通过http向Solr发出信号,以使用修订版r1更新自身。
  5. Solr(来自不同的连接)查询MySQL以获取r1>更改,但没有获取刚刚在步骤3中写入的更改。

这是预期/正常行为吗?我在文档中找不到任何表明更新不是跨连接的原子内容。请记住,在第二个连接发出更新自身的信号时,更改应该已经写入数据库。

如果这是正常行为,则必须有某种方法强制MySQL将其连接写入/刷新回磁盘以强制正常的原子操作并保证其他连接将看到更改。但是,同样,对于MyISAM表,我找不到任何提及这一点。

我还应该补充一点,如果我在步骤 1 和 2 之间明确放置短暂的延迟(4-4 秒),事情就会正常工作。

以下是我们正在运行的MySQL版本:

mysql-server-5.1.66-2.el6_3.x86_64
php-mysql-5.3.3-14.el6_3.x86_64
mysql-libs-5.1.66-2.el6_3.x86_64
mysql-5.1.66-2.el6_3.x86_64

MyISAM不会刷新到磁盘,它会写入文件系统缓冲区,操作系统最终会负责写入磁盘。

但无论如何,另一个查询,

即使是另一个会话中的查询,也应该能够立即读取MyISAM数据,即使它从文件系统缓冲区中读取它。 该部分应该对 mysqld 进程透明。

MyISAM中也没有事务隔离,因此没有未提交的更改。 无论事务隔离模式如何,任何会话都应该能够针对MyISAM表读取任何已完成的更改。

因此,如果您使用 MyISAM 表,您描述的步骤(步骤 5 看不到对 r2 的更改)应该永远不会发生。 因此,我猜你误解了操作顺序,你实际上是在尝试阅读实际上尚未进行的更改。

无论如何,这是没有意义的,因为你真的应该使用InnoDB。 那么事务隔离就很重要了。 您可能希望 READ-COMMITTED的事务隔离,它不会像 SERIALIZABLE 那样阻止并发,但它确实允许事务查看任何数据的最新版本。 也就是说,如果您提交更改,并且Solr正在使用READ-COMMITTED,则Solr应该立即看到更改。