在flask框架下利用Python的threading或thread多线程库如何操作数据库?
PHP中文网
PHP中文网 2017-04-18 09:16:55
0
2
546

萌新在写网站的发送邮件验证,为了防止用户滥发,所以加了权限。前端简单地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中文网

认证高级PHP讲师

répondre à tous(2)
阿神

Dites-moi une idée qui n'a rien à voir avec ce sujet.
Pour le code de vérification, vous pouvez utiliser redis pour le sauvegarder et définir un temps de survie. Dès que le temps est écoulé, la valeur correspondante disparaîtra dans redis. Accédez simplement à redis pour obtenir la valeur soumise, car redis l'est. La mise en cache de la base de données sera plus rapide que SQL et peut empêcher d'autres personnes de modifier les paramètres et de les soumettre. Personnellement, je ne pense pas qu’il soit approprié d’ajouter des horodatages car je peux modifier directement les paramètres soumis.

小葫芦

J'ai deux suppositions :

    Dans le mécanisme d'implémentation de
  1. flask, certains objets globaux dont current_app sont tous des objets proxy. Le proxy est l'élément supérieur de la pile correspondant à la pile locale. est une variable locale de thread (Threading Local), ce qui signifie que pour chaque requête, la référence à l'objet du même nom est différente.

  2. Je n'ai pas vu le code de validation dans async_reset, donc je suppose que le current_user dans le code de routage derrière devrait être ré-obtenu à partir de la base de données, pas l'objet qui a été initialement mis à jour par vous (la référence est différent). Alors essayez de vous engager ?

En fait, cette solution n'est pas particulièrement bonne. Il est préférable d'écrire l'heure d'envoi lors de l'envoi d'un email, puis de déterminer l'intervalle entre l'heure actuelle et la dernière heure d'envoi dans le routage. Cela évite la surcharge liée à l'écriture de la base de données et à l'allocation des threads.

Après avoir été rappelé par @TKfeng, redis cache + TTL est une solution appropriée. Il a de bonnes performances et convient au fractionnement fin des services à un stade ultérieur. Son idée est correcte.

Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal