Home  >  Q&A  >  body text

在flask框架下利用Python的threading或thread多线程库如何操作数据库?

萌新在写网站的发送邮件验证,为了防止用户滥发,所以加了权限。前端简单地disable按钮一刷新就没了,纯粹视觉提示作用,所以在后端models里为user加了一个resend_right,当为True时才能重新发送,False不行。

所以在models里,user模型有一个column是这样的(SQLAlchemy):

resend_right = db.Column(db.Boolean, default=True)

当然前端是等待60秒后可以重新发送,所以后端也计时60秒后重新赋值True给resend_right。我就想这种等待性IO/数据库读取录入等操作当然是多线程处理。

所以我写了resend_right权限重置的方法:

def async_reset(app, user):
    with app.app_context():
        time.sleep(55)
        user.resend_right = True

def resend_right_reset(user):
    app = current_app._get_current_object()
    thr = Thread(target=async_reset, args=[app, user])
    thr.start()
    return thr
    

然后在views的路由函数里面调用它:

# Resend confirmation email route, need to be protected
@auth.route('/resend_email/')
@login_required
def resend_confirmation():
    mail_host ='http://mail.' + re.split('@', current_user.email)[1]
    if not current_user.resend_right:
        flash("请不要尝试刷新页面来短时间内重复发送验证邮件,你可以在一分钟后再试")
        return render_template('auth/confirm.html',user=current_user, mail_host=mail_host)
    token = current_user.generate_confirmation_token()
.........

结果无效,所以我测试了一下,发现路由函数无问题,resend_right_reset无问题。假如我把user.rend_right=True写进resend_right_reset是能够正常运作的,但一旦用多线程来处理就始终无法重置。然后我分析,多线程这里用了current_app._get_current_object()获取全局对象,然后app.app_context()拿到了上下文导入到多线程里,应该就没问题了。但为什么不行?

求教,非常感谢!

PHP中文网PHP中文网2741 days ago498

reply all(2)I'll reply

  • 阿神

    阿神2017-04-18 09:18:55

    Tell me an idea that has nothing to do with this topic.
    For the verification code, you can use redis to save it and set a survival time. As soon as the time is up, the corresponding value will disappear in redis. Just go to redis to get the submitted value, because redis is a cache database. , the speed will be faster than sql, and then it can prevent others from modifying parameters and submitting them. I personally think the method of adding timestamps is inappropriate, because I can modify the submission parameters directly.

    reply
    0
  • 高洛峰

    高洛峰2017-04-18 09:18:55

    I have two guesses:

      Some global objects, including
    1. flask 的实现机制里,包括 current_app, are all proxy objects. The proxy object is the top element of the stack corresponding to the local stack. This object is a thread local variable (Threading Local), which means that for each Requests that references to objects with the same name are different.

    2. I didn’t see commit code in async_reset, so I guess the current_user in the routing code behind should be obtained from the database again, not the object that was originally updated by you (the reference is different), so try commit?

    In fact, this solution is not particularly good. It is best to write the sending time when sending an email, and then determine the interval from the current time to the last sending time in the routing. This avoids the overhead of database writing and allocating threads.

    After being reminded by @TKfeng, redis cache + TTL is the appropriate solution. It has good performance and is suitable for fine-grained service splitting in the later stage. His idea is right.

    reply
    0
  • Cancelreply