【问题标题】:START TRANSACTION with Python 3.6 mysql-connector-python returns no results使用 Python 3.6 mysql-connector-python 开始交易不返回任何结果
【发布时间】:2018-12-14 20:47:24
【问题描述】:

我正在使用 Python 3.6、mysql-connector-python 8.0.11 和 8.0.11 MySQL 社区服务器 - GPL。有问题的表正在使用 innoDB 引擎。

使用 MySQL Workbench 时我可以输入:

使用测试;开始交易; SELECT * FROM tasks WHERE task_status != 1 LIMIT 1 FOR UPDATE;

它按预期提供了 1 条记录:

当我使用 python3 的脚本时(来自同一台机器 - 相同的访问权限等):

  * SQL QRY: START TRANSACTION; SELECT * FROM test WHERE task_status != 1 LIMIT 1 FOR UPDATE;
  * SQL RES: No result set to fetch from.

这是我的脚本的调试输出。如果我将 Query 更改为普通 SELECT,我会得到输出。

  * SQL QRY: SELECT * FROM test WHERE task_status != 1 LIMIT 1;
  * SQL RES: [(1, 0, 'TASK0001')]

我知道 SELECT * 不是要走的路,但现在只是想得到一些回应。

我正在尝试允许多个工作脚本在没有工作人员执行相同任务的情况下执行一项任务:

  1. 执行选择并行锁定任务,以便其他工作人员的“SELECT”查询不会显示它们,
  2. 将任务状态设置为“正在处理”并解锁记录。

这是我第一次尝试锁定,所以这是一个新领域。我能够进行普通查询和填充表等,所以有一些经验,但没有锁定。

表创建:

create table test
(
  id          int auto_increment
   primary key,
  task_status int         not null,
  task_ref    varchar(16) not null
);

问题:

  1. 这是正确的心态吗? IE。有没有更 Pythonic/mysql 的方法来做到这一点?

  2. 我需要以特定方式启动 mysql 连接吗?为什么它可以使用 MySQL 工作台而不是通过脚本工作?我已经尝试使用直接 mysql,这也可以 - 所以我认为它是 python 连接器可能需要正确设置,因为它是唯一不工作的组件。

  3. 目前我在连接器上使用“autocommit=1”,在光标上使用“buffered=True”。我知道您可以在“START TRANSACTION”之前在 SQL 中设置“autocommit=0”,因此了解锁定我可能需要这样做,但对于所有其他事务,我更愿意保持自动提交。这可以和/或可行吗?

代码:

#!/usr/bin/env python

import mysql.connector
import pprint

conn = mysql.connector.connect(user='testuser',
                               password='testpass',
                               host='127.0.0.1',
                               database='test_db',
                               autocommit=True)

dbc = conn.cursor(buffered=True)

qry = "START TRANSACTION; SELECT * FROM 'test' WHERE task_status != 1 LIMIT 1 ON UPDATE;"
sql_select = dbc.execute(qry)
try:
    output = dbc.fetchall()
except mysql.connector.Error as e:
    print("  * SQL QRY: {0}".format(qry))
    print("  * SQL RES: {0}".format(e))
    exit()
else:
    print("  * SQL QRY: {0}".format(qry))
    print("  * SQL RES: {0}".format(output))

非常感谢,

弗兰克

【问题讨论】:

  • 显示 Python 代码

标签: mysql python-3.x transactions mysql-connector-python


【解决方案1】:

所以在玩了一会之后,我发现(通过反复试验)正确的方法是将“FOR UPDATE”放在正常查询的末尾:

完整代码如下(包括添加虚拟记录以进行测试的选项):

#!/usr/bin/env python

import mysql.connector
import pprint
import os

conn = mysql.connector.connect(user='testuser',
                               password='testpass',
                               host='127.0.0.1',
                               database='test_db',
                               autocommit=True)

dbc = conn.cursor(buffered=True)

worker_pid = os.getpid()
all_done = False

create = False

if create:

    items = []
    for i in range(10000):
        items.append([0, 'TASK%04d' % i])

    dbc.executemany('INSERT INTO test (task_status, task_ref) VALUES (%s, %s)', tuple(items))
    conn.commit()
    conn.close
    exit()


while all_done is False:

    print(all_done)
    qry = (
        "SELECT id FROM test WHERE task_status != 1 LIMIT 1 FOR UPDATE;"
        )
    sql_select = dbc.execute(qry)

    try:
        output = dbc.fetchall()
    except mysql.connector.Error as e:
        print("      * SQL QRY: {0}".format(qry))
        print("      * SQL RES: {0}".format(e))
        exit()
    else:
        print("      * SQL QRY: {0}".format(qry))
        print("      * SQL RES: {0}".format(output))

    if len(output) == 0:
        print("All Done = Yes")
        all_done = True
        continue
    else:
        print("Not Done yet!")

    if len(output) > 0:
        test_id = output[0][0]
        print("WORKER {0} FOUND: '{1}'".format(worker_pid, test_id))
        qry = "UPDATE test SET task_status = %s, task_ref = %s WHERE id = %s;"

    sql_select = dbc.execute(qry, tuple([1, worker_pid, test_id]))
    conn.commit()

    try:
        output = dbc.fetchall()
    except mysql.connector.Error as e:
        print("      * SQL QRY: {0}".format(qry))
        print("      * SQL RES: {0}".format(e))

    else:
        print("      * SQL QRY: {0}".format(qry))
        print("      * SQL RES: {0}".format(output))

    print(all_done)

希望这可以帮助其他人节省一些时间,因为有很多地方提供不同的信息,但搜索 python3、mysql-connector 和 transactions 并没有得到任何信息。

祝你好运,

弗兰克

【讨论】:

    猜你喜欢
    • 2013-02-19
    • 1970-01-01
    • 1970-01-01
    • 2023-02-09
    • 2018-09-17
    • 1970-01-01
    • 1970-01-01
    • 2013-07-05
    • 1970-01-01
    相关资源
    最近更新 更多