Thread: Transaction vs. Savepoints

Transaction vs. Savepoints

From
Andreas
Date:
Hi,

I'm a bit confused about the handling of transactions and savepoints
withing reallife applications.
It's theoretically all pretty neat and I understand what's the point of
transactions in general.

As far as I know, PG handles 1 transaction per connection an several
savepoints boxed within.
E.G.   T1 ( Sp1, Sp2, Sp3 )
I could commit Sp1, rollback Sp2 and commit Sp3 in a session.
If I commit T1 all those actions get permanently written to to DB
whereas if I rollback T1 all committed savepoints within get rolled
back, too.

Suppose an application that runs all the 8 workhours. It handles
customers and goods/services.

I obviously can't start a global transaction with the application
because in the worst case something bad happens at the end of a workday
and T1 can't be committed so all the work of this day would be lost.

So I have to manage smaller work-packages.
Like T1 (open a customer -- change his adress info -- write it back --
commit T1)

He might have several adresses so I'd show them in a list and provide a
dialoge that opens to edit single adresses.
T1 (open a customer -- Sp1 (change adress 3 -- write it back -- commit
Sp1) -- (Sp2 add a phone note -- commit Sp2) -- commit T1)

What if before T1 gets committed the front-end-application crashes.
T1 gets rolled back and erases the changes of Sp1 and Sp2 even though a
user would expect them to be safe since those 2 dialoges might have been
closed 50 minutes ago before he went to lunch.
He would be a wee bit unhappy to find them lost, too.

Now suppose you open a customer-form F1 and another form F2 that is
semantically independent like some infos about an item in your warehouse
or some color-config-dialog.
Both dialogs would try to start a transaction but the second one can't.
If I somehow keep track of running transactions and safepoint within the
application I could let the second dialog use a safepoint instead of a
real transaction.
What if F2 gets closed OK (committed) but the first dialog F1 that got
the transaction gets rolled back?

Using separate connections everywhere where a bit of the application
accesses the DB isn't desirable either because initiating connections is
way slower than using an allready established one.
I actually wondered if I can get away with a single connection that gets
build up within the start of the application.

How do you go about those problems ?


Re: Transaction vs. Savepoints

From
"Phillip Smith"
Date:
You know you can start and commit multiple transactions in one
connection...?

<open connection to pg daemon; say when user logs on at 9.00am>
BEGIN;
<transaction 1 here>
COMMIT;
BEGIN;
<transaction 2 here>
<save point 1>
<save point 2>
COMMIT;
BEGIN;
<transaction 3 here>
<save point 1>
COMMIT;
<close connection to pg daemon; say when user logs off at 5.00pm>

Just as an example...
-p

-----Original Message-----
From: pgsql-novice-owner@postgresql.org
[mailto:pgsql-novice-owner@postgresql.org] On Behalf Of Andreas
Sent: Friday, 9 February 2007 16:05
To: pgsql-novice@postgresql.org
Subject: [NOVICE] Transaction vs. Savepoints

Hi,

I'm a bit confused about the handling of transactions and savepoints
withing reallife applications.
It's theoretically all pretty neat and I understand what's the point of
transactions in general.

As far as I know, PG handles 1 transaction per connection an several
savepoints boxed within.
E.G.   T1 ( Sp1, Sp2, Sp3 )
I could commit Sp1, rollback Sp2 and commit Sp3 in a session.
If I commit T1 all those actions get permanently written to to DB
whereas if I rollback T1 all committed savepoints within get rolled
back, too.

Suppose an application that runs all the 8 workhours. It handles
customers and goods/services.

I obviously can't start a global transaction with the application
because in the worst case something bad happens at the end of a workday
and T1 can't be committed so all the work of this day would be lost.

So I have to manage smaller work-packages.
Like T1 (open a customer -- change his adress info -- write it back --
commit T1)

He might have several adresses so I'd show them in a list and provide a
dialoge that opens to edit single adresses.
T1 (open a customer -- Sp1 (change adress 3 -- write it back -- commit
Sp1) -- (Sp2 add a phone note -- commit Sp2) -- commit T1)

What if before T1 gets committed the front-end-application crashes.
T1 gets rolled back and erases the changes of Sp1 and Sp2 even though a
user would expect them to be safe since those 2 dialoges might have been
closed 50 minutes ago before he went to lunch.
He would be a wee bit unhappy to find them lost, too.

Now suppose you open a customer-form F1 and another form F2 that is
semantically independent like some infos about an item in your warehouse
or some color-config-dialog.
Both dialogs would try to start a transaction but the second one can't.
If I somehow keep track of running transactions and safepoint within the
application I could let the second dialog use a safepoint instead of a
real transaction.
What if F2 gets closed OK (committed) but the first dialog F1 that got
the transaction gets rolled back?

Using separate connections everywhere where a bit of the application
accesses the DB isn't desirable either because initiating connections is
way slower than using an allready established one.
I actually wondered if I can get away with a single connection that gets
build up within the start of the application.

How do you go about those problems ?


---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
       choose an index scan if your joining column's datatypes do not
       match


*******************Confidentiality and Privilege Notice*******************

The material contained in this message is privileged and confidential to
the addressee.  If you are not the addressee indicated in this message or
responsible for delivery of the message to such person, you may not copy
or deliver this message to anyone, and you should destroy it and kindly
notify the sender by reply email.

Information in this message that does not relate to the official business
of Weatherbeeta must be treated as neither given nor endorsed by Weatherbeeta.
Weatherbeeta, its employees, contractors or associates shall not be liable
for direct, indirect or consequential loss arising from transmission of this
message or any attachments

Re: Transaction vs. Savepoints

From
Richard Broersma Jr
Date:
> As far as I know, PG handles 1 transaction per connection an several
> savepoints boxed within.
> E.G.   T1 ( Sp1, Sp2, Sp3 )
> I could commit Sp1, rollback Sp2 and commit Sp3 in a session.
> If I commit T1 all those actions get permanently written to to DB
> whereas if I rollback T1 all committed savepoints within get rolled
> back, too.

As far as I know, Postgresql defaults to one transaction from ~every~ statement, not per every
connection.  You do have the option to explicitly open a transaction at the beginning of a
connection and commit at the end, but it certainly isn't the default.  if your connection crashes,
all commited transactions remain commited.

Regards,
Richard Broersma Jr.

Re: Transaction vs. Savepoints

From
Tom Lane
Date:
Andreas <maps.on@gmx.net> writes:
> As far as I know, PG handles 1 transaction per connection an several
> savepoints boxed within.

One transaction *at a time*, not one for the whole life of the session.

A good general design rule is that no transaction should stay open for
very long: do what you need to do and commit.  So the scenarios you're
envisioning are not relevant to a well-designed application.

            regards, tom lane

Re: Transaction vs. Savepoints

From
Andreas
Date:
Tom Lane wrote:
> Andreas <maps.on@gmx.net> writes:
>
>> As far as I know, PG handles 1 transaction per connection an several
>> savepoints boxed within.
>>
>
> One transaction *at a time*, not one for the whole life of the session.
>
Err .. That was what I meant.   ;-)

> A good general design rule is that no transaction should stay open for
> very long: do what you need to do and commit.
I understand this in regards to a programms that run queries in a
certain order e.g. like a script without user interaction.
There I do "this", then "that" and afterwards "something else".

A interactive application on the other hand would open records and have
them in an edit-form as long as the user needs them.
Probaply I just don't get it how to use transactions in such a
interactive scenario the right way.

I have classes that do the data handling and talk to the DB.
So a form would instanciate such a class and present its data to get edited.
Some time later the user might klick OK and the form puts the changed
data back into the object and lets it store the changes in the DB.
Would you begin the transaction with the instantiacion of the object and
put the commit in the destructor or BEGIN right where the form got
opened and COMMIT in the close of the form?

What if I enter a new record (customer) then attach some records that
reference this new customer like a phone notes or a document history.
How could I do this without nested transactions?

>   So the scenarios you're
> envisioning are not relevant to a well-designed application.
>
Is there documentation that describes how to do such a good design?
I figure this is an issue that is not bound to PostgreSQL specifically.


Re: Transaction vs. Savepoints

From
Tom Lane
Date:
Andreas <maps.on@gmx.net> writes:
> A interactive application on the other hand would open records and have
> them in an edit-form as long as the user needs them.
> Probaply I just don't get it how to use transactions in such a
> interactive scenario the right way.

Right, a lot of novices think they should hold open a transaction for
the whole edit cycle.  This is not good design: what if the user goes
off to lunch and meanwhile someone else wants to edit the same record?

Usually the best approach is to fetch the data without acquiring any
lock, allow the interactive editing to happen outside a transaction,
then when the user hits SAVE, perform a transaction that locks the
row(s), checks for conflicting changes, and commits if no conflict.
On conflict you might be able to resolve the discrepancy automatically,
but if not, you just fail and let the user deal with it ...

            regards, tom lane

Re: Transaction vs. Savepoints

From
James Long
Date:
On Fri, Feb 09, 2007 at 11:21:59AM -0500, Tom Lane wrote:
>
> Usually the best approach is to fetch the data without acquiring any
> lock, allow the interactive editing to happen outside a transaction,
> then when the user hits SAVE, perform a transaction that locks the
> row(s), checks for conflicting changes, and commits if no conflict.

Might you please expand on how the application could check for
conflicting changes?  Would this be simply fetching the record
again, and comparing to the previously-fetched version, to see
if the record is still as it was when the user started editing?
Something more sophisticated?

Thank you for your time.

Jim

Re: Transaction vs. Savepoints

From
"Daniel T. Staal"
Date:
On Fri, February 9, 2007 2:18 pm, James Long said:
> On Fri, Feb 09, 2007 at 11:21:59AM -0500, Tom Lane wrote:
>>
>> Usually the best approach is to fetch the data without acquiring any
>> lock, allow the interactive editing to happen outside a transaction,
>> then when the user hits SAVE, perform a transaction that locks the
>> row(s), checks for conflicting changes, and commits if no conflict.
>
> Might you please expand on how the application could check for
> conflicting changes?  Would this be simply fetching the record
> again, and comparing to the previously-fetched version, to see
> if the record is still as it was when the user started editing?
> Something more sophisticated?
>
> Thank you for your time.

That would be the simple way.  More complicated ways might be needed in
more complicated scenarios.  (Where, for instance, data has keep
relational integrity between two different tables, where you would have to
check that the records still existed in both before updating one.)

Exactly how sophisticated depends on the application, and the data.  (And
the database design...)  In some situations you might be able to come up
with a 'merged' change, where both changes are applied, but again that
depends on exactly what is being done.

Daniel T. Staal

---------------------------------------------------------------
This email copyright the author.  Unless otherwise noted, you
are expressly allowed to retransmit, quote, or otherwise use
the contents for non-commercial purposes.  This copyright will
expire 5 years after the author's death, or in 30 years,
whichever is longer, unless such a period is in excess of
local copyright law.
---------------------------------------------------------------


Re: Transaction vs. Savepoints

From
Tom Lane
Date:
James Long <pgsql-novice@museum.rain.com> writes:
> On Fri, Feb 09, 2007 at 11:21:59AM -0500, Tom Lane wrote:
>> Usually the best approach is to fetch the data without acquiring any
>> lock, allow the interactive editing to happen outside a transaction,
>> then when the user hits SAVE, perform a transaction that locks the
>> row(s), checks for conflicting changes, and commits if no conflict.

> Might you please expand on how the application could check for
> conflicting changes?  Would this be simply fetching the record
> again, and comparing to the previously-fetched version, to see
> if the record is still as it was when the user started editing?

Comparing all the fields is certainly the most portable way.  If you
don't mind being Postgres-specific you can instead check xmin and ctid;
if those are the same as what you read before, the tuple hasn't been
modified.  So:

    SELECT xmin, ctid, * FROM mytab WHERE whatever;

... let user edit data ...

    BEGIN;
    SELECT xmin, ctid FROM mytab WHERE whatever FOR UPDATE;
    -- abort if xmin or ctid is different from before, else:
    UPDATE mytab SET ...
    COMMIT;

Note the FOR UPDATE, that's to avoid race conditions by locking the
tuple momentarily.

            regards, tom lane