SQLite3

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
PNS-Richi
User
Beiträge: 68
Registriert: Donnerstag 17. Januar 2008, 01:48

Freitag 27. Februar 2009, 10:30

Hallo,

ich habe nun mein Projekt mit SQLite3 Anbindung geschrieben. Nun ist es von nöten das ein 2. Prozess auch auf die Datenbank zugreifen kann.

Ist dies möglich mit SQLite, oder kann immer nur 1 Prozess die Datenbank öffnen, ohne das diese Schaden nimmt?

Bis jetzt gefällt mir SQLite sehr gut und es ist auch schnell, würde demnach nur ungerne umsteigen, oder gar ein Client/Server entwickeln.

lg Richi
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Freitag 27. Februar 2009, 10:59

Hallo Richi!

Das ist kein Problem. Lesend können mehrere Prozesse (Connections) gleichzeitig auf eine SQLite-Datenbank zugreifen. Dabei kommen sich die Connections nicht in die Quere.

Schreibend: SQLite sperrt den kompletten Schreibzugriff für andere Connections, sobald eine Connection schreibend darauf zugreift. Möchte eine Connection auf die DB schreibend zugreifen, während die DB von einer anderen Connection blockiert wird, wird ein Fehler ausgelöst, den man problemlos abfangen kann. Man muss sich also darum kümmern, dass bei Auftreten dieses Fehlers kurz gewartet wird bevor man es erneut versucht.

Gleichzeitig schreibend auf die DB zuzugreifen, erfordert also etwas mehr Arbeit -- ist aber möglich.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
PNS-Richi
User
Beiträge: 68
Registriert: Donnerstag 17. Januar 2008, 01:48

Freitag 27. Februar 2009, 11:45

Die Frage ist nun wie wirkt sich das auf die Geschwindigkeit aus?

Mein Problem ist das ich derzeit zu wenig Zeit habe um ein Server/Client Konzept aus zu arbeiten, oder etwas ähnliches mit Fork.

Vll. erinnerst du dich noch an mein Redirect Programm für Squid. Das ganze ist nun so weit das man auch Uhrzeiten angeben kann und Downloads auf Viren überprüfen kann. Dafür läuft ein Server der einen Cache für Downloads pflegt und gleichzeitig die User darüber informiert das Ihr Download auf Viren überprüft wird und diese Informationen werden auch in die SQLite Datenbank abgelegt. Somit müssen verschiedene Prozesse auf die Datenbank zugreifen und evtl. auch darauf schreiben können und bei einem Squid Redirection Programm ist es wichtig das dieses schnell reagiert. Deshalb laufen mehrere Dienste, damit alles flüssig weiter läuft. Bei großen Downloads kommt eben eine Informationsseite das die Datei noch gescannt wird. Sollten mehrere Leute die Datei laden, so wird diese vom Cache Server geladen. Da der Tag nur 24 Stunden hat und ich mich vervierfachen müsste um mit irgendwas fertig zu bekommen habe ich nur wenig Zeit was weiter zu bringen und freu mich jedesmal wenn du mir weiter hilfst ;)

Es gibt ja auch SQLite3 bassierende Server/Client Programme, falls du da etwas weißt: nur raus damit.

lg Richi
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Freitag 27. Februar 2009, 13:55

PNS-Richi hat geschrieben:Die Frage ist nun wie wirkt sich das auf die Geschwindigkeit aus?
Negativ :)

Ich habe aber mal spaßeshalber SQLite mit einem Socket verbunden um einen Datenbankserver mit SQLite-Backend zu basteln. Ist recht simpel, ist vielleicht ja eine Lösung die du beschreiten könntest, falls das mit den Schreibzugriffen nicht so hinhaut.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
Damaskus
Administrator
Beiträge: 919
Registriert: Sonntag 6. März 2005, 20:08
Wohnort: Schwabenländle

Freitag 27. Februar 2009, 14:09

Ich verwende als "schnell umsetzbare" Lösung eine Queue mit einem Workerthread und lass über den jeden schreibzugriff auf die DB laufen.

Gruß
Damaskus
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Freitag 27. Februar 2009, 15:50

Hallo Richi!

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

import sqlite3
import time


FILENAME = "addresses.sdb3"


class SqliteConnection(sqlite3.Connection):
    
    WRITE_TRIALS = 100
    LOCKED_WAIT_SECONDS = 0.2
    
    def _with_timeout(self, methode, *args, **kwargs):
        for i in xrange(self.WRITE_TRIALS):
            try:
                return methode(self, *args, **kwargs)
                break
            except sqlite3.OperationalError, err:
                if "locked" in str(err):
                    time.sleep(self.LOCKED_WAIT_SECONDS)
                else:
                    raise
        else:
            raise
    
    
    def execute(self, *args, **kwargs):
        return self._with_timeout(sqlite3.Connection.execute, *args, **kwargs)
    
    
    def executemany(self, *args, **kwargs):
        return self._with_timeout(sqlite3.Connection.executemany, *args, **kwargs)
    
    
    def commit(self, *args, **kwargs):
        return self._with_timeout(sqlite3.Connection.commit, *args, **kwargs)


def create_db_structure(conn):
    sql = """
    CREATE TABLE IF NOT EXISTS addresses (
      id INTEGER PRIMARY KEY,
      first_name TEXT,
      last_name TEXT,
      address TEXT
    )
    """
    conn.execute(sql)
    conn.commit()


def insert_address(conn, first_name, last_name, address):
    sql = """
    INSERT INTO addresses (
      first_name, last_name, address
    ) VALUES (
      ?, ?, ?
    )
    """
    conn.execute(sql, (first_name, last_name, address))
    conn.commit()


def main():
   
    # SQLite-Connection
    conn = SqliteConnection(FILENAME)
    create_db_structure(conn)
   
    # Tabelle mit Werten füllen
    addresses = (
        ("Martin", "Huber", "Wallerweg 1"),
        ("Maria", "Sauter", "Schupfweg 2"),
    )
    for i in xrange(100):
        for first_name, last_name, address in addresses:
            insert_address(conn, first_name, last_name, address)
        time.sleep(0.05)
   
    conn.close()


if __name__ == "__main__":
    main()
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Antworten