2017-07-07 1 views
0

Est-il possible de savoir si une ligne d'une table a été créée par la transaction en cours (et n'est donc pas encore visible pour les autres transactions, car le la transaction est toujours active)?PostgreSQL: savoir si une ligne a été créée par la transaction en cours

Mon cas d'utilisation: J'ajoute la journalisation des événements à la base de données. Ceci est fait dans les déclencheurs de plpgsql. Une ligne dans la table des événements ressemble à ceci: (event id:serial, event action:text, count:integer:default 1). Maintenant, le raisonnement derrière ma question: Si une certaine ligne a été créée par cette transaction (probablement dans un autre déclencheur), je pourrais incrémenter le compte au lieu de créer une nouvelle ligne dans la table d'événements.

+0

Quel est votre cas d'utilisation réel? Votre question crie "état de la course" et "problème d'intégrité". – spectras

+0

Si votre code crée les lignes, pourquoi ne le faites-vous pas suivre les lignes qu'il crée? De cette façon, vous n'avez même plus à interroger la base de données, votre code peut envoyer une mise à jour immédiatement. – spectras

+0

Ceci est fait dans ** plusieurs ** déclencheurs plpgsql.Donc, je pourrais soit garder une trace des lignes que les événements ont été créés (table temporaire? Colonne timestamp?) Ou mieux encore, trouver d'une manière ou d'une autre. D'où ma question. –

Répondre

1

Vous pouvez simplement rechercher des entrées de journalisation comme ceci:

SELECT ... 
FROM tablename 
WHERE xmin = current_txid() % (2^32)::bigint; 

qui trouveront toutes les lignes ajoutées ou modifiées dans la transaction en cours. L'inconvénient est que cela va forcer une analyse séquentielle de la table entière, et vous ne pouvez pas éviter cela car vous ne pouvez pas avoir un index sur une colonne système.

Vous pouvez donc ajouter une colonne supplémentaire xid à votre tableau remplie de txid_current()::bigint chaque fois qu'une ligne est insérée ou mise à jour. Une telle colonne peut être indexée et efficacement utilisée dans une recherche:

SELECT ... 
FROM tablename 
WHERE xid = current_txid(); 
+0

Merci. Je vais penser à ajouter la colonne 'xid'. –

+0

Je crois que la vérification suivante est également valide pour éviter les faux positifs? 'xmin :: text = (txid_current()% (2^32) :: bigint) :: text;' (sans avoir besoin de votre colonne 'xid') Je l'ai trouvé sur https://dba.stackexchange.com/ questions/146315/comment-comparer-xmin-et-txid-current-after-transactions-id-wraparound –

+1

Oh, j'ai fait une erreur là-bas. 'current_txid()' ne * renvoie * pas les mêmes valeurs que celles de 'xmin'. J'ai corrigé (et simplifié) la réponse. –

1

Vous pourriez envisager quelque chose comme ceci:

create table ConnectionCurrentAction (
    connectionID int primary key, 
    currentActionID uuid 
) 

puis au début de la transaction:

delete ConnectionCurrentAction where connectionID = pg_backend_pid() 
insert ConnectionCurrentAction(connectionID, currentActionID) 
select pg_backend_pid(), uuid_generate_v4() 

Vous pouvez envelopper cela dans un proc appelé dire audit_action_begin

Remarque : Vous pouvez choisir à la place d'appliquer l'exigence qu'une "action" soit créée explicitement en supprimant la suppression ici.

A la fin d'une transaction, faire audit_action_end:

delete ConnectionCurrentAction where connectionID = pg_backend_pid() 

Chaque fois que vous voulez savoir la transaction en cours:

(select currentActionID from ConnectionCurrentAction where connectionID - pg_backend_pid()(

Vous pouvez envelopper que dans une fonction audit_action_current()

Vous Vous pouvez ensuite insérer currentActionID dans votre journal, ce qui vous permettra d'identifier si une ligne a été créée dans l'action en cours ou non. Cela vous permettra également d'identifier où les lignes des différentes tables d'audit ont été créées dans l'action logique en cours.

Si vous ne voulez pas utiliser un uuid, une séquence ferait aussi bien ici. J'aime les uuids.

+1

Bonnes idées! C'est très utile. Une question cependant: pourquoi utilisez-vous 'pg_backend_pid()' et pas 'txid_current()'? Je me demandais simplement s'il y avait une bonne raison à cela ... Merci encore. –

+0

Excellente question. Parce que je ne connaissais pas 'txid_current()'. Maintenant, je le fais :-) Avec cela, vous n'avez pas vraiment besoin de cette réponse, juste bung que dans votre table d'audit. – Ben

+0

À moins bien sûr que vous ayez des actions "d'application" logiques qui sont distinctes des transactions postgresql – Ben