我正在创建一个telegrambot,用户可以在其中创建他们想要出售的商品的报价。当用户一个接一个地创建它时,它工作得非常好。但当他们同时这么做时,数据就被破坏了。它们在某些字段中得到null或覆盖。
我使用了sqlite,并且我了解到sqlite可能是问题所在,所以我切换到mysql(mysql.connector)并且仍然存在这个问题。
connMembers = mysql.connector.connect(host = "localhost", user = "root", password = "qwerty", database = "testdb")
connItems = mysql.connector.connect(host = "localhost", user = "root", password = "qwerty", database = "testdb")
def create_table_members():
cursor = connMembers.cursor()
sql = "CREATE TABLE IF NOT EXISTS Members" \
"(FirstName TEXT, LastName TEXT, ChatID INTEGER UNIQUE)"
cursor.execute(sql)
connMembers.commit()
cursor.close()
def create_table_items():
cursor = connItems.cursor()
sql = "CREATE TABLE IF NOT EXISTS " \
"Items(FirstName TEXT, LastName TEXT, ChatID INTEGER, " \
"ItemName TEXT, ItemPrice INTEGER, ItemID INTEGER PRIMARY KEY )"
cursor.execute(sql)
connMembers.commit()
cursor.close()
我是这样进入的:
@bot.message_handler(commands=['CreateOffer'])
def handle_createoffer(message):
msg = bot.send_message(message.from_user.id, "Enter Item Name")
bot.register_next_step_handler(msg, get_item_name)
完成此步骤后,将我重定向到此处:
def get_item_name(message):
global CurrentID
CurrentID = CurrentID + 1
ItemName = message.text
items_add(message.from_user.first_name, message.from_user.last_name, message.from_user.id, ItemName, 0, CurrentID)
msg = bot.send_message(message.from_user.id, 'What is your price?')
bot.register_next_step_handler(msg, get_item_price)
然后:
def get_item_price(message):
try:
ItemPrice = message.text
if ItemPrice.isdigit():
edit_item_price(ItemPrice, CurrentID)
else:
msg = bot.send_message(message.from_user.id, "not a digit")
bot.register_next_step_handler(msg, get_item_price)
except Exception as e:
msg = bot.send_message(message.from_user.id, "ERROR" )
bot.register_next_step_handler(msg, get_item_price)
要更新价格,我使用以下命令:
def edit_item_price(ItemPrice, ItemID):
cursor = connItems.cursor()
cursor.execute("UPDATE Items SET ItemPrice = %s WHERE ItemID = %s", (ItemPrice, ItemID))
connItems.commit()
cursor.close()
upd:这是我获取当前ID的方式:
CurrentID = item_id_finder()
def item_id_finder():
cursor = connItems.cursor()
cursor.execute("SELECT MAX(ItemID) FROM Items")
data = cursor.fetchall()
connItems.commit()
cursor.close()
if data[0][0] == None:
return 0
else:
return data[0][0]
例子:
User1 ItemName : ItemNameOne
User2 ItemName : ItemNameTwo
User2 ItemPrice : 40
User1 ItemPrice : 20
Expected output:
User1 - ItemNameOne - 20
User2 - ItemNameTwo - 40
Real OutPut:
User1 - ItemNameOne - 0
User2 - ItemNameTwo - 20
1条答案
按热度按时间izkcnapc1#
你的问题是
global CurrentID
. 这意味着所有用户共享一个值。考虑以下流程:
用户1启动了一个offer,id被提升到23。
当您等待用户1的价格时,用户2启动了一个报价,并且id被提升到24。
当您等待用户1和用户2的价格时,其中一个响应,您将更新第24项的价格。
然后另一个响应,您再次更新第24项的价格。
所以,第24项的最终价格是由最后一个用户设定的,同时,第23项根本不会更新,所以它的价格可能仍然是空的(或者不管你的默认值是什么)。
所以,首先,你需要改变
get_item_price
要将id作为参数,而不是使用全局参数,请执行以下操作:然后需要传入正确的值:
但你怎么知道的
ItemID
以一种不会被其他同时工作的人干扰的方式?实际上我对电报一无所知。如果它是通过协同程序工作的,那么您可以确定在这段时间内没有被打断
CurrentID = CurrentID + 1
第一个潜在的阻塞调用,可能是消息发送,所以你可以这样做:另一方面,如果它是通过线程工作的,而线程可以随时中断,则需要某种同步机制,如锁:
正如op在评论中所建议的,如果您可以更改数据库模式,那么这里有一个更好的解决方案,只需使itemid自动递增。在mysql中,这是:
然后,换你的衣服
INSERT
要离开的声明ItemID
,并获取lastrowid
后产权INSERT
:你还是要通过考试
ItemID
这样它就可以被UPDATE
语句(或者,如果您愿意的话,传递游标本身),但是您不再需要担心以并发安全的方式选择数字,比如锁和初始化函数,这些函数必须在任何线程启动之前运行等等。