SQLite3 数据库已被锁定

6

当我需要从actions表中删除记录时,出现了数据库锁定错误。

有两个程序在一个sqlite3数据库上进行读写操作。

其中一个是C程序,将硬件操作的结果写入sqlite3表中,另一个是Python脚本,从sqlite读取记录并处理它们,在完成任务后删除行。

但是Python脚本在删除行时显示数据库已锁定错误。

数据库名称: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 但是我经常遇到数据库锁定错误


脚本可能会锁定数据库。为什么要将DB查询、文件写入和Web发布包装在一个无限循环中,而实际上没有“break”? - Parfait
1
为什么你在 while 循环之外打开数据库?你必须在 while True: 中打开和关闭连接。 - roozgar
3个回答

3

考虑移除无限的while True循环,使用连接光标执行和获取语句:

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()

1
感谢您的回答。但是,使用while True将帮助我在每次监视数据库时查找新记录,并且我必须每秒检查一次数据库以查找任何新记录并将它们处理到我的 Web 服务中...因此,如果我删除它,我必须找到其他循环以在1或0.5秒后检查数据库... - peiman F.
2
然后,考虑使用cur.fetchall()循环。请参见编辑。 - Parfait
一个循环后,获取所有记录的脚本就会停止!?我该如何获取其他记录? - peiman F.
重新运行脚本以获取其他记录。请记住,脚本运行时将获取查询中的所有记录。实际上,您不必每秒运行它。只需定期批量获取记录(例如每小时/每天)。因此,请安排计划程序在您需要的指定时间运行脚本。无限期运行脚本会对CPU资源、内存和数据库引擎造成负担。 - Parfait
好的,我明白了。但是这是一个硬件控制器,所以我需要每秒从/向硬件获取命令,如果我把所有代码(从数据库连接到最后提交)放在一个“while True”循环中,你有什么想法? - peiman F.
尝试将包括光标打开和关闭在迭代线程中,而不是无限的while True循环中,以避免占用CPU。 - Parfait

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

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


0

在使用Flask时,我只需设置app.run(debug=False)就可以了。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接