未处理来自 pyodbc 查询的最后一条记录(到使用 stomp 的消息传递系统)

Posted

技术标签:

【中文标题】未处理来自 pyodbc 查询的最后一条记录(到使用 stomp 的消息传递系统)【英文标题】:Last record from a pyodbc query doesn't process (to messaging system using stomp) 【发布时间】:2022-01-22 12:25:38 【问题描述】:

我正在查询一个返回 38 条记录的数据库。在下面的示例中,所有 38 条都打印,但最后一条记录没有发送到消息系统,只有前 37 条。我在这里缺少什么???

cnxn = pyodbc.connect('DRIVER=ODBC Driver 17 for SQL Server;' + connectionString)
cnxn.autocommit = True
cursor = cnxn.cursor()

sql = (sql statement that returns 38 records)

cursor.execute(sql)
print("Connected")
row = cursor.fetchone()

while row:

    conn = stomp.Connection([('this.that.sys', '61616')])
    conn.connect('user', 'pass', wait=True)
    print("Send " + row.id)  
    conn.send(destination='test1.topic::test1.test1.queue', body=row.payload)

    row = cursor.fetchone()
    conn.disconnect()

这会输出所有 38 个 ID 的列表,但最后一个 Payload 不会发布到队列中。

我做了更多的测试。这很奇怪。这似乎取决于记录。它们在 7KB 到 15KB 之间。如果我尝试某两个,只发布第一个。某某三,全部发表。再确定三个,最后一个又不发表了。

如何调试?

编辑:我做了更多的实验。 Stomp 不保证交货吗?我没有收到任何错误,但有时消息只是没有到达,尤其是最后一条。我稍微重构了我的代码,这似乎有点帮助。我不知道...

cursor.execute(sql)
print("Connected")
row = cursor.fetchone()
print("First " + row.id)
i = 1

try:
    conn = stomp.Connection([('this.that.sys', '61616')])
    conn.connect('user', 'pass', wait=True)
    while row:
        print(str(i))
        print("Send " + row.id + " " + row.status)
        conn.send('test1.topic::test1.test1.queue', row.payload)

        row = cursor.fetchone()
        i = i + 1
    conn.disconnect()
except Exception as e:
    print("Error: %s" % e)

【问题讨论】:

您使用什么库来发送 STOMP 消息? send 方法是否异步执行?如果是这样,那么disconnect 可能会在发送实际发生之前被调用。 嗨贾斯汀。谢谢。该库仅称为 stomp.py。好想法。我在 conn.disconnect() 之前添加了 time.sleep(1),并做了一些实验而没有丢失最后一条消息。棘手。 为什么是 fetchone 而不是 fetchall? STOMP 协议支持receipt header,您可以使用它从代理那里获得您的SEND 帧已成功处理的回复。我不是 100% 确定 stomp.py 支持这一点,但它应该支持,因为它是协议规范的一部分。 另外,它可能值得activating trace logging for STOMP on the broker。然后您可以准确地看到代理从客户端接收到的内容(例如,如果它过早地接收到 DISCONNECT 帧)。 【参考方案1】:

send 方法是否异步执行?如果是这样,那么disconnect 可能会在发送实际发生之前被调用。因此,您可以尝试延迟调用disconnect 方法。

还值得注意的是,STOMP 协议支持receipt header,您可以使用它从代理处获得回复,以确保您的 SEND 帧已成功处理。我不能 100% 确定 stomp.py 支持这一点,但它应该支持,因为它是协议规范的一部分。

此外,在代理上可能值得activating trace logging for STOMP。然后您可以准确地看到代理从客户端接收到的内容(例如,如果它过早地接收到 DISCONNECT 帧)。

最后,您绝对不应该通过连接和断开连接来发送一条消息。这是一个众所周知的反模式,应该尽可能避免。您的第二个代码 sn-p 在这方面更好。

【讨论】:

【参考方案2】:

我会改变它:

cnxn = pyodbc.connect('DRIVER=ODBC Driver 17 for SQL Server;' + connectionString)
cnxn.autocommit = True
cursor = cnxn.cursor()

sql = (sql statement that returns 38 records)

cursor.execute(sql)
print("Connected")
rows = cursor.fetchall()

for row in rows:

    conn = stomp.Connection([('this.that.sys', '61616')])
    conn.connect('user', 'pass', wait=True)
    print("Send " + row.id)  
    conn.send(destination='test1.topic::test1.test1.queue', body=row.payload)
    conn.disconnect()

【讨论】:

连接和断开以发送单个消息是众所周知的反模式,应尽可能避免。 我的回答与有关数据获取的问题有关,而您的评论与他的问题无关 据我所知,问题实际上与数据获取无关。他清楚地说他正在获取所有 38 条记录。问题是只有 37 个被发送到消息代理。因此,失败与通过 STOMP 客户端发送消息有关,这就是我的评论所要解决的问题。为什么您认为问题在于获取数据? 如果你已经阅读了整个问题,你会注意到他只尝试了一次连接和断开连接,问题仍然存在 我了解维护单个连接并不能解决问题。我从没想过会这样。然而,事实仍然是,连接和断开连接以发送单个消息是一种众所周知的反模式,应尽可能避免。

以上是关于未处理来自 pyodbc 查询的最后一条记录(到使用 stomp 的消息传递系统)的主要内容,如果未能解决你的问题,请参考以下文章

在 pyodbc 中执行 SELECT 查询时,来自 ODBC MS Access 驱动程序的“系统资源超出”错误

sql 查询最后一条记录

SQL Server 如何查询最后一条记录

Spring batch - 项目阅读器知道阅读器处理的最后一条记录

查询回访用户、第一条记录和最后一条记录

查询大型 SQL Server 表时,pymssql/pyodbc 性能(cursor.execute)非常慢