恢复程序的最后状态

时间:2016-06-04 17:22:05

标签: database python-2.7 sqlite

我想开发一个程序,它可以恢复使用sqlite3数据库的程序中的最后一个循环。

我有一个Raspberry Pi运行,其中源是Python,系统可能会出现电源故障并重启一段时间。

程序可以从启动启动,但可能很难回到程序的最后一个循环。让我们将print函数视为Python语法,每个语法延迟5秒,这意味着有4个不同的程序同步运行。

以下程序没有按预期工作,有人可以帮我解决这个难题吗?

import thread
import time

import sqlite3


conn = sqlite3.connect('testdatabase.db')
conn.isolation_level = None
c = conn.cursor()
c.execute("SELECT ID from LAST_STATE")
fetch=c.fetchone()

def morning_u():
    conn = sqlite3.connect('testdatabase.db')
    c = conn.cursor()
    c.execute("UPDATE LAST_STATE SET ID=1")
    conn.commit()
    c.close()
    conn.close()

def noon_u():
    conn = sqlite3.connect('testdatabase.db')
    c = conn.cursor()
    c.execute("UPDATE LAST_STATE SET ID=2")
    conn.commit()
    c.close()
    conn.close()

def afternoon_u():
    conn = sqlite3.connect('testdatabase.db')
    c = conn.cursor()
    c.execute("UPDATE LAST_STATE SET ID=3")
    conn.commit()
    c.close()
    conn.close()

def evening_u():
    conn = sqlite3.connect('testdatabase.db')
    c = conn.cursor()
    c.execute("UPDATE LAST_STATE SET ID=4")
    conn.commit()
    c.close()
    conn.close()

def morning():
        print ("morning")
        time.sleep(5)
        return

def noon():
        print ("noon")
        time.sleep(5)
        return

def afternoon():
        print ("afternoon")
        time.sleep(5)


def evening():
        print ("evening")
        time.sleep(5)
        morning_u()

while True:
    if fetch[0] is 1:
        morning()
        noon_u()
    if fetch[0] is 2:
        noon()
        afternoon_u()
    if fetch[0] is 3:
        afternoon()
        evening_u()
    if fetch[0] is 4:
        evening()
        morning_u()

数据库信息

conn = sqlite3.connect('testdatabase.db')

conn.execute('''CREATE TABLE LAST_STATE
       (ID INT PRIMARY KEY     NOT NULL);''')

conn.execute("INSERT INTO LAST_STATE (ID) \
      VALUES (1)");

根据评论编辑程序,请提出改进​​建议

import datetime
import time
import logging
import sqlite3


conn = sqlite3.connect('testdatabase.db')
conn.isolation_level = "IMMEDIATE"
c = conn.cursor()
c.execute("SELECT ID from LAST_STATE")
state=c.fetchone()

 def morning_u():
    c.execute("UPDATE LAST_STATE SET ID=1")
    conn.commit()

def noon_u():
    c.execute("UPDATE LAST_STATE SET ID=2")
    conn.commit()

def afternoon_u():
    c.execute("UPDATE LAST_STATE SET ID=3")
    conn.commit()

def evening_u():
    c.execute("UPDATE LAST_STATE SET ID=4")
    conn.commit()

def morning():
        print ("morning")
        time.sleep(5)

def noon():
        print ("noon")
        time.sleep(5)

def afternoon():
        print ("afternoon")
        time.sleep(5)

def evening():
        print ("evening")
        time.sleep(5)

while True:
    if state[0] is 1:
        morning()
        try:
            noon_u()
        except:
            print ("error1")

    if state[0] is 2:
        noon()
        try:
            afternoon_u()
        except:
            print ("error2")

    if state[0] is 3:
        afternoon()
        try:
            evening_u()
        except:
            print ("error3")

    if state[0] is 4:
        evening()
        try:
            morning_u()
        except:
            print ("error4")

1 个答案:

答案 0 :(得分:0)

我看到两个可能导致你的错误的直接问题。

首先,evening调用morning_u,但没有其他函数执行此操作,并且它对循环来说是多余的。

其次,你永远不会在循环中更新fetch(这是一个不好的名字,考虑更像statetime_of_day)。循环将一遍又一遍地做同样的事情。

此外,您还要在每个函数调用时断开连接并重新连接到数据库。这是低效的,它可能会导致并发问题。可以更好地编写函数来接受现有的数据库连接。

最后,您有conn.isolation_level = None自动提交,但您正在调用commit。提交是一个无操作,但它可以欺骗读者认为你正在使用事务。通常,避免自动提交,并使用事务。事务对于并发非常重要。 SQLite defaults to odd implicit transactions这可能不会做你想要的,很难解开。我建议使用显式交易。对于最可预测的行为,可能immediate,但不是排他性的。设置conn.isolation_level = "IMMEDIATE"

设计明智,你说你想要一个崩溃恢复系统,但你正试图将它用作并发系统。这些是两个,主要是独家的东西。

崩溃恢复假设任何时候只有一个进程拥有该状态。它加载,它得到旧的状态,然后它快乐地假装它拥有状态并根据需要改变它。 没有其他人正在改变状态。它甚至可以通过桌面上的独占锁来保证这一点。

并发性假设许多进程都在更新状态。由于您正在构建状态机,因此对状态的每次更改都取决于现有状态。对状态的所有更改都必须是原子的:启动事务(即获取锁定),读取状态,更新状态和提交。状态的所有使用也必须是原子的:启动事务(即获取读锁以防止状态改变),读取状态,使用状态,结束事务。

对于崩溃恢复,您只需在程序开始时读取一次状态。您只需在更改时编写它。

对于并发性,您必须在程序开始时以及任何想要使用它的状态下读取状态。当您使用它时,您必须获得共享锁,以确保它在此期间不会发生变化。

您拥有崩溃恢复所需的代码,您所缺少的只是确保状态更改函数更新状态(即fetch[0])。你没有并发代码,但你不需要它。