2011-11-16 19 views
6

Según la documentación de Postgres: una vez preparada, una transacción puede comprometerse o retrotraerse posteriormente con COMMIT PREPARED o ROLLBACK PREPARED, respectivamente. Estos comandos se pueden emitir desde cualquier sesión, not only the one that executed the original transaction.Cómo hacer que funcione PREPARE TRANSACTION

estoy tratando de importar datos desde CSV en tablas de bases de datos y para ello, estoy usando el

COPY tablename [ (column [, ...]) ] FROM { 'filename' }

Todo esto se hace en un script de shell . Ahora el problema es que estoy cumpliendo psql comando y pasando este comando como parámetro mediante la opción -c (comienzo a la transacción a través del comando

prepare transaction 'some-id' en ese orden).

Quiero crear un Savepoint y deshacerlo en caso de cualquier error.

Después de algunas otras tareas en el shell script, puedo comprobar si hay errores que la declaración psql anteriores han producido y cuando luego tratar de deshacer con el comando

Prepared Rollback 'transaction-id' (en separada psql command with sql statements)

Se informes "No "transaction-id" found"

¿Me estoy equivocando o me falta algo en el proceso?

¿Esto está sucediendo porque estoy emitiendo el comando psql varias veces y cada una da como resultado una nueva transacción?

Respuesta

8

Para su preparación para trabajar, el COPY y el PREPARE deben estar en la misma sesión. Desde su pregunta carece de comandos concretos, estoy asumiendo que cuando se escribe:

Preparado Rollback 'transaction ID (en el comando psql independiente con sentencias SQL)

Estás usando psql diferente comandos para COPIAR y PREPARAR. Esto está mal. Combine COPY y PREPARE en la misma sesión.

E.g.

$ psql -c "BEGIN; COPY tablename FROM '/tmp/sql'; PREPARE TRANSACTION 'foobar';" db 
$ while /bin/not-ready-to-commit ; do sleep 1 ; done 
$ psql -c "COMMIT PREPARED 'foobar';" db 

Los PREPARE TRANSACTION obras de escribir la transacción actual en el disco y salir del proceso de transacción en la sesión actual. Es por eso que necesita un BEGIN: inicia la transacción que desea preparar. Todos los comandos que desee que se vean afectados por el prepeare deben venir después de que se haya iniciado la transacción (en su caso, el comando COPY). Cuando se emite PREPARE TRANSACTION, la transacción en la que se encuentra actualmente se escribe en el disco con el identificador que usted proporciona. Cualquier declaración emitida después de la transacción ya no forma parte de la transacción. Entonces, al hacer BEGIN; PREPARE... ; COPY se ejecuta la operación COPY sin una transacción.

He aquí un ejemplo con cáscara psql:

demo=# DELETE FROM foo; 
DELETE 4 
demo=# BEGIN; -- start a transaction 
BEGIN 
DEMO=# COPY foo FROM '/tmp/sql'; -- do what you want to commit later 
COPY 4 
demo=# PREPARE TRANSACTION 'demo'; -- prepare the transaction 
PREPARE TRANSACTION 
demo=# ROLLBACK; -- this is just to show that there is no longer a transaction 
NOTICE: there is no transaction in progress 
ROLLBACK 
demo=# SELECT * FROM foo; -- the table is empty, copy waiting for commit 
a | b 
---+--- 
(0 rows) 
demo=# COMMIT PREPARED 'demo'; -- do the commit 
COMMIT PREPARED 
demo=# SELECT * FROM foo; -- data is visible 
a | b 
---+--- 
1 | 2 
3 | 4 
5 | 6 
7 | 8 
(4 rows) 

Editar: Debe habilitar las transacciones preparadas en PostgreSQL.conf:

max_prepared_transactions = 1 # or more, zero (default) disables this feature. 

Si max_prepared_transactions es cero, psql informa que no se encuentra la identificación de la transacción, pero no le advierte acerca de esta característica de ser desactivado. Psql da una advertencia para PREPARE TRANSACTION pero es fácil pasar por alto si tus scripts de shell imprimen cosas después de la declaración de preparación.

3

PREPARE TRANSACTION es para distribuye transacciones a través de múltiple servidores, generalmente utilizados por los monitores de transacción o servidores de aplicaciones similares (por ejemplo EJB).

Simplemente envuelva su copia en un bloque de transacción normal:

START TRANSACTION; 
COPY ....; 
COMMIT; 

Si quieres un punto de almacenamiento en el medio, y luego utilizar SAVEPOINT some_name puede revertir a que punto de salvaguarda.

Cuestiones relacionadas