在Python中使用MySQLdb时结果长期过时
我的Python程序会查询MySQL数据库中的一组表,查询完后会睡30秒,然后再查询一次,如此反复。这些表是由第三方不断更新的,我当然希望每30秒能看到新的结果。
假设我的查询是这样的:
"select * from A where A.key > %d" % maxValueOfKeyFromLastQuery
但我发现,经过一两次查询后,我的程序就不再找到新的结果,尽管表中确实有新数据。我知道表中有新数据,因为我在使用交互式mysql时可以看到这些新行(也就是说,不是通过Python查询的)。
我发现,如果我在每次查询后断开与数据库的连接,然后为下一个查询重新建立连接,问题就解决了。
我想这可能是服务器端缓存的问题,正如这里讨论的那样:在程序的某些部分显式禁用MySQL查询缓存
但是:
当我检查交互式mysql命令行时,它显示缓存是开启的。(如果这是缓存问题,为什么交互式命令行没有受到影响呢?)
如果我在Python程序中明确执行
SET SESSION query_cache_type = OFF
,问题依然存在。
目前,我只能通过为每个查询创建一个新的数据库连接来解决这个问题。
我该如何让我的Python查询看到那些我知道存在的新结果呢?
4 个回答
你可以在MySQLdb中自动开启自动提交功能!试试下面的代码:
conn = MySQLdb.Connect("host", "user", "password")
conn.autocommit(True)
这样做会让你在使用交互式命令行时,体验到一样的操作方式。
你可能需要检查一下你数据库的事务隔离级别。你描述的行为,如果设置为REPEATABLE-READ,是很正常的。你可以考虑把它改成READ-COMMITTED。
因为提问的人说他只是查询数据库,所以不可能是忘记提交了。虽然插入一个提交看起来是个解决办法,因为这样会开始一个新的事务,并且可能需要建立一个新的快照。但在每次选择之前都要插入一个提交,这听起来并不是一个好的编程习惯。
这里没有Python代码可以展示,因为解决方案在于正确配置数据库。
一定要查看MySQL的文档,地址是 http://dev.mysql.com/doc/refman/5.5/en/set-transaction.html。
REPEATABLE READ
这是InnoDB的默认隔离级别。对于一致性读取,它与READ COMMITTED隔离级别有一个重要区别:同一个事务中的所有一致性读取都读取第一次读取时建立的快照。这意味着如果你在同一个事务中发出多个普通(非锁定)SELECT语句,这些SELECT语句之间也是一致的。请参见第14.3.9.2节,“一致性非锁定读取”。READ COMMITTED
这是一个有点像Oracle的隔离级别,针对一致性(非锁定)读取:每次一致性读取,即使在同一个事务中,都会设置并读取自己的新快照。请参见第14.3.9.2节,“一致性非锁定读取”。
检查配置的隔离级别:
>mysql > SELECT @@GLOBAL.tx_isolation, @@tx_isolation;
+-----------------------+-----------------+
| @@GLOBAL.tx_isolation | @@tx_isolation |
+-----------------------+-----------------+
| REPEATABLE-READ | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.01 sec)
将事务隔离级别设置为READ-COMMITTED
mysql> SET GLOBAL tx_isolation='READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)
mysql> SET SESSION tx_isolation='READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @@GLOBAL.tx_isolation, @@tx_isolation;
+-----------------------+----------------+
| @@GLOBAL.tx_isolation | @@tx_isolation |
+-----------------------+----------------+
| READ-COMMITTED | READ-COMMITTED |
+-----------------------+----------------+
1 row in set (0.01 sec)
mysql>
然后再次运行应用程序……