Thread: Locking rows

Locking rows

From
Jean-Christian Imbeault
Date:
I have written an application that prints out data from a database. One
problem I am encountering is in the time it takes to generate the print
file the data may have changed.

I was thinking that a way around this would be to lock the rows that are
used to generate the print file. However I am not quite sure how to best
go about this.

Is locking the rows the best (or simplest) solution?

If locking is a good idea how could I lock and then unlock the rows
returned by this (somewhat ugly) query?

select prod_id, sum(quantity), case when (select stock_qty+cancelled_qty
from stock where pid=prod_id) is null then 0 else (select
stock_qty+cancelled_qty from stock where pid=prod_id) end as stock_qty
from invoice_li, invoices where invoices.id=invoice_id AND dist_id=1 AND
NOT invoices.cancelled AND NOT invoice_li.cancelled group by prod_id;

I will also be doing some other select queries between this one and the
printing (I need to get more information on each prod_id returned).

I've read the iDocs and Bruce's online manual but can seem to find any
info on the syntax for locking other that for SELECT FOR UPDATE. And
even then the docs don't state how to remove the lock created by a
SELECT FOR UPDATE.

Thanks!

Jc


Re: Locking rows

From
Richard Huxton
Date:
On Friday 28 Feb 2003 10:26 am, Jean-Christian Imbeault wrote:
> I have written an application that prints out data from a database. One
> problem I am encountering is in the time it takes to generate the print
> file the data may have changed.
>
> I was thinking that a way around this would be to lock the rows that are
> used to generate the print file. However I am not quite sure how to best
> go about this.
>
> Is locking the rows the best (or simplest) solution?

See the chapter "Concurrency Control" in the User Guide. Sounds like you want
to set transaction level to serializable - no explicit locking required.

This means that within your report-building transaction you don't see any
changes to the database (unless you do any within the transaction itself).

HTH

--
  Richard Huxton

Re: Locking rows

From
Neil Conway
Date:
On Fri, 2003-02-28 at 05:26, Jean-Christian Imbeault wrote:
> I have written an application that prints out data from a database. One
> problem I am encountering is in the time it takes to generate the print
> file the data may have changed.

Is that a problem? ISTM that if you need to keep the DB consistent
during the entire print job, you're going to get pretty poor concurrent
performance regardless.

> I've read the iDocs and Bruce's online manual but can seem to find any
> info on the syntax for locking other that for SELECT FOR UPDATE. And
> even then the docs don't state how to remove the lock created by a
> SELECT FOR UPDATE.

The docs on FOR UPDATE say:

This prevents them from being modified or deleted by other transactions
until the current transaction ends; that is, other transactions that
attempt UPDATE, DELETE, or SELECT FOR UPDATE of these rows will be
blocked until the current transaction ends.

Cheers,

Neil
--
Neil Conway <neilc@samurai.com> || PGP Key ID: DB3C29FC




Re: Locking rows

From
Doug McNaught
Date:
Jean-Christian Imbeault <jc@mega-bucks.co.jp> writes:

> I have written an application that prints out data from a
> database. One problem I am encountering is in the time it takes to
> generate the print file the data may have changed.

If you use a single query to generate the rows, this will not be a
problem.

If you use multiple queries, execute them all inside a transaction and
you will get a consistent view of the database.

No locking needed.

-Doug

Re: Locking rows

From
Jean-Christian Imbeault
Date:
Doug McNaught wrote:
>
> If you use a single query to generate the rows, this will not be a
> problem.
>
> If you use multiple queries, execute them all inside a transaction and
> you will get a consistent view of the database.
>
> No locking needed.

True but what I am worried about is the data changing while I am in a
transaction.

Right now I want to print customer receipts for items that have been
ordered. But while I gathering the data, which takes more than one
query, a customer might come along and cancel an invoice.

In that case I would print a receipt for something that was cancelled.

I need to find a way to avoid this. I thought locking was a way around
this ... or maybe I need to change my "business" logic or the way the
app gathers the data?

Jc


Re: Locking rows

From
Manfred Koizar
Date:
On Fri, 28 Feb 2003 19:26:55 +0900, Jean-Christian Imbeault
<jc@mega-bucks.co.jp> wrote:
>I have written an application that prints out data from a database. One
>problem I am encountering is in the time it takes to generate the print
>file the data may have changed.
> [...]
>Is locking the rows the best (or simplest) solution?

The simplest (and IMHO best) solution is:

    BEGIN;
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
    SELECT <this> ...
    SELECT <that> ...
    SELECT <whatever> ...
    COMMIT;

If your entire report is generated from the result of a single SELECT,
you don't even need that BEGIN/SET TRANSACTION/COMMIT stuff.

Servus
 Manfred

Re: Locking rows

From
Jonathan Bartlett
Date:
> ordered. But while I gathering the data, which takes more than one
> query, a customer might come along and cancel an invoice.

So what?  Wouldn't you have the same situation if they cancelled
imediately after you finished the report?

Jon

>
> In that case I would print a receipt for something that was cancelled.
>
> I need to find a way to avoid this. I thought locking was a way around
> this ... or maybe I need to change my "business" logic or the way the
> app gathers the data?
>
> Jc
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 5: Have you checked our extensive FAQ?
>
> http://www.postgresql.org/users-lounge/docs/faq.html
>


Re: Locking rows

From
Tom Lane
Date:
Jean-Christian Imbeault <jc@mega-bucks.co.jp> writes:
> True but what I am worried about is the data changing while I am in a
> transaction.

Start a serializable-mode transaction, and the data will not change ---
not from your perspective, anyway.  Trying to lock it down to not change
from other people's perspectives seems pointless.

            regards, tom lane

Re: Locking rows

From
Dmitry Tkach
Date:
Jean-Christian Imbeault wrote:
> Doug McNaught wrote:
>
>>If you use a single query to generate the rows, this will not be a
>>problem.
>>
>>If you use multiple queries, execute them all inside a transaction and
>>you will get a consistent view of the database.
>>
>>No locking needed.
>
>
> True but what I am worried about is the data changing while I am in a
> transaction.
>
> Right now I want to print customer receipts for items that have been
> ordered. But while I gathering the data, which takes more than one
> query, a customer might come along and cancel an invoice.
>
> In that case I would print a receipt for something that was cancelled.
>
> I need to find a way to avoid this. I thought locking was a way around
> this ... or maybe I need to change my "business" logic or the way the
> app gathers the data?
>

But can't the customer cancel that invoice one millisecond *after* your application is done?
As far as I can see, from the customer's standpoint, it will look exactly the same, won't it?

Dima


Re: Locking rows

From
"Nigel J. Andrews"
Date:
On Sat, 1 Mar 2003, Jean-Christian Imbeault wrote:

> Doug McNaught wrote:
> >
> > If you use a single query to generate the rows, this will not be a
> > problem.
> >
> > If you use multiple queries, execute them all inside a transaction and
> > you will get a consistent view of the database.
> >
> > No locking needed.
>
> True but what I am worried about is the data changing while I am in a
> transaction.
>
> Right now I want to print customer receipts for items that have been
> ordered. But while I gathering the data, which takes more than one
> query, a customer might come along and cancel an invoice.
>
> In that case I would print a receipt for something that was cancelled.

But then what happens if someone does want to cancel? You're going to say they
can't? Unless the invoice print run is going to take quite a while I think
you're approaching it incorrectly. Even if the print run is going to take along
time you're still approaching it wrong. Say it runs for 2 hours and a customer
wants to cancel but you've locked the tables because of the printing. That
customer has to wait for 2 hours and then still needs the credit note
printing. Why not just let the transaction take a snapshot of a consistent
database, do the print run and do the credit note run as normal. You can't
avoid the credit note run whatever.

> I need to find a way to avoid this. I thought locking was a way around
> this ... or maybe I need to change my "business" logic or the way the
> app gathers the data?

It's not something I've looked at but presumably lock table will lock it so
inserts are also locked out. Obviously select for update can't prevent those
from happening so if cancellations are recorded via insert then there would
appear to be no option but to lock tables.

I could have the wrong end of the stick for what you are wanting. I only vaguly
remember the start of this thread.


Nigel Andrews



Re: Locking rows

From
"scott.marlowe"
Date:
On Fri, 28 Feb 2003, Jean-Christian Imbeault wrote:

> I have written an application that prints out data from a database. One
> problem I am encountering is in the time it takes to generate the print
> file the data may have changed.
>
> I was thinking that a way around this would be to lock the rows that are
> used to generate the print file. However I am not quite sure how to best
> go about this.
>
> Is locking the rows the best (or simplest) solution?
>
> If locking is a good idea how could I lock and then unlock the rows
> returned by this (somewhat ugly) query?
>
> select prod_id, sum(quantity), case when (select stock_qty+cancelled_qty
> from stock where pid=prod_id) is null then 0 else (select
> stock_qty+cancelled_qty from stock where pid=prod_id) end as stock_qty
> from invoice_li, invoices where invoices.id=invoice_id AND dist_id=1 AND
> NOT invoices.cancelled AND NOT invoice_li.cancelled group by prod_id;
>
> I will also be doing some other select queries between this one and the
> printing (I need to get more information on each prod_id returned).
>
> I've read the iDocs and Bruce's online manual but can seem to find any
> info on the syntax for locking other that for SELECT FOR UPDATE. And
> even then the docs don't state how to remove the lock created by a
> SELECT FOR UPDATE.

No need.  Take a look here:

http://www.postgresql.org/docs/view.php?version=7.3&idoc=0&file=transaction-iso.html

And read up on serializable, which should do exactly what you want.  I.e.
Even if people are changing the database underneath you, you'll see the
database wholly as if it never changed since your begin; was issued.


Re: Locking rows

From
Jean-Christian Imbeault
Date:
Jonathan Bartlett wrote:
 >
 > So what?  Wouldn't you have the same situation if they cancelled
 > imediately after you finished the report?

No. While I gather the data necessary to print a receipt I mark the
invoice as non-cancellable.

In other words, I want to make invoices that have had receipts printed
no longer cancellable.

Jc


Re: Locking rows

From
Jean-Christian Imbeault
Date:
Nigel J. Andrews wrote:
 >
 > But then what happens if someone does want to cancel? You're going to
say they
 > can't?

Exactly. Once you have been charged (i.e. an invoice has been printed)
for an item you cannot cancel it. At least that's the way the the
company would like it to be :)

Jc


Re: Locking rows

From
Jonathan Bartlett
Date:
>
> No. While I gather the data necessary to print a receipt I mark the
> invoice as non-cancellable.
>

Why don't you have two fields - non-cancellable and printed.

In transaction A, you mark everything you want to print as
non-cancellable.

In transaction B, you query for everything that is not printed AND
non-cancellable, and print it, and then update those same records as being
printed.

In addition, you probably want to turn on the maximum isolation level to
fully prevent rewriting records.

Jon

> In other words, I want to make invoices that have had receipts printed
> no longer cancellable.
>
> Jc
>