Seite 2 von 2

Verfasst: Donnerstag 24. November 2005, 19:51
von jens
Also das mit dem COMMIT war wohl quatsch... Das ist nur bei 'Transaction' notwendig...

Aber irgendwie kommt mir das alles komisch vor:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import cgitb;cgitb.enable()

print "Content-type: text/html; charset=utf-8\r\n"

import adodbapi as dbapi


DSN_info = (
    "DRIVER=SQL Server;"
    "SERVER=.\SQLEXPRESS;"
    "DATABASE=DatabaseName;"
    "UID=UserName;"
    "PASSWORD=Password;"
)


class test:
    def __init__( self ):
        print "<pre>"
        self.connect()
        self.make_test_table()
        self.select_all()

        self.insert_1()
        self.select_all()

        self.delete_1()
        self.select_all()

        self.delete_test_table()
        self.close()
        print "</pre>"

    def connect(self):
        print "connect:",
        print DSN_info

        try:
            self.connection = dbapi.connect(DSN_info)
            self.cursor = self.connection.cursor()
        except Exception, e:
            print "Error:", e
            sys.exit()
        else:
            print "Connection OK"

    def close(self):
        self.connection.close()
        print "\n\nConnection closed"

    def make_test_table(self):
        SQLcommand  = (
            "CREATE TABLE TestTable ("
            "id INTEGER NOT NULL PRIMARY KEY IDENTITY(1,1), "
            "data1 VARCHAR( 50 ) NOT NULL, "
            "data2 VARCHAR( 50 ) NOT NULL"
            ");"
        )

        self.execute(
            "Creat a temporary test table",
            SQLcommand
        )

    def delete_test_table(self):
        self.execute(
            "Delete temporary test table",
            "DROP TABLE TestTable;"
        )

    def insert_1(self):
        self.execute(
            "RAW INSERT without SQLescaping",
            "INSERT INTO TestTable (data1,data2) VALUES ('Value A 1', 'Value A 2');"
        )

    def select_all(self):
        result = self.fetchall(
            "SELECT all",
            "SELECT * FROM TestTable;"
        )
        print result

    def delete_1(self):
        self.execute(
            "RAW DELETE values",
            "DELETE FROM TestTable WHERE data1='Value A 1';"
        )

    def execute(self, comment, SQLcommand):
        print "\n\n%s:" % comment
        print "SQLcommand:", SQLcommand
        try:
            self.cursor.execute(SQLcommand)
        except Exception, e:
            print "Error:", e
        else:
            print "OK"

    def fetchall(self, comment, SQLcommand):
        print "\n\n%s:" % comment
        print "SQLcommand:", SQLcommand
        try:
            self.cursor.execute(SQLcommand)
            return self.cursor.fetchall()
        except Exception, e:
            print "Error:", e
        else:
            print "OK"



if __name__ == "__main__":
    test()
Ich lasse doch einfach nur ein paar SQL-Befehle ablaufen. Dennoch kommt es zu dem Fehler:
Mehrfache Recordsets sind bei einer Transaktion mit diesem Cursortyp nicht m\xf6glich. \xc4ndern Sie entweder den Cursortyp, f\xfchren Sie Commit f\xfcr die Transaktion aus, oder schlie\xdfen Sie eines der Recordsets.
Aber je nachdem welche Befehle ich ausführe kommt das mal früher oder später. Irgendwie sehe ich da keinen Zusammenhang :?

Etwas komisch ist es auch wenn ich mit CREATE TABLE und DROP TABLE rumspiele... Man kann CREATE TABLE immer wieder ausführen und es kommt zu keinem Fehler?!?!?

Kann es sein, das es da irgendie ein Cache Mechanismus gibt?!?!


EDIT: So, nun hab ich genau die gleiche Aktion mit ODBC gemacht und damit klappt alles einwandfrei!!! Also ist ADOBDAPI mist???

Verfasst: Donnerstag 24. November 2005, 22:22
von gerold
jens hat geschrieben:Also das mit dem COMMIT war wohl quatsch... Das ist nur bei 'Transaction' notwendig...
[...]
Ich lasse doch einfach nur ein paar SQL-Befehle ablaufen. Dennoch kommt es zu dem Fehler:
Mehrfache Recordsets sind bei einer Transaktion mit diesem Cursortyp nicht m\xf6glich. \xc4ndern Sie entweder den Cursortyp, f\xfchren Sie Commit f\xfcr die Transaktion aus, oder schlie\xdfen Sie eines der Recordsets.
Aber je nachdem welche Befehle ich ausführe kommt das mal früher oder später. Irgendwie sehe ich da keinen Zusammenhang :?

Etwas komisch ist es auch wenn ich mit CREATE TABLE und DROP TABLE rumspiele... Man kann CREATE TABLE immer wieder ausführen und es kommt zu keinem Fehler?!?!?
Kann es sein, das es da irgendie ein Cache Mechanismus gibt?!?!
Hi Jens!

So wie ich das sehe, ignorierst du die Transaktionen. Wahrscheinlich wird vor jeder Abfrage automatisch ein "Begin Transaction" ausgeführt. Was kein Problem ist, wenn du nur ein paar Daten abfragst, aber es ist definitiv ein Problem, wenn du etwas in der Datenbank veränderst. Du musst wahrscheinlich nach jeder SQL-Anweisung, die etwas in der Datenbank verändert, ein adodb.commit, db.commit oder cursor.commit oder etwas ähnliches ausführen. Erst dann ist die Transaktion abgeschlossen -- die Änderung akzeptiert.

Wenn du eine Tabelle erstellst und noch im gleichen Prozess, die Tabelle füllst und abfragst, dann könnte es sein, dass du den Inhalt der Tabelle auslesen kannst. Wartest du aber eine Sekunde und möchtest dann noch einmal den Inhalt der Tabelle abfragen, dann ist nichts mehr da, was du abfragen könntest. Die Änderung wurde ja nicht mit "Commit Transaction" oder einem anderen, an die Connection gebundenen Befehl, abgeschlossen.

SQLite z.B. hält sich auch daran, dass es Änderungen nur nach einem "Commit Transation" akzeptiert. Und AutoCommit sollte man sowiso nicht einschalten, da das Datenbanksystem dadurch hergebremst wird.

Dass man "Create Table" immer wieder ausführen kann, sehe ich als Indiz für meine Theorie an. Natürlich kann man immer wieder die gleiche Tabelle erstellen, wenn der Erstellvorgang niemals korrekt abgeschlossen wurde.

lg
Gerold
:-)

Verfasst: Freitag 25. November 2005, 07:32
von jens
Dann ist bei MySQLdb und ODBC immer AutoCommit eingeschaltet???

Verfasst: Freitag 25. November 2005, 10:18
von gerold
jens hat geschrieben:Dann ist bei MySQLdb und ODBC immer AutoCommit eingeschaltet???
Hi Jens!

Bei MySQL weiß ich gar nicht, ob es so etwas wie ein Transaktionsmanagement überhaupt gibt.

ODBC hält sich aus so etwas raus. Es leitet einfach nur die SQL-Anweisungen weiter.

Als Standard-Einstellung von MS-SQL steht "AutoCommit" auf "Ein". Wenn man trotzdem mit ADODBAPI ein Commit nachschicken muss, dann mischt sich ADODBAPI ein.

Tut es auch. Ich habe soeben im Quelltext von ADODBAPI nachgesehen.

Code: Alles auswählen

if self.supportsTransactions:
    self.adoConn.IsolationLevel=defaultIsolationLevel
    self.adoConn.BeginTrans() #Disables autocommit
lg
Gerold
:-)

Verfasst: Freitag 25. November 2005, 10:41
von jens
Danke für deine Hilfe!!!

Also ich hab es jetzt nochmal mit adodbapi probiert. Wenn ich immer ein connection.commit() mache, kommt es wieder zu einem Fehler:
Die Transaktion kann im Firehosemodus nicht gestartet werden

Verfasst: Freitag 25. November 2005, 12:00
von gerold
jens hat geschrieben: Wenn ich immer ein connection.commit() mache, kommt es wieder zu einem Fehler:
Die Transaktion kann im Firehosemodus nicht gestartet werden
Hi Jens!

Den **Firehosemodus** kenne ich noch nicht, das muss in der 2005'er Version neu eingeführt worden sein. Die Fehlermeldung ist auf deutsch. Da es im ADODBAPI keine deutschen Fehlermeldungen gibt, muss diese direkt vom SQL-Server kommen. Da im ADODBAPI auch kein besonderer Modus ausgewählt wird, dürfte das jetzt der Standardmodus für ADODB-Abfragen sein.
Wie auch immer -- mehr habe ich dazu nicht beizutragen. Ich möchte mich ja von MS-Datenbanken zurück ziehen, weil ich keinen Mehrwert mehr in der Verwendung dieser Technologie sehe.

lg
Gerold
:-)

Verfasst: Freitag 25. November 2005, 14:31
von jens
Na, also ich möchte auch kein MSSQL Experte werden... Nur, weil es ja eine Anbindung gibt die ja fast die selbe ist (Python DB-API) wäre es doch schade, wenn ich nicht auch MSSQL unterstützen würde ;) Zumal ich es im konkreten Fall auch brauche ;)

Ich möchte gern generell an der "portierbarkeit" zur SQL-DB arbeiten um MySQL, SQLite (interessant für eine Standalone-Probier-Variante) und MSSQL unterstützen zu können.

Naja, ich denke da werde doch für MSSQL doch auf ODBC setzten, weil das andere einfach zuviele Probleme macht. Schade eigentlich...

Verfasst: Freitag 25. November 2005, 20:41
von mitsuhiko
Unterstützt nicht auch SQLObject MSSQL?

Verfasst: Samstag 26. November 2005, 21:24
von jens
Hm! Das tut es wohl:
Currently SQLObject supports MySQL via MySQLdb aka MySQL-python, PostgreSQL via psycopg, SQLite via PySQLite, Firebird via kinterbasdb, Sybase via Sybase, and MAX DB (also known as SAP DB) via sapdb, MSSQL Server via pymssql (+ FreeTDS) or ADODBAPI (Win32).
Allerdings müßte ich dann schon komplett auf SQLObject übersatteln... Aber das dürfte wesendlich mehr Arbeit sein... Auf langer sicht gesehen, ist SQLObject schon interessant, aber das muß ich mir halt nochmal näher anschauen.

Ich denke ich mach erstmal mit win32/ODBC weiter...