Flask对接SQLite加提交确认弹窗后表单提交报database is locked错误
问题定位与修复方案
触发锁库的两个核心原因
- 前端提交逻辑缺陷:当前绑定在提交按钮上的
myFunction仅会弹出确认框,既没有拦截表单的默认提交行为,也没有根据用户的弹窗选择判断是否允许提交。用户停留在弹窗选择“确定/取消”的间隙,表单请求可能被多次触发;如果此时DB Browser仍连着同一个数据库文件,文件锁会被长期占用,最终触发sqlite3.OperationalError: database is locked报错。 - 后端代码缩进错误:你给出的
addrec路由代码中,数据库连接、插入操作的逻辑没有被包裹在if request.method == 'POST'的判断块内。Python依靠缩进识别代码块边界,这意味着无论请求是GET还是POST,只要访问该路由就会触发数据库写操作,很容易和其他请求争抢SQLite的单写权限锁。
分步修复操作
1. 修正前端确认按钮逻辑
调整脚本逻辑,保证只有用户在弹窗点“确定”时才触发表单提交,点“取消”时直接拦截提交,避免无效请求触发锁竞争:
<div class="arrange3"> <button type="submit" class="submit-button" name="save" value="save" onclick="return myFunction()">Submit</button> <script> function myFunction() { // 用户点确定返回true,允许提交;点取消返回false,拦截提交 return confirm("Press a button!"); } </script> </div>
注意:原按钮属性里
name="save", value="save"中间的逗号是HTML语法错误,需要删掉换成空格。
2. 修正后端路由的代码逻辑
把所有数据库操作移动到POST请求的判断块内部,避免非POST请求也触发数据库写操作;同时补全原insert语句缺失的右括号,修正语法错误:
@app.route('/addrec', methods=['POST', 'GET']) def addrec(): if request.method == 'POST': # 提取表单参数 depart = request.form['depart'] type = request.form['type'] uploadre = request.form['uploadre'] amt = request.form['amt'] description = request.form['description'] # 数据库操作全部放入POST判断块内 conn = sql.connect(db_path) c = conn.cursor() c.execute( "INSERT INTO SubmitClaim VALUES (?,?,?,?,?)", (depart, type, uploadre, amt, description) ) conn.commit() c.execute("SELECT * FROM SubmitClaim") print(c.fetchall()) conn.close() return render_template('base.html', user=session["user"], version=msal.__version__) # 非POST请求可根据业务需求补充跳转逻辑,不要走到数据库操作分支
锁库问题通用兜底
- 调试阶段使用DB Browser查看数据时,查看完毕及时关闭数据库连接,不要让工具长期持有文件锁占用写入权限。
- 所有数据库操作完成后及时调用
conn.close()释放连接,避免连接泄漏导致锁长时间无法释放。
内容的提问来源于stack exchange,提问作者Elton Tan
相关产品推荐
相关产品推荐

