Sql update web2py更新\u或插入以增加计数器
我有一个web2py定义的数据库表,用于计算特定用户发出请求的次数,因此它有整数列“user\u id”和“n\u req”。我不想为每个可能的用户填充一个零。相反,我想检查是否存在一个具有user_id的行,如果存在,则将'n_req'增加1,否则使用'n_req'的初始值1创建它。为了避免竞争条件,我想使用单个update_或insert调用来实现这一点,例如Sql update web2py更新\u或插入以增加计数器,sql-update,counter,sql-insert,web2py,Sql Update,Counter,Sql Insert,Web2py,我有一个web2py定义的数据库表,用于计算特定用户发出请求的次数,因此它有整数列“user\u id”和“n\u req”。我不想为每个可能的用户填充一个零。相反,我想检查是否存在一个具有user_id的行,如果存在,则将'n_req'增加1,否则使用'n_req'的初始值1创建它。为了避免竞争条件,我想使用单个update_或insert调用来实现这一点,例如 db.count_table.update(db.count_table.user_id == uid, user_id = uid
db.count_table.update(db.count_table.user_id == uid, user_id = uid, n_req = n_req + 1)
但是,我假设我不能这样做,因为它在递增时使用了预先存在的
n_req
值。那么如何告诉DALn_req
的初始值呢。例如,n|req=(n|req | 0)+1
?在这种情况下,我认为您不能使用.update\u或\u 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)
请注意,.update
中的n_rec
的值设置为db.count_table.n_rec+1
,这将转换为SQL语句,该语句将使数据库增加现有值,而不是自己显式提供最终值。在两个请求同时更新计数的情况下,这应该避免争用条件
另外,请注意,
user\u id
字段上有一个unique
约束。这将防止竞争条件允许为同一用户创建两个记录。在这种情况下,try/except
将捕获生成的IntegrityError
,并对现有记录进行更新。谢谢@anthony。如果在第一个'db.count_table'调用和'insert'之间,另一个进程添加了行,会发生什么情况。我想这会失败的,所以我们希望能找到一种原子化的方法。很好。上面的代码将避免更新时的竞争条件,但您仍然可以在初始插入时获得竞争条件。为了避免这个问题,您应该在用户id
字段上设置一个唯一的
约束,以防止应用程序为同一用户创建两个记录。然后,您可以将insert
包装在try/except
中,以捕获违反唯一约束的行为。如果出现这样的异常,请再次检查现有记录,并进行更新而不是插入。我更新了答案以处理插入时的竞争条件。谢谢@Anthony。真遗憾,这一切都这么复杂!我有点希望有一个简单的一行解决方案。但我想这就是你的比赛条件。