Обсуждение: confused about transactions and connection pools

Поиск
Список
Период
Сортировка

confused about transactions and connection pools

От
David Goodenough
Дата:
I am running a servlet on Tomcat 5.5 which talks to a PostgreSQL DB (8.1)
using the Jdbc3 driver.

The database is accessed using a DataSource, and so at the start of each
servlet doPost call I get a new connection, do a setAutoCommit( false) and
then get on with the processing.  At the end if it works I do a commit
otherwise I do a rollback.  Then I setAutoCommit( true) and write to a
log table (a single insert which I always want to do) and close the
connection.  The servlet is entirely stateless, it keeps nothing from
one invocation to the next other than the DataSource which it opens
during its init( ) method along with a few configuration parameters.

I turned on postgresql logging and for the first request (the two requests and
their responses were identical - both failed) the postgresql log said:-

LOG:  statement: BEGIN
LOG:  statement: SELECT password, role, proxy, pool, company FROM users WHERE
id = $1
LOG:  statement: INSERT INTO users( created, phone, password, role, origin,
xml, updated, id) VALUES( $1, $2, $3, $4, $5, $6, $7, $8)
LOG:  statement: INSERT INTO users( created, phone, password, role, origin,
xml, updated, id) VALUES( $1, $2, $3, $4, $5, $6, $7, $8)
ERROR:  duplicate key violates unique constraint "users_pkey"
LOG:  statement: ROLLBACK
LOG:  statement: INSERT INTO logs( userid, ip, request, response, at, success)
VALUES( $1, $2, $3, $4, $5, $6)
LOG:  statement: SELECT 1 FROM ONLY "public"."users" x WHERE "id" = $1 FOR
UPDATE OF x
CONTEXT:  SQL statement "SELECT 1 FROM ONLY "public"."users" x WHERE "id" = $1
FOR UPDATE OF x"

and for the second one it said:

LOG:  statement: SELECT password, role, proxy, pool, company FROM users WHERE
id = $1
LOG:  statement: INSERT INTO users( created, phone, password, role, origin,
xml, updated, id) VALUES( $1, $2, $3, $4, $5, $6, $7, $8)
LOG:  statement: INSERT INTO users( created, phone, password, role, origin,
xml, updated, id) VALUES( $1, $2, $3, $4, $5, $6, $7, $8)
ERROR:  duplicate key violates unique constraint "users_pkey"
LOG:  statement: INSERT INTO logs( userid, ip, request, response, at, success)
VALUES( $1, $2, $3, $4, $5, $6)

which is slightly different.

Now the first thing I notice about this is that the first one has the BEGIN
I would expect, followed by a select (which I recognise) followed by the
insert that fails (quite why it logs it twice I do not know, it is certainly
not issued twice) followed by the rollback (because it failed) and the insert
into the logs table.

Then comes an odd SELECT statement (the one SELECT 1) which I do not recognise
and I can not find anywhere in my code.  It is referencing one of my tables
(users) and it says both LOG: and CONTEXT: which I do not understand.  Given
that the autoCommit was turned off after the rollback this should have had
no effect.

The we get to the second time through the servlet.  First thing - no BEGIN
or ROLLBACK, but the code went through a call to connection.setAutoCommit(
false).  Secondly this odd statement that I do not recognise id no longer
there.

My reason for investigating this is that I had an odd problem with the
log table being left with a lock on it, when none should exist as the
insert is done outside a transaction.

I have tried the same thing with a transaction that works (you just do not
get the ERROR: and in the first case you get a COMMIT not a ROLLBACK.  Also
in that case the INSERT is not repeated in the log so I guess that is an
artifact of the failure.

Obviously I am doing something wrong, but for the life of me I can not see
what.  Anyone got any ideas?

David

Re: confused about transactions and connection pools

От
Dave Cramer
Дата:
On 30-Oct-06, at 6:17 AM, David Goodenough wrote:

> I am running a servlet on Tomcat 5.5 which talks to a PostgreSQL DB
> (8.1)
> using the Jdbc3 driver.
>
> The database is accessed using a DataSource, and so at the start of
> each
> servlet doPost call I get a new connection, do a setAutoCommit
> ( false) and
> then get on with the processing.  At the end if it works I do a commit
> otherwise I do a rollback.  Then I setAutoCommit( true) and write to a
> log table (a single insert which I always want to do) and close the
> connection.  The servlet is entirely stateless, it keeps nothing from
> one invocation to the next other than the DataSource which it opens
> during its init( ) method along with a few configuration parameters.
>
> I turned on postgresql logging and for the first request (the two
> requests and
> their responses were identical - both failed) the postgresql log
> said:-
>
> LOG:  statement: BEGIN
> LOG:  statement: SELECT password, role, proxy, pool, company FROM
> users WHERE
> id = $1
> LOG:  statement: INSERT INTO users( created, phone, password, role,
> origin,
> xml, updated, id) VALUES( $1, $2, $3, $4, $5, $6, $7, $8)
> LOG:  statement: INSERT INTO users( created, phone, password, role,
> origin,
> xml, updated, id) VALUES( $1, $2, $3, $4, $5, $6, $7, $8)
> ERROR:  duplicate key violates unique constraint "users_pkey"
> LOG:  statement: ROLLBACK
> LOG:  statement: INSERT INTO logs( userid, ip, request, response,
> at, success)
> VALUES( $1, $2, $3, $4, $5, $6)
> LOG:  statement: SELECT 1 FROM ONLY "public"."users" x WHERE "id" =
> $1 FOR
> UPDATE OF x
> CONTEXT:  SQL statement "SELECT 1 FROM ONLY "public"."users" x
> WHERE "id" = $1
> FOR UPDATE OF x"
>
> and for the second one it said:
>
> LOG:  statement: SELECT password, role, proxy, pool, company FROM
> users WHERE
> id = $1
> LOG:  statement: INSERT INTO users( created, phone, password, role,
> origin,
> xml, updated, id) VALUES( $1, $2, $3, $4, $5, $6, $7, $8)
> LOG:  statement: INSERT INTO users( created, phone, password, role,
> origin,
> xml, updated, id) VALUES( $1, $2, $3, $4, $5, $6, $7, $8)
> ERROR:  duplicate key violates unique constraint "users_pkey"
> LOG:  statement: INSERT INTO logs( userid, ip, request, response,
> at, success)
> VALUES( $1, $2, $3, $4, $5, $6)
>
> which is slightly different.
>
> Now the first thing I notice about this is that the first one has
> the BEGIN
> I would expect, followed by a select (which I recognise) followed
> by the
> insert that fails (quite why it logs it twice I do not know, it is
> certainly
> not issued twice) followed by the rollback (because it failed) and
> the insert
> into the logs table.
>
> Then comes an odd SELECT statement (the one SELECT 1) which I do
> not recognise
> and I can not find anywhere in my code.

Are you using hibernate ? Either way the select 1 is locking the
users table.
> It is referencing one of my tables
> (users) and it says both LOG: and CONTEXT: which I do not
> understand.  Given
> that the autoCommit was turned off after the rollback this should
> have had
> no effect.
>
> The we get to the second time through the servlet.  First thing -
> no BEGIN
> or ROLLBACK, but the code went through a call to
> connection.setAutoCommit(
> false).  Secondly this odd statement that I do not recognise id no
> longer
> there.
>
> My reason for investigating this is that I had an odd problem with the
> log table being left with a lock on it, when none should exist as the
> insert is done outside a transaction.
>
> I have tried the same thing with a transaction that works (you just
> do not
> get the ERROR: and in the first case you get a COMMIT not a
> ROLLBACK.  Also
> in that case the INSERT is not repeated in the log so I guess that
> is an
> artifact of the failure.
>
> Obviously I am doing something wrong, but for the life of me I can
> not see
> what.  Anyone got any ideas?
First of all I'd suggest you add pid to the logs so you can see which
connection is doing what. The server logs sequentially in the order
it sees things. You could have 2 connections logs interleaved there.

Dave
>
> David
>
> ---------------------------(end of
> broadcast)---------------------------
> TIP 2: Don't 'kill -9' the postmaster
>


Re: confused about transactions and connection pools

От
David Goodenough
Дата:
On Monday 30 October 2006 11:35, Dave Cramer wrote:
> On 30-Oct-06, at 6:17 AM, David Goodenough wrote:
> > I am running a servlet on Tomcat 5.5 which talks to a PostgreSQL DB
> > (8.1)
> > using the Jdbc3 driver.
> >
> > The database is accessed using a DataSource, and so at the start of
> > each
> > servlet doPost call I get a new connection, do a setAutoCommit
> > ( false) and
> > then get on with the processing.  At the end if it works I do a commit
> > otherwise I do a rollback.  Then I setAutoCommit( true) and write to a
> > log table (a single insert which I always want to do) and close the
> > connection.  The servlet is entirely stateless, it keeps nothing from
> > one invocation to the next other than the DataSource which it opens
> > during its init( ) method along with a few configuration parameters.
> >
> > I turned on postgresql logging and for the first request (the two
> > requests and
> > their responses were identical - both failed) the postgresql log
> > said:-
> >
> > LOG:  statement: BEGIN
> > LOG:  statement: SELECT password, role, proxy, pool, company FROM
> > users WHERE
> > id = $1
> > LOG:  statement: INSERT INTO users( created, phone, password, role,
> > origin,
> > xml, updated, id) VALUES( $1, $2, $3, $4, $5, $6, $7, $8)
> > LOG:  statement: INSERT INTO users( created, phone, password, role,
> > origin,
> > xml, updated, id) VALUES( $1, $2, $3, $4, $5, $6, $7, $8)
> > ERROR:  duplicate key violates unique constraint "users_pkey"
> > LOG:  statement: ROLLBACK
> > LOG:  statement: INSERT INTO logs( userid, ip, request, response,
> > at, success)
> > VALUES( $1, $2, $3, $4, $5, $6)
> > LOG:  statement: SELECT 1 FROM ONLY "public"."users" x WHERE "id" =
> > $1 FOR
> > UPDATE OF x
> > CONTEXT:  SQL statement "SELECT 1 FROM ONLY "public"."users" x
> > WHERE "id" = $1
> > FOR UPDATE OF x"
> >
> > and for the second one it said:
> >
> > LOG:  statement: SELECT password, role, proxy, pool, company FROM
> > users WHERE
> > id = $1
> > LOG:  statement: INSERT INTO users( created, phone, password, role,
> > origin,
> > xml, updated, id) VALUES( $1, $2, $3, $4, $5, $6, $7, $8)
> > LOG:  statement: INSERT INTO users( created, phone, password, role,
> > origin,
> > xml, updated, id) VALUES( $1, $2, $3, $4, $5, $6, $7, $8)
> > ERROR:  duplicate key violates unique constraint "users_pkey"
> > LOG:  statement: INSERT INTO logs( userid, ip, request, response,
> > at, success)
> > VALUES( $1, $2, $3, $4, $5, $6)
> >
> > which is slightly different.
> >
> > Now the first thing I notice about this is that the first one has
> > the BEGIN
> > I would expect, followed by a select (which I recognise) followed
> > by the
> > insert that fails (quite why it logs it twice I do not know, it is
> > certainly
> > not issued twice) followed by the rollback (because it failed) and
> > the insert
> > into the logs table.
> >
> > Then comes an odd SELECT statement (the one SELECT 1) which I do
> > not recognise
> > and I can not find anywhere in my code.
>
> Are you using hibernate ? Either way the select 1 is locking the
> users table.

No, no hibernate.  I was using ha-jdbc but I turned it off for this
test am I am using the Postgresql JDBC driver directly.

>
> > It is referencing one of my tables
> > (users) and it says both LOG: and CONTEXT: which I do not
> > understand.  Given
> > that the autoCommit was turned off after the rollback this should
> > have had
> > no effect.
> >
> > The we get to the second time through the servlet.  First thing -
> > no BEGIN
> > or ROLLBACK, but the code went through a call to
> > connection.setAutoCommit(
> > false).  Secondly this odd statement that I do not recognise id no
> > longer
> > there.
> >
> > My reason for investigating this is that I had an odd problem with the
> > log table being left with a lock on it, when none should exist as the
> > insert is done outside a transaction.
> >
> > I have tried the same thing with a transaction that works (you just
> > do not
> > get the ERROR: and in the first case you get a COMMIT not a
> > ROLLBACK.  Also
> > in that case the INSERT is not repeated in the log so I guess that
> > is an
> > artifact of the failure.
> >
> > Obviously I am doing something wrong, but for the life of me I can
> > not see
> > what.  Anyone got any ideas?
>
> First of all I'd suggest you add pid to the logs so you can see which
> connection is doing what. The server logs sequentially in the order
> it sees things. You could have 2 connections logs interleaved there.

This is on a test machine, and I am submitting the requests to it manually
(they are XML and I have a testrig that submits them), so I know that there
is only one thing going on at the time of the test.

However for completeness it would be good to turn on the pid, I guess I
need the log_line_prefix set up.  I will give it a go.

David

>
> Dave
>
> > David
> >
> > ---------------------------(end of
> > broadcast)---------------------------
> > TIP 2: Don't 'kill -9' the postmaster
>
> ---------------------------(end of broadcast)---------------------------
> TIP 2: Don't 'kill -9' the postmaster

Re: confused about transactions and connection pools

От
Kris Jurka
Дата:

On Mon, 30 Oct 2006, David Goodenough wrote:

> The we get to the second time through the servlet.  First thing - no BEGIN
> or ROLLBACK, but the code went through a call to connection.setAutoCommit(
> false).  Secondly this odd statement that I do not recognise id no longer
> there.
>

For each connection the statements BEGIN, ROLLBACK, and COMMIT are only
prepared once and after that they are executed again and again.  This can
be very confusing when looking at the logs which only show the preparation
step, but not execution.  So even though you can't see them, they're being
executed.  The 8.2 release will be the first release that can accurately
log this usage pattern.

Kris Jurka


Re: confused about transactions and connection pools

От
David Goodenough
Дата:
On Monday 30 October 2006 18:40, Kris Jurka wrote:
> On Mon, 30 Oct 2006, David Goodenough wrote:
> > The we get to the second time through the servlet.  First thing - no
> > BEGIN or ROLLBACK, but the code went through a call to
> > connection.setAutoCommit( false).  Secondly this odd statement that I do
> > not recognise id no longer there.
>
> For each connection the statements BEGIN, ROLLBACK, and COMMIT are only
> prepared once and after that they are executed again and again.  This can
> be very confusing when looking at the logs which only show the preparation
> step, but not execution.  So even though you can't see them, they're being
> executed.  The 8.2 release will be the first release that can accurately
> log this usage pattern.
>
> Kris Jurka
is it only the BEGIN, ROLLBACK and COMMIT that are only shown when being
prepared?  I ask because all the statement are PreparedStatements and they
get prepared each time we get a new connection, which I understand means
that they prepared for real first time they are used, but are then cached
and therefore that one should always use substitutable ? paramaters so that
the statement is always the same.  If only the prepares are being logged
then the pool is obviously not working as the insert into the logs table
get logged each time through.

I am now more confused.

David

Re: confused about transactions and connection pools

От
Kris Jurka
Дата:

On Mon, 30 Oct 2006, David Goodenough wrote:

> On Monday 30 October 2006 18:40, Kris Jurka wrote:
>> For each connection the statements BEGIN, ROLLBACK, and COMMIT are only
>> prepared once and after that they are executed again and again.  This can
>> be very confusing when looking at the logs which only show the preparation
>> step, but not execution.  So even though you can't see them, they're being
>> executed.  The 8.2 release will be the first release that can accurately
>> log this usage pattern.
>>
> is it only the BEGIN, ROLLBACK and COMMIT that are only shown when being
> prepared?  I ask because all the statement are PreparedStatements and they
> get prepared each time we get a new connection, which I understand means
> that they prepared for real first time they are used, but are then cached
> and therefore that one should always use substitutable ? paramaters so that
> the statement is always the same.  If only the prepares are being logged
> then the pool is obviously not working as the insert into the logs table
> get logged each time through.
>

The driver handles BEGIN, ROLLBACK, and COMMIT slightly differently than
regular PreparedStatement objects.  For user PreparedStatements, the
driver only avoids reparsing it on the fifth execution.  This is
configurable via the prepareThreshold URL parameter.  So after you use
it five times you won't see it being logged any more.  For these
transaction handling commands the driver knows it will be reusing them
often, so it switches over right away, not on the fifth exectuion.  The
execution count is kept in the PreparedStatement object so if you do
something like:

get connection from pool
create PreparedStatement
execute PreparedStatement
close PreparedStatement
return connection to pool

Then no matter how many times you do the above the it will never switch
to avoiding the reparse because the count is kept in the
PreparedStatement which is continually created and destroyed,
reinitializing the counter.  The driver/connection manages the reference
to the transaction handling commands so it can keep them around across
connections the pool hands out.

Kris Jurka


Re: confused about transactions and connection pools

От
Tom Lane
Дата:
Kris Jurka <books@ejurka.com> writes:
> For each connection the statements BEGIN, ROLLBACK, and COMMIT are only
> prepared once and after that they are executed again and again.  This can
> be very confusing when looking at the logs which only show the preparation
> step, but not execution.  So even though you can't see them, they're being
> executed.  The 8.2 release will be the first release that can accurately
> log this usage pattern.

BTW, have you verified that it's actually worth the trouble to prepare
these commands?  Given that there's no planning cost for a utility
statement, and hardly any parsing cost for one-word commands, I'm a bit
dubious that the prepared-statement machinery actually results in a win
compared to just issuing simple Query messages.

            regards, tom lane

Re: confused about transactions and connection pools

От
Dave Cramer
Дата:
On 30-Oct-06, at 5:25 PM, Tom Lane wrote:

> Kris Jurka <books@ejurka.com> writes:
>> For each connection the statements BEGIN, ROLLBACK, and COMMIT are
>> only
>> prepared once and after that they are executed again and again.
>> This can
>> be very confusing when looking at the logs which only show the
>> preparation
>> step, but not execution.  So even though you can't see them,
>> they're being
>> executed.  The 8.2 release will be the first release that can
>> accurately
>> log this usage pattern.
>
> BTW, have you verified that it's actually worth the trouble to prepare
> these commands?  Given that there's no planning cost for a utility
> statement, and hardly any parsing cost for one-word commands, I'm a
> bit
> dubious that the prepared-statement machinery actually results in a
> win
> compared to just issuing simple Query messages.

Yeah, the driver needs to be taught to not prepare *everything* in v3
mode

Dave
>
>             regards, tom lane
>
> ---------------------------(end of
> broadcast)---------------------------
> TIP 4: Have you searched our list archives?
>
>                http://archives.postgresql.org
>


Re: confused about transactions and connection pools

От
Oliver Jowett
Дата:
Tom Lane wrote:
> I'm a bit
> dubious that the prepared-statement machinery actually results in a win
> compared to just issuing simple Query messages.

The driver has no infrastructure for issuing simple Query messages in v3
mode, and anyway we want to batch the BEGIN up with the query that
follows it.

COMMIT/ROLLBACK might be of dubious value but I don't know if it's worth
having a completely separate code path in the driver just for that one case.

-O

Re: confused about transactions and connection pools

От
Oliver Jowett
Дата:
Dave Cramer wrote:

> Yeah, the driver needs to be taught to not prepare *everything* in v3  mode

What do you want to avoid preparing, other than BEGIN/COMMIT/ROLLBACK?

-O

Re: confused about transactions and connection pools

От
Dave Cramer
Дата:
On 31-Oct-06, at 6:55 AM, Oliver Jowett wrote:

> Dave Cramer wrote:
>
>> Yeah, the driver needs to be taught to not prepare *everything* in
>> v3  mode
>
> What do you want to avoid preparing, other than BEGIN/COMMIT/ROLLBACK?
>
We also use it for setting the transaction mode
> -O
>
> ---------------------------(end of
> broadcast)---------------------------
> TIP 2: Don't 'kill -9' the postmaster
>


Re: confused about transactions and connection pools

От
Kris Jurka
Дата:

On Wed, 1 Nov 2006, Oliver Jowett wrote:

> Tom Lane wrote:
>> I'm a bit
>> dubious that the prepared-statement machinery actually results in a win
>> compared to just issuing simple Query messages.
>
> The driver has no infrastructure for issuing simple Query messages in v3
> mode, and anyway we want to batch the BEGIN up with the query that follows
> it.
>

We could easily use QueryExecutor.QUERY_ONESHOT for these, but I'm not
sure what the point would be.  The 8.2 release can log this correctly so
I'm not sure why bother changing it for the 8.2 driver.  Some quick
testing shows that using ONESHOT results in a 4-5% hit using the attached
test case of a BEGIN; SELECT 1; COMMIT loop.

Kris Jurka

Вложения