我有2个python程序在运行。Script1定期将条目写入表,Script2从同一个MySQL表读取条目。两人同时奔跑。Script2必须获得表的最后(最新添加的)条目。
现在,问题是Script1正在完美地将条目添加到表中,但是Script2每次都无法读取最新的条目。它只在读取后关闭连接时读取最新的条目,当我想再次阅读时才重新打开它。
,这是唯一可以采取的方法吗?是否有一种方法可以获得更新的值,而不需要每次关闭和打开连接?当访问不断更新的DB时,最佳实践程序员遵循什么?
更详细的是:
下面的代码工作正常,但无法显示更新的值。它第一次成功地显示了最后一个条目,但是接下来几次调用readComm()时,将再次显示相同的条目,尽管表已经被更新。
import MySQLdb
import time
db = MySQLdb.connect("localhost", "root", "abc", "abc")
cursor=db.cursor()
def readComm():
sql = "SELECT * FROM my_table ORDER BY id DESC LIMIT 1;"
try:
cursor.execute(sql)
# Fetch all the rows in a list of lists.
results = cursor.fetchall()
print '~~~~', results
except:
print "Error! Unable to fetch data"
return
for i in range(5):
readComm()
time.sleep(10)如果修改它,代码将显示更新后的值,以便每次输入和退出readComm()时都会打开和关闭DB。
发布于 2014-06-25 18:18:41
这仅仅是因为事务内部的读取隔离。在每个循环之后执行db.commit()。
发布于 2014-06-25 19:00:49
正如@DanielRoseman所指出的,您正在事务中写入数据,这是为了在更改集发生之前出错时,允许您回滚一组更改。因此,在事务期间所做的更改在会话之外是不可见的,直到语句将事务变为永久的和最终的。即使您只是在SELECT语句中读取数据,也可以开始一个事务--因此您的“读取”脚本每次都在查看数据库在第一个SELECT时所处的状态。
最明显的解决方案是使用与commit()对象关联的显式Connection方法。然而,更优雅的解决方案利用了MySQLdb Connection对象的上下文管理器协议的实现,该上下文管理器协议的实现是从佩普343中采用的
def __enter__(self):
if self.get_autocommit():
self.query("BEGIN")
return self.cursor()
def __exit__(self, exc, value, tb):
if exc:
self.rollback()
else:
self.commit()这告诉您Connection对象如何与with语句一起工作。因此,如果您要以这种方式使用连接对象db:
with db as x:
# indented code block here然后发生以下情况:
x (或您选择的名称)绑定到由db.__enter__()返回的Cursor对象*db将调用自己的rollback()方法。db将在离开缩进块时调用自己的commit()方法。换句话说,该模块的设计使得您可以通过将应该是单个事务的每一组语句放入with块来轻松地实现事务。因为这里显示的代码只是从表中读取数据,所以无论您决定使用with还是显式调用commit(),最重要的是要修改的是对数据库进行更改的其他脚本。
最容易做的事。
...for“读”脚本是在打开连接后调用db.autocommit(True)来启用自动提交模式。Python数据库API指定“如果数据库支持自动提交功能,这必须在一开始就关闭”,但是如果您不担心并发性问题,就没有理由不能打开它,这应该是您的“读取”脚本的情况。
事实上,如果这两个脚本是服务器上唯一的事情,并且您不需要在其他脚本中进行事务处理,那么最简单的方法就是在这两个脚本中打开自动提交,然后忘记它。但是,如果您忘记了这里所做的事情,然后编写需要执行并发事务的其他脚本,这可能会让您在以后的日子里陷入麻烦。
*注意,db.__enter__()为您创建的游标不是由db.__exit__()关闭的。在这种情况下,MySQLdb.Cursor实际上只是模拟游标的Python对象;它不会占用任何额外的服务器资源,您通常不必担心关闭它。实际上,在Cursor块退出后,您可以继续使用with语句中绑定它的任何名称来引用with对象,只要其父Connection仍然处于打开状态。(当然,除非显式地close()游标或将其名称绑定到另一个对象。)
https://stackoverflow.com/questions/24415699
复制相似问题