在python中获取更新的MySQL表条目而不关闭连接

在python中获取更新的MySQL表条目而不关闭连接,python,mysql,sql,Python,Mysql,Sql,我有两个python程序正在运行。Script1定期向表中写入条目,Script2从同一个MySQL表中读取。两者同时运行。Script2必须获取表的最后一个最新添加的条目 现在的问题是,Script1将条目完美地添加到表中,但Script2无法每次读取最新的条目。仅当我在读取后关闭连接时,它才会读取最新条目,当我想再次读取时,它会重新打开 这是唯一可以采取的办法吗?是否有一种方法可以获得更新的值,而无需每次关闭和打开连接?当访问不断更新的数据库时,程序员遵循的最佳实践是什么 更详细地说: 下面

我有两个python程序正在运行。Script1定期向表中写入条目,Script2从同一个MySQL表中读取。两者同时运行。Script2必须获取表的最后一个最新添加的条目

现在的问题是,Script1将条目完美地添加到表中,但Script2无法每次读取最新的条目。仅当我在读取后关闭连接时,它才会读取最新条目,当我想再次读取时,它会重新打开

这是唯一可以采取的办法吗?是否有一种方法可以获得更新的值,而无需每次关闭和打开连接?当访问不断更新的数据库时,程序员遵循的最佳实践是什么

更详细地说:

下面的代码工作正常,但无法显示更新的值。它第一次成功地显示了最后一个条目,但在接下来的几次调用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,则代码将显示更新的值。

这只是因为事务内部的读取隔离。每次循环后都执行db.commit。

这只是因为事务内部的读取隔离。每次循环后都要执行db.commit。

正如@DanielRoseman所指出的,您正在事务中写入数据,这样做的目的是,如果在进行一组更改之前出现问题,您可以回滚一组更改。因此,在事务永久化和最终化之前,事务期间所做的更改在发生更改的会话之外是不可见的。即使只是在SELECT语句中读取数据,也会开始一个事务,因此每次读取脚本都会查看第一次SELECT时数据库的状态

最明显的解决方案是使用与连接对象关联的显式提交方法。然而,一个更优雅的解决方案利用了MySQLdb连接对象,该对象采用于:

这告诉您连接对象如何与with语句一起工作。因此,如果以这种方式使用连接对象数据库:

with db as x:
    # indented code block here
然后发生以下情况:

x或您选择的名称绑定到db返回的游标对象*。\u__ 如果在缩进块期间引发异常,db将调用自己的回滚方法 否则,db将在离开缩进块时调用自己的提交方法 换句话说,该模块的设计使您可以通过将应为单个事务的每一组语句放入with块来轻松实现事务。因为这里显示的代码只是从表中读取数据,所以无论您决定使用with还是显式调用commit,都需要修改另一个脚本(对数据库进行更改的脚本)

最容易做的事。。。 …对于读取脚本,可以在打开连接后调用db.autocommitTrue来启用自动提交模式。指定如果数据库支持自动提交功能,则在开始时必须禁用该功能,但如果您不担心并发性问题,则没有理由不能启用该功能,这对于您的阅读脚本来说应该是如此

事实上,如果服务器上只运行这两个脚本,而您不需要在另一个脚本中执行事务,那么最简单的方法就是在两个脚本中都启用自动提交,然后忘记它。但是,如果您忘记了在这里所做的事情,转而编写其他需要执行并发事务的脚本,那么这可能会对您造成伤害


*请注意,db为您创建的光标。\uuuuu enter\uuuuuuuuu不会被db关闭。\uuuuu exit\uuuuuuuu。在本例中,MySQLdb.Cursor实际上只是;它不会占用任何额外的服务器资源,并且通常不必担心关闭它。事实上,在with块退出后,只要其父连接保持打开状态,就可以在with语句中以任何绑定的名称继续引用游标对象。当然,除非您明确关闭光标或将其名称绑定到另一个对象。

正如@DanielRoseman所指出的,您正在事务中写入数据,这是为了在进行一组更改之前,如果出现问题,可以回滚一组更改。因此,在事务永久化和最终化之前,事务期间所做的更改在发生更改的会话之外是不可见的。即使只是在SELECT语句中读取数据,也会开始一个事务,因此每次读取脚本都会查看第一次SELECT时数据库的状态

最明显的解决方案是使用显式提交方法asso 与连接对象关联。然而,一个更优雅的解决方案利用了MySQLdb连接对象,该对象采用于:

这告诉您连接对象如何与with语句一起工作。因此,如果以这种方式使用连接对象数据库:

with db as x:
    # indented code block here
然后发生以下情况:

x或您选择的名称绑定到db返回的游标对象*。\u__ 如果在缩进块期间引发异常,db将调用自己的回滚方法 否则,db将在离开缩进块时调用自己的提交方法 换句话说,该模块的设计使您可以通过将应为单个事务的每一组语句放入with块来轻松实现事务。因为这里显示的代码只是从表中读取数据,所以无论您决定使用with还是显式调用commit,都需要修改另一个脚本(对数据库进行更改的脚本)

最容易做的事。。。 …对于读取脚本,可以在打开连接后调用db.autocommitTrue来启用自动提交模式。指定如果数据库支持自动提交功能,则在开始时必须禁用该功能,但如果您不担心并发性问题,则没有理由不能启用该功能,这对于您的阅读脚本来说应该是如此

事实上,如果服务器上只运行这两个脚本,而您不需要在另一个脚本中执行事务,那么最简单的方法就是在两个脚本中都启用自动提交,然后忘记它。但是,如果您忘记了在这里所做的事情,转而编写其他需要执行并发事务的脚本,那么这可能会对您造成伤害


*请注意,db为您创建的光标。\uuuuu enter\uuuuuuuuu不会被db关闭。\uuuuu exit\uuuuuuuu。在本例中,MySQLdb.Cursor实际上只是;它不会占用任何额外的服务器资源,并且通常不必担心关闭它。事实上,在with块退出后,只要其父连接保持打开状态,就可以在with语句中以任何绑定的名称继续引用游标对象。当然,除非您明确关闭光标或将其名称绑定到另一个对象。

如果OP的其他脚本没有定期提交其事务,则在此脚本中提交不一定有帮助。更糟糕的是,如果OP的另一个脚本以OP没有意识到/理解的某种方式提交,给人的印象是db.commit跨会话运行…@AirThomas但问题不是另一个脚本没有提交-我们可以从丢弃和重新打开连接确实显示新数据这一事实中看出。正如我所说,问题在于OP在一个事务中读取数据,InnoDB的默认隔离级别是可重复读取的,因此他只能看到事务开始时出现的数据。如果OP的另一个脚本没有定期提交其事务,则在此脚本中提交不一定有帮助。更糟糕的是,如果OP的另一个脚本以OP没有意识到/理解的某种方式提交,给人的印象是db.commit跨会话运行…@AirThomas但问题不是另一个脚本没有提交-我们可以从丢弃和重新打开连接确实显示新数据这一事实中看出。正如我所说,问题在于OP在一个事务中读取数据,InnoDB的默认隔离级别是可重复读取的,因此他只能看到事务开始时出现的数据。