我们遇到了一个非常奇怪的问题,不连接的并发PHP进程访问同一个表(使用表锁)。
不涉及复制,我们正在用PHP 5.6.40的mysql接口做一个单体(我知道,升级是时候了,我们正在努力)。
假设字段名的初始值"value">
PHP-Process 1: modify table
LOCK TABLE xyz WRITE;
UPDATE xyz SET value = 1;
UNLOCK TABLE xyz;
PHP-Process 2:取决于表中的值(例如检查访问权限)
SELECT value from xyz;
现在,如果我们设法使进程2停止并等待锁被释放,在本地开发环境(XAMPP, MariaDB 10.1.x)上,一切都很好,它将获得值1;
但是,在我们的生产服务器(DebianLinux, MySQL 5.6.x)上,值在查询结果中具体化似乎需要等待一段时间。
- 立即SELECT语句输出0
- 睡眠(1),然后SELECT传递1
我们总是假设a) LOCK/UNLOCK将刷新表或b)手动Flush Tables xyz WITH READ LOCK也将刷新缓存,强制写入磁盘,并且通常会确保每个其他进程的每个后续查询都将产生预期的结果。
我们已经尝试过了:
- FLUSH TABLES如上所述-没有结果
- 在执行SELECT语句之前显式地获取LOCK - no result
- 只是等待一些时间-产生了我们正在寻找的结果,但这是一个肮脏,不可靠的解决方案。
你们觉得怎么样?原因是什么?我在想:查询缓存没有及时更新,底层操作系统的分页没有及时将内容写回磁盘/没有验证表数据的内存页。
你知道有什么方法可以绝对保证数据的连续一致性吗?
在不同的MariadB版本中默认有不同的事务隔离模式。
如果您期望得到相同的结果,则您已经设置了相同的模式。在不同的MySQL版本上测试它似乎也很奇怪。
https://mariadb.com/kb/en/mariadb-transactions-and-isolation-levels-for-sql-server-users/
你的第二个进程开始事务可能远远早于提交实际发出。如果你不想挖掘事务隔离,可以尝试在select之前执行rollback(但正确的解决方案是确定你的应用需要的隔离)。
Rollback; -- may give error, but it is okay.
SELECT value from xyz;