【问题标题】:sqlite3 database is lockedsqlite3 数据库被锁定
【发布时间】:2015-11-22 20:56:01
【问题描述】:

当我必须从actions 表中删除记录时,我遇到了数据库锁定错误。

有两个程序在 sqlite3 数据库上读写

一个是在 sqlite3 表上写入硬件操作结果的 c 程序,另一个是从 sqlite 读取记录并处理它们并在完成作业后删除行的 python 脚本。

但是python脚本在删除行时显示database is locked错误..

数据库名称:db.db

数据库表: TABLE 'actions' ( 'rid' INTEGER PRIMARY KEY AUTOINCREMENT, 'owner' INTEGER, 'action' TEXT, 'node' TEXT, 'value' TEXT

python 脚本:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sqlite3
import time
import os.path
import requests
#import urllib.parse

#defines
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
db_path = os.path.join(BASE_DIR+"/dbs/", "db.db")
wd_file_path = os.path.join(BASE_DIR, "wd")
pid = os.getpid()
conn = sqlite3.connect(db_path, isolation_level=None ,timeout=30000)
print ("Opened database successfully");
while True:
    res = conn.execute("select * from 'actions' where 'owner'='1';")
    #conn.commit()
    data=res.fetchone()
    print(data)
    if (data is None) :
        print('nothing @ '+str(time.time()))
        with open(wd_file_path, 'w') as file_:
            file_.write("{'pid'='"+str(pid)+"','time'='"+str(time.time())+"'}")
        time.sleep(0.5)
    else:
        #print(data)
        r = requests.post("http://127.0.0.1/json.php", data={'act': data[2], 'val': data[4]})
        #if (r.text == '1'):
        conn.execute("delete from 'actions' where 'rid'="+str(data[0])+";")
        conn.commit()
        #else:
        #   print(r.text)

如您所见,我将isolation_level=Nonetimeout=30000 放在我的连接上 但我多次遇到数据库锁定错误

【问题讨论】:

  • 脚本可能正在锁定数据库。为什么要将数据库查询、文件写入和网络发布包装在一个实际上是无限的循环中,因为没有break?
  • 为什么要在while循环之外打开数据库?你神秘地在while True: 上打开和关闭连接

标签: python sqlite


【解决方案1】:

考虑移除无限的while True 循环并使用connection cursor 执行和获取语句:

conn = sqlite3.connect(db_path, isolation_level=None ,timeout=30000) 
print("Opened database successfully")

cur = conn.cursor()
cur.execute("select * from 'actions' where 'owner'='1';") 

for data in cur.fetchall() 
  print(data) 

  if (data is None): 
    print('nothing @ '+str(time.time())) 
    with open(wd_file_path, 'w') as file_: 
      file_.write("{'pid'='"+str(pid)+"','time'='"+str(time.time())+"'}") 
    time.sleep(0.5) 
  else: 
    #print(data) 
    r = requests.post("http://127.0.0.1/json.php", data={'act': data[2], 'val': data[4]}) 
    #if (r.text == '1'): 
    cur.execute("delete from 'actions' where 'rid'="+str(data[0])+";") 
    conn.commit() 
    #else: 
    # print(r.text)

cur.close()
conn.close()

【讨论】:

  • 感谢您的回答。但是while True 将帮助我每次都监控数据库中的新记录,我必须每秒检查数据库以找到任何新记录并将它们处理到我的网络服务。 ..所以如果我删除它,我必须在 1 或 0.5 秒后找到其他循环来检查数据库....
  • 然后,考虑使用 cur.fetchall() 循环。见编辑。
  • 好的。一个循环后获取所有记录脚本会死!?在此之后如何获取其他记录?
  • 重新运行脚本以获取其他记录。请记住,当前查询中的所有记录都将在脚本运行时获取。不会有其他记录。事实上,您不必每秒钟都运行它。只需定期(即每小时/每天)分批抓取记录。因此,让您的调度程序在您需要的指定时间运行脚本。无限期运行脚本会占用 CPU 资源、内存和数据库引擎。
  • 好的。明白了。但这是一个硬件控制器,所以我需要随时从/到硬件获取命令所以如果我把所有代码(从数据库连接到最后一次提交)你的想法是什么在while True 循环中?!
【解决方案2】:

if (data is None) : 分支没有提交,因此 Python 进程无限期地持有数据库的读锁。将 conn.commit() 添加到该分支(或将 else 分支中的那个移出 if/else)。

我也建议不要像这样使用 SQLite 作为队列。如果您使用的是 Linux,请考虑使用更好的工具,例如命名管道。

【讨论】:

    【解决方案3】:

    在使用烧瓶时,我只是设置了 app.run(debug=False) 它对我有用..

    • 请保留一份数据库备份
    • 删除您的日志日志文件
    • 用备份的数据库替换锁定的数据库

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-07
      • 1970-01-01
      • 2018-10-07
      • 1970-01-01
      • 1970-01-01
      • 2019-04-13
      相关资源
      最近更新 更多