web2py update_or_insert 增加一个计数器

web2py update_or_insert to increment a counter

我有一个 web2py 定义的数据库 table 用于计算特定用户发出请求的次数 - 所以它有整数列 'user_id' 和 'n_req'.我不想为每个可能的用户用零填充它。相反,我想检查是否存在带有 user_id 的行,如果存在,则将 'n_req' 递增 1,否则使用 'n_req' 的初始值 1 创建它。避免竞争条件,我想使用单个 update_or_insert 调用来执行此操作,例如

db.count_table.update(db.count_table.user_id == uid, user_id = uid, n_req = n_req + 1)

我想我不能这样做,但是,因为它在递增时使用了 n_req 的预先存在的值。那么我如何告诉 DAL n_req 的初始值。例如,我可以做 n_req = (n_req || 0) + 1?

我认为在这种情况下您不能使用 .update_or_insert 方法,因为 n_rec 的值取决于是否找到记录。相反,您可以这样做:

db.define_table('count_table',
    Field('user_id', 'integer', unique=True),
    Field('n_rec', 'integer', default=1))

def update_count(user_id):
    return db(db.count_table.user_id == user_id).update(n_rec=db.count_table.n_rec + 1)

if not update_count(uid):
    try:
        db.count_table.insert(user_id=uid)
    except db._adapter.driver.IntegrityError:
        update_count(uid)

请注意,.updaten_rec 的值设置为 db.count_table.n_rec + 1,这将转换为 SQL 语句,让数据库递增现有值而不是自己明确提供最终价值。这应该避免竞争条件,以防两个请求同时更新计数。

另外,请注意 user_id 字段有一个 unique 约束。这将防止竞争条件允许为同一用户创建两个记录。在这种情况下,try/except 将捕获结果 IntegrityError,并将对现有记录进行更新。