鱼C论坛

 找回密码
 立即注册
查看: 2586|回复: 3

[已解决]sqlalchemy会长时间占用数据库锁吗?

[复制链接]
发表于 2022-6-21 14:54:03 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
如题。我的项目一开始采用的是sqlalchemy,后来在部分地方改为了pymysql。
结果发现,pymysql在执行删除语句的时候,一直在等待一个锁或者类似锁的东西释放,就卡在那了。用mysql直接删也没用,只有把程序停下来才正常。
是sqlalchemy在运行期间会把MySQL的删除功能上锁吗?应该怎么解决?要把sqlalchemy的代码全部换掉吗?
最佳答案
2022-6-22 20:03:34
没用过flask_sqlalchemy   只用过sqlalchemy 没遇到过占用的情况 看了一眼你的代码 似乎是你一种保持着会话并且默认开启了事务?
建议使用会话元类来生成会话 sessionmaker(bind=engine)  每次执行完关闭会话 。

当然 还有一种解法 那就是不开启事务 。你需要开启事务的时候 手动with session.begin()就行了
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2022-6-21 20:41:45 | 显示全部楼层
得看你sqlalchemy代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-6-22 11:03:33 | 显示全部楼层
kogawananari 发表于 2022-6-21 20:41
得看你sqlalchemy代码

sqlalchemy:
  1. """
  2. Routes and views for the flask application.
  3. """

  4. from flask import render_template, request
  5. from HelloWorld_Controller import app
  6. import os
  7. import json
  8. import pydub
  9. import threading
  10. import time
  11. import pydub.exceptions
  12. import copy
  13. import re
  14. from . import mysql_controller as mc
  15. import datetime
  16. import hashlib
  17. import random
  18. import base64
  19. from flask_sqlalchemy import SQLAlchemy
  20. import pymysql
  21. import filetype

  22. app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://RWUser:d774ab2befc390901bc738ed735ce256b7b07dd35175c2aace2bc3517b5264ec@localhost/HelloWorldServerDatabase"

  23. app.config['SQLALCHEMY_COMMIT_TEARDOWN'] = True
  24. app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
  25. app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True

  26. config = {}
  27. necessaryConfigs = ["baseDIR", "DB", "DB.cleanDB", "firstStartup"]
  28. try:
  29.     with open("config.json") as f:
  30.         text = f.read()
  31.         text = text.replace("\n", "")
  32.         config = json.loads(text)
  33.         #print("dee")
  34. except Exception:
  35.    
  36.     config = json.loads(r"""
  37. {
  38.     "baseDIR": "D:\\HelloWorld_Server\",
  39.     "DB": {
  40.         "cleanDB": false,
  41.         "create_new": false
  42.     }
  43. }""")

  44. for each in necessaryConfigs:
  45.     if ("." in each):
  46.         splited = each.split(".")
  47.         now = config
  48.         for i in range(len(splited)):
  49.             try:
  50.                 now = now[splited[i]]
  51.             except KeyError:
  52.                 raise AssertionError("Cannot find necessary config named %s." % each)
  53.     else:
  54.         try:
  55.             config[each]
  56.         except KeyError:
  57.             raise AssertionError("Cannot find necessary config named %s." % each)
  58. db = SQLAlchemy(app)

  59. class Token(db.Model):
  60.     id = db.Column(db.BigInteger, primary_key=True)
  61.     username = db.Column(db.String(300), nullable=False)
  62.     token = db.Column(db.String(100), unique=True, nullable=False)
  63.     vaildTime = db.Column(db.DateTime, unique=True)

  64. class User(db.Model):
  65.     id = db.Column(db.BigInteger, primary_key=True)
  66.     username = db.Column(db.String(300), unique=True, nullable=False)
  67.     password_hash = db.Column(db.String(128), nullable=False)
  68.     salt = db.Column(db.String(10), nullable=False)

  69. class Evidence(db.Model):
  70.     id = db.Column(db.BigInteger, primary_key=True)
  71.     username = db.Column(db.String(300), nullable=False)
  72.     evidence = db.Column(db.String(150), unique=True, nullable=False)
  73.     vaildTime = db.Column(db.DateTime)
  74. #db.create_all()

  75. BASE_PATH = config["baseDIR"]
  76. temps = []
  77. try:
  78.     config["DB"]["create_new"]
  79. except:
  80.     config["DB"]["create_new"] = False

  81. if (config["DB"]["cleanDB"] or config["firstStartup"]):
  82.     db.drop_all()
  83.     db.create_all()
  84.     if (config["firstStartup"]):
  85.         config["firstStartup"] = False
  86.         with open("config.json", "w") as f:
  87.             json.dump(config, f, indent=4)
  88. elif (config["DB"]["create_new"]):
  89.     db.create_all()

  90. def new_token(username : str):
  91.     lst = [e for e in username]
  92.     res = ""
  93.     for i in range(len(lst)):
  94.         index = random.randint(0, len(lst) - 1)
  95.         res += lst[index]
  96.         lst.pop(index)
  97.         lst.reverse()
  98.     res += str(time.time()) + "efj;"
  99.     res += str(random.randint(0, 5023))
  100.     res = res.encode(random.choice(['utf-32', 'utf-16', 'utf-8']))
  101.     return str(int("0x" + hashlib.sha256(res).hexdigest(), 16))

  102. def compute_evidence(username):
  103.     evidence = hashlib.sha512(str(time.time() + random.randint(-100, 100) + random.random() * random.choice([-1, 1])).encode()).hexdigest()
  104.     info = Evidence(evidence=evidence, username=username, vaildTime=datetime.datetime.now() + datetime.timedelta(0, 0, 0, 0, 25.5, 0, 0))
  105.     db.session.add(info)
  106.     return evidence

  107. def eff(db):
  108.     lock = threading.RLock()
  109.     while True:
  110.         lock.acquire()
  111.         db.session.commit()
  112.         lock.release()
  113.         time.sleep(5)

  114. thread2 = threading.Thread(target=lambda:eff(db))
  115. thread2.start()

  116. @app.route("/python/account/loginState", methods=["GET", "POST"])
  117. def LoginStateCheck():
  118.     data = ""
  119.     if (request.method == "POST"):
  120.         data = request.form.get("token")
  121.     elif (request.method == "GET"):
  122.         data = request.args.get("token")
  123.     retsder = Token.query.filter_by(token=data).first()
  124.     if (retsder == None):
  125.         return "invaild"
  126.     #retsder = retsder#.first()
  127.     if (retsder.vaildTime <= datetime.datetime.now()):
  128.             db.session.delete(retsder)
  129.             return "invaild"
  130.     else:
  131.         _token = new_token(retsder.username)
  132.         _username = retsder.username
  133.         info = Token(username=_username, token=_token, vaildTime=retsder.vaildTime)
  134.         db.session.delete(retsder)
  135.         db.session.add(info)
  136.         return json.dumps({"token": _token, "username": _username,
  137.                            "evidence": compute_evidence(_username)})

  138. class DictTool:
  139.     @staticmethod
  140.     def reverse(dic):
  141.         nd = {}
  142.         for k, v in dic.items():
  143.             nd[v] = k
  144.         return nd
  145.     @staticmethod
  146.     def keys(dic):
  147.         return [k for k, v in dic.items()]
  148.     @staticmethod
  149.     def vals(dic):
  150.         return [v for k, v in dic.items()]

  151. @app.route("/python/account/checkEvidence", methods=["GET", "POST"])
  152. def CheckEvi():
  153.     global evi
  154.     data = ""
  155.     if (request.method == "POST"):
  156.         data = request.form.get("evidence")
  157.     elif (request.method == "GET"):
  158.         data = request.args.get("evidence")
  159.     test = Evidence.query.filter_by(evidence=data).first()
  160.     if (test == None):
  161.         return "false"
  162.     else:
  163.         return "true"

  164. @app.route("/python/account/login", methods=["GET", "POST"])
  165. def Login():
  166.     global evi, db
  167.     username = ""
  168.     password = ""
  169.     withToken = False
  170.     if (request.method == "GET"):
  171.         username = request.args.get("username")
  172.         password = request.args.get("password")
  173.         withToken = request.args.get("withtoken")
  174.     else:
  175.         username = request.form.get("username")
  176.         password = request.form.get("password")
  177.         withToken = request.form.get("withtoken")
  178.     username = base64.decodebytes(username.encode()).decode()
  179.     password = base64.decodebytes(password.encode()).decode()
  180.     withToken = True if withToken == "true" else False

  181.     query = User.query.filter_by(username=username).first()
  182.     if (query == None):
  183.         return "nouser"
  184.     elif (str(int("0x" + hashlib.sha256((username + query.salt).encode()).hexdigest(), 16)) != query.password_hash):
  185.         return "wrongpassword"
  186.     evidence = compute_evidence(username)
  187.     if (withToken):
  188.         token = new_token(username)
  189.         info = Token(username=username, token=token, vaildTime=datetime.datetime.now() + datetime.timedelta(5, 0, 0, 0, 0, 0, 0))
  190.         db.session.add(info)
  191.         return json.dumps({"username": username, "token": token, "evidence": evidence})
  192.     return json.dumps({"username": username, "evidence": evidence})

  193. @app.route("/python/account/signup", methods=["POST", "GET"])
  194. def Signup():
  195.     global db
  196.     rf = request.args
  197.     if (request.method == "POST"):
  198.         rf = request.form
  199.     username = base64.decodebytes(rf.get("username").encode()).decode()
  200.     password = base64.decodebytes(rf.get("password").encode()).decode()

  201.     if (User.query.filter_by(username=username).first() != None):
  202.         return "userexisted"
  203.     d = "abcdefghijklmnopqrstuvwxyz"
  204.     d += d.upper()
  205.     d += "1234567890!@#$%^&*()~-=_+{}[]\\|:";\'<>?,./ "
  206.     d = [e for e in d]
  207.     salt = "".join([random.choice(d) for i in range(random.randint(4, 10))])
  208.     hashobj = hashlib.sha256((password + salt).encode())
  209.     hexhash = hashobj.hexdigest()
  210.     integerhash = int("0x" + hexhash, 16)
  211.     decimalhash = str(integerhash)
  212.     info = User(username=username, salt=salt, password_hash=integerhash)
  213.     db.session.add(info)
  214.     return "Completed.Username:%s, Password:%s" % (username, password)


  215. def getPhyhicsPath(uri):
  216.     global BASE_PATH
  217.     return BASE_PATH + uri[1:].replace("/", "\")
复制代码

然后是pymysql的代码:
  1. conn = pymysql.connect(host="127.0.0.1", user="recordCleaner", password="faf76827f1634a501544bb6f668efe4a6882101f9783f33ca790308173be0ec5", database="helloworldserverdatabase")
  2. cur = conn.cursor(pymysql.cursors.DictCursor)
  3. while True:
  4.     cur.execute("delete from evidence where vaildTime <= CURTIME()")
  5.     cur.fetchall()
  6.     cur.execute("select id, evidence from evidence order by id")
  7.     ret = cur.fetchall()
  8.     lastid = 0
  9.     for each in ret:
  10.         if (each["id"] - lastid != 1):
  11.             cur.execute("update evidence set id=%d where id=%d and evidence='%s'" % (lastid + 1, each["id"], each['evidence']))
  12.         lastid = lastid + 1
  13.     cur.execute("delete from token where vaildTime <= CURTIME()")
  14.     cur.fetchall()
  15.     cur.execute("select id, token from token order by id")
  16.     ret = cur.fetchall()
  17.     lastid = 0
  18.     for each in ret:
  19.         if (each["id"] - lastid != 1):
  20.             cur.execute("update token set id=%d where id=%d and token='%s'" % (lastid + 1, each["id"], each['token']))
  21.         lastid = lastid + 1
  22.     time.sleep(2)
复制代码

用的是flask。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-6-22 20:03:34 | 显示全部楼层    本楼为最佳答案   
没用过flask_sqlalchemy   只用过sqlalchemy 没遇到过占用的情况 看了一眼你的代码 似乎是你一种保持着会话并且默认开启了事务?
建议使用会话元类来生成会话 sessionmaker(bind=engine)  每次执行完关闭会话 。

当然 还有一种解法 那就是不开启事务 。你需要开启事务的时候 手动with session.begin()就行了
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-6-22 23:30

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表