Pergunta

Eu estou usando Python com adodbapi de pywin32 para escrever um script para criar um banco de dados SQL Server e todas as suas tabelas associadas, exibições e procedimentos. O problema é que DBAPI do Python exige que cursor.execute () ser envolvido em uma transação que só é cometido por cursor.commit (), e você não pode executar uma queda ou criar declaração de banco de dados em uma transação do usuário. Todas as ideias sobre como contornar isso?

EDIT:

Não parece ser nada análogo a um parâmetro autocommit, quer o método connect () de adodbapi ou seu método cursor (). Eu ficaria feliz em usar pymssql vez de adodbapi, exceto que ele trunca CHAR e VARCHAR tipos de dados em 255 caracteres.

Eu tentei isso antes postagem; aqui está o rastreamento.

Traceback (most recent call last):
  File "demo.py", line 39, in <module>
    cur.execute("create database dummydatabase")
  File "C:\Python26\lib\site-packages\adodbapi\adodbapi.py", line 713, in execute
    self._executeHelper(operation,False,parameters)
  File "C:\Python26\lib\site-packages\adodbapi\adodbapi.py", line 664, in _executeHelper
    self._raiseCursorError(DatabaseError,tracebackhistory)
  File "C:\Python26\lib\site-packages\adodbapi\adodbapi.py", line 474, in _raiseCursorError
    eh(self.conn,self,errorclass,errorvalue)
  File "C:\Python26\lib\site-packages\adodbapi\adodbapi.py", line 60, in standardErrorHandler
    raise errorclass(errorvalue)
adodbapi.adodbapi.DatabaseError: 
--ADODBAPI
Traceback (most recent call last):
   File "C:\Python26\lib\site-packages\adodbapi\adodbapi.py", line 650, in _executeHelper
    adoRetVal=self.cmd.Execute()
   File "<COMObject ADODB.Command>", line 3, in Execute
   File "C:\Python26\lib\site-packages\win32com\client\dynamic.py", line 258, in _ApplyTypes_
    result = self._oleobj_.InvokeTypes(*(dispid, LCID, wFlags, retType, argTypes) + args)
 com_error: (-2147352567, 'Exception occurred.', (0, u'Microsoft SQL Native Client', u'CREATE DATABASE statement not allowed within multi-statement transaction.', None, 0, -2147217900), None)
-- on command: "create database dummydatabase"
-- with parameters: None
Foi útil?

Solução

O conn connection object adodbapi se iniciar automaticamente uma nova transação após cada commit se as transações banco de dados suporta. DB-API requer autocommit para ser desligado por padrão e permite que um método de API para ligá-lo novamente, mas eu não vejo um em adodbapi.

Você pode ser capaz de usar a propriedade conn.adoConn para cortar em torno disso, usando a API ADO em vez de DB-API para levá-lo fora de qualquer transação. Deixe-me saber se isso funciona:

conn.adoConn.CommitTrans()
cursor.execute('CREATE DATABASE ...')
conn.adoConn.BeginTrans()

Aqui está a fonte para o adodbapi método commit () .

Outras dicas

"O problema é que DBAPI do Python exige que cursor.execute () ser envolvido em uma transação que só é cometido por cursor.commit ()"

"e você não pode executar uma queda ou criar declaração de banco de dados em uma transação do usuário."

Eu não tenho certeza de tudo isto é verdade para todas as interfaces DBAPI.

Uma vez que você não mostrar as mensagens de erro, pode revelar-se que isso não é verdade para a interface adodbapi. Você realmente tentou fazê-lo? Se sim, qual mensagem de erro você está recebendo?

Uma conexão não pode sempre ser a criação de uma "transação do usuário". Muitas vezes você pode abrir conexões com autocommit=True para obter autocommit DDL-estilo.

Além disso, você pode querer considerar o uso de uma conexão diferente para fazer executar DDL.

http://pymssql.sourceforge.net/ por exemplo, mostra DDL a ser executado assim.

import pymssql
conn = pymssql.connect(host='SQL01', user='user', password='password', database='mydatabase')
cur = conn.cursor()
cur.execute('CREATE TABLE persons(id INT, name VARCHAR(100))')

criar a db real fora da transação. Eu não estou familiarizado com python, mas tem que haver uma maneira de executar um usuário dada corda em um banco de dados, o uso que com o real criar db comando. Em seguida, use o adodbapi para fazer todas as tabelas, etc e comprometer essa transação.

Eu tive esse mesmo problema ao tentar executar comandos mais adodbapi (por exemplo DBCC CHECKDB ...) e os conselhos de joeforker ajudou um pouco. O problema que eu ainda tinha era que adodbapi inicia automaticamente uma transação, então não havia nenhuma maneira de executar algo fora de uma transação.

No final, eu acabei desativação do adodbapi cometer comportamento parecido com isto:

self.conn = adodbapi.connect(conn_str)
# rollback the transaction that was started in Connection.__init__()
self.conn.adoConn.RollbackTrans() 
# prevent adodbapi from trying to rollback a transaction in Connection.close()
self.conn.supportsTransactions = False

Tanto quanto eu posso dizer, isso re-permite que o auto-commit funcionalidade, ou seja, cada instrução SQL padrão SQL Server é automaticamente confirmada. A desvantagem é que não há nenhuma maneira para que eu transações ativados novamente (no momento) se eu quero para executar algo dentro de uma transação, desde Connection.commit() não fará nada quando supportsTransactions == False.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top