bilalhaider
bilalhaider

Reputation: 181

Performing the jdbc transaction in right way

I have a database table that logs the changes occur in other tables. table structure for my log table is as following.

    Log_Table(id, table_name, operation, flag)
    values   (1,  Customer_Table, 1,       1);
    values   (2,  Customer_Table, 2,       1);
    values   (3,  Customer_Table, 1,       1);
    values   (4,  Customer_Table, 2,       1);
    values   (5,  Customer_Table, 1,       1);

I update this table against a button on a web page by doing following operations:

/* first */
public List<Long> select_Changes()
{
    select id from Log_Table where flag =1;
}

/* (wait for user input) */

/* second */
public void update_table(List<Long> ids)
{
    update Log_Table set flag =0 where id in( ids)
}

Problem is that between first and second operation its up to the user to perform the operation. Meanwhile another user at same time does the same operations. I don't want rows already selected by the first user to be selected by the second user; that is, when the second user runs the first step (assuming two more rows have been added since the first user ran it), the result should be:

    values(6,Customer,2,1);
    values(7,Customer,1,1);

Please suggest what I should do? I need to lock the rows for any kind of operation after rows are get selected. I tried select for update clause but it did not solve the problem. It's in a web application.

Upvotes: 1

Views: 105

Answers (2)

kgrittn
kgrittn

Reputation: 19471

It is almost never a good idea to hold a database transaction open while waiting for user input. What if the user goes to lunch while the transaction is pending, or their network connection goes down and isn't restored for days?

Also, you don't say what database product you are using. Depending on the product, its configuration, and the transaction isolation level, the results of the concurrent attempt what the transaction is pending, so if you want portable behavior you can't rely on the behavior of SELECT FOR UPDATE or even more standardized features.

My recommendation would be to provide a way in the row to identify pending rows, which are waiting for user confirmation. You could use three states for the flag column, to represent something like available, pending, and taken; however, you probably want to have some way to recognize rows which were presented to a user but for which the user never clicked "OK" or "Cancel" (or whatever the options are). If you add a timestamp column for that purpose, you could stay with two states for the flag column and use something like this (assuming that you are using databases which support the RETURNING clause) for the first step:

public List<Long> select_Changes()
{
    UPDATE Log_Table
      SET when_presented = CURRENT_TIMESTAMP
      WHERE flag = 1
        AND when_presented = NULL
      RETURNING id, when_presented;
}

The second step would be changed to:

public void update_table(List<Long> ids)
{
    UPDATE Log_Table
      SET flag = 0
      WHERE id IN (ids)
        AND when_presented = time_claimed;
}

The second step would not necessarily need to change, but with the change above, you could use another RETURNING clause to confirm which id values this user actually claimed, closing a race condition otherwise present if a maintenance process set when_presented back to NULL on an apparently abandoned set of rows which were then presented to another user right before the first user belatedly tried to claim them.

Upvotes: 1

bilalhaider
bilalhaider

Reputation: 181

I have added a timestamps column and an extra table with the structure

Last_Oeration_Time(id number, last_op_time timestamp(6)) 

When the first user clicks the button i run an sql insert query on Last_Oeration_Time like insert int Last_Oeration_Time(id,last_op_time) values(seq_lasst_op_time_id.nextval,sysdate)

now when the second user runs the first step (assuming two more rows have been added since the first user ran it), the result is desired result. is this ok?

Upvotes: 0

Related Questions