防止 MySQL 中的查询缓存

Posted

技术标签:

【中文标题】防止 MySQL 中的查询缓存【英文标题】:Preventing queries caching in MySQL 【发布时间】:2013-06-06 04:46:49 【问题描述】:

我正在通过 JNDI 资源使用 tomcat 连接池。

context.xml

<Resource name="jdbc/mydb" auth="Container" type="javax.sql.DataSource"
          username="myusr" password="mypwd" driverClassName="com.mysql.jdbc.Driver"
          maxActive="1000" maxIdle="100" maxWait="10000"
          url="jdbc:mysql://localhost:3306/mydatabase" 
          factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" />

web.xml:

<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/mydb</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>

数据库是 MySQL 的。

当我选择一些信息时,例如产品列表,在插入或删除产品后也会显示相同的列表。

如何防止这种情况?在这种情况下,我会看到更新后的列表。

编辑

query_cache_size 为 0,query_cache_type 为 ON。

那么,问题可能出在哪里?为什么会发生查询缓存?

编辑

我读到了“RESET QUERY CACHE”和“FLUSH TABLES”。

它们之间有什么区别?

通过使用其中一个,拍卖/电子商务场景中可能会出现问题吗?

【问题讨论】:

从 MySQL 的角度来看,SELECT SQL_NO_CACHE 将执行一个绕过检查查询缓存的 SELECT,而不管查询缓存是打开还是关闭。 @eggyal:是的。我自动授予它。 @eggyal:之前,我只接受了答案。现在,我授予它。 非常感谢 :) 很抱歉打扰了您。 【参考方案1】:

如Consistent Nonlocking Reads 中所述:

如果事务isolation level 是REPEATABLE READ(默认级别),则同一事务中的所有一致性读取都会读取该事务中第一次此类读取所建立的快照。您可以通过提交当前事务并在之后发出新查询来获得查询的更新快照。

[ deletia ]

如果您想查看数据库的“最新”状态,请使用READ COMMITTED 隔离级别或locking read:

SELECT * FROM t LOCK IN SHARE MODE;

可以在Tomcatvia its Resource@defaultTransactionIsolation attribute中设置默认的事务隔离级别。

【讨论】:

【参考方案2】:

连接池与数据缓存没有任何关系(除非您专门以这种方式配置它)。最佳实践是使用连接池进行数据库访问,以防止连接失控(例如,同时连接过多的数据库)并重用已打开一次的连接(通常建立连接非常昂贵,因此它们会再次被利用) .您还希望语句本身(如PreparedStatement)被缓存,因为数据库的下一个昂贵操作是确定执行计划。 (这与实际结果缓存无关)

您是否分析过您的缓存数据是否真的来自 mysql,或者您是否在应用程序级别进行缓存?

另外,请确保您的 insertupdate 事务实际上已提交,否则显然不会有任何更改,并且数据看起来像是被缓存了。

【讨论】:

inserts 和 updates 实际上已提交。在这些事务之一之后,如果我在 mysql 工作台上或通过 webapp 进行查询,mysql db 会发生变化,并且相同的查询会产生不同的结果。 query_cache_size 为 0 且 query_cache_type 为 ON【参考方案3】:

RESET QUERY CACHE 只清除查询缓存。

FLUSH TABLES 关闭所有表(在刷新任何未写入的数据之后)并且清除查询缓存。

清除缓存不会导致您遇到的任何问题。它所做的只是强制后续查询实际从表中获取数据(直到再次缓存这些结果)。

请注意,查询缓存保证永远不会显示过时的数据。对缓存中查询引用的任何表的任何已提交写入都会从缓存中删除此类查询。如果您看到过时的数据,则必须使用另一种外部机制。例如,许多 ORM 会在某个阶段进行一些行缓存,这种机制可能会被破坏,或者如果没有完全按照预期使用,可能会产生意想不到的结果。

无论如何,如果query_cache_size = 0query_cache_type = OFF(或0),则查询缓存被禁用。

【讨论】:

以上是关于防止 MySQL 中的查询缓存的主要内容,如果未能解决你的问题,请参考以下文章

13MySQL-查询缓存Query Cache

在 Symfony 中防止 Doctrine 的查询缓存

MySQL查询过程

MySQL高级查询缓存合并表分区表

MySQL/MariaDB基础第二次

如何防止 Apollo 客户端查询在 IE11 中缓存?