有客自远方来52 2024-04-23 16:37 采纳率: 15.3%
浏览 1
已结题

如何实现页面的报错?(语言-python|开发工具-pycharm)

我想实现当同一本书被第二次借阅时会借阅失败并弹出禁止借阅的界面,但现在代码写出来功能不能实现,反而会借阅成功,我该如何修改

def add(self):
    """
    添加图书信息
    :return:
    """
    bookName = self.bookNameInput.text()
    if bookName.strip() == "":
        self.x = show_custom_message_box("系统提示", "请选择借阅图书!")
        return
    ID = self.idInput.text()
    if ID.strip() == "":
        self.x = show_custom_message_box("系统提示", "图书编号不能为空!")
        return
    author = self.authorInput.text()
    if author.strip() == "":
        self.x = show_custom_message_box("系统提示", "图书作者不能为空!")
        return
    age = self.ageInput.text()
    if age.strip() == "":
        self.x = show_custom_message_box("系统提示", "年龄不能为空!")
        return
    sex = ''
    if self.manRadio.isChecked():
        sex = '男'
    else:
        sex = '女'
    price = self.priceInput.text()
    if price.strip() == "":
        self.x = show_custom_message_box("系统提示", "图书价格不能为空!")
        return
    stock = self.stockInput.text()
    if stock.strip() == "":
        self.x = show_custom_message_box("系统提示", "借阅量不能为空!")
        return
    stock = int(stock)
    if stock == 0 or stock > 10:
        self.x = show_custom_message_box("系统提示", "同本书每人仅限十本借阅!")
        return
    TID = self.bookTypeComboBoX.currentData()
    if bookName == -1:
        self.x = show_custom_message_box("系统提示", "请选择图书类别!")
        return
    bookDesc = self.bookDescInput.toPlainText()
    rbook = Book.my_construtor2(ID, bookName, author, age, sex, price, TID, bookDesc, stock)
    if int(stock) > borrowDao.check1(rbook):
        self.x = show_custom_message_box("系统提示", "借阅量超出,请重新借阅!")
        return
    if bookName == borrowDao.check2(rbook):
        self.x = show_custom_message_box("系统提示", "禁止重复借阅!")
        return
    if borrowDao.add(rbook) > 0:
        self.x = show_custom_message_box("系统提示", "借阅成功!")
        self.resetForm()
        self.initTable()
    else:
        self.x = show_custom_message_box("系统提示", "借阅失败!")


def check2(rbook: Rbook):
    con = dbUtil.getCon()
    cursor = con.cursor()
    # 检查重复借阅
    check_sql_book = f"SELECT bookName FROM borrow WHERE bookName='{rbook.bookName}'"
    cursor.execute(check_sql_book)
    con.commit()
    count_book = cursor.fetchone()
    print(count_book)
    if count_book is not None:
        return 0
    dbUtil.closeCon(con)

  • 写回答

5条回答 默认 最新

  • 专家-赤兔[在线] 优质创作者: 编程框架技术领域 2024-04-23 16:37
    关注

    引自免费微信小程序:皆我百晓生

    在您提供的代码片段中,check2 方法用于检查是否已经存在相同书名的借阅记录。但是,这个方法并没有处理并发情况,即可能在查询数据库的同时有其他线程也进行了借阅操作,导致两次借阅都通过了。为了解决这个问题,您可以在数据库层面添加锁,确保同一时刻只有一个请求可以执行相关操作。

    这里我将提供一个基于 MySQL 的示例,使用 GET_LOCKRELEASE_LOCK 函数来控制并发。首先,确保您的数据库支持这些函数(MySQL 5.5+版本支持)。

    更新后的 check2 方法:

    import time
    
    def check2(rbook: Rbook):
        con = dbUtil.getCon()
        
        # 获取锁,等待3秒,如果获取不到则返回False
        lock_name = "my_lock_" + rbook.bookName
        acquire_lock_sql = f"DO $$ DECLARE result INT; BEGIN SELECT GET_LOCK('{lock_name}', 3) INTO result; IF result THEN RETURN 1; ELSE SLEEP(1); END IF; END$$;"
        cursor = con.cursor()
        cursor.execute(acquire_lock_sql)
        con.commit()
    
        try:
            # 如果获取到了锁,进行查询
            check_sql_book = f"SELECT bookName FROM borrow WHERE bookName='{rbook.bookName}'"
            cursor.execute(check_sql_book)
            con.commit()
            count_book = cursor.fetchone()
            
            if count_book is not None:
                return 0
        finally:
            # 无论查询结果如何,释放锁
            release_lock_sql = f"DO $$ BEGIN RELEASE_LOCK('{lock_name}'); END$$;"
            cursor.execute(release_lock_sql)
            con.commit()
    
        dbUtil.closeCon(con)
    
        return 1
    

    然后,在 add 方法中调用 check2 并根据其返回值决定是否允许借阅:

    def add(self):
        ...
        if borrowDao.check2(rbook) == 0:
            self.x = show_custom_message_box("系统提示", "禁止重复借阅!")
            return
        ...
    

    这样,如果有两个请求同时尝试借阅同一本书,一个请求会因为获取不到锁而暂停,直到另一个请求完成并释放锁。这能有效防止同一本书被同时借阅的情况。

    请注意,这个方案依赖于 MySQL 的特性,如果您使用的是其他数据库,可能需要寻找相应的并发控制机制。例如,PostgreSQL 使用 advisory locks 或者 SELECT ... FOR UPDATE 命令,SQLite 可以使用事务进行控制。

    评论 编辑记录

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 5月9日
  • 创建了问题 4月23日