Locking rows
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
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
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
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
Import Notes
Reply to msg id not found: Jean-ChristianImbeault'smessageofFri28Feb2003192655+0900
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
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
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
Show quoted text
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?
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
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.
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
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
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
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
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
Show quoted text
In other words, I want to make invoices that have had receipts printed
no longer cancellable.Jc