1

I have a table named CUSTOMERS with the following columns :

CUSTOMER_ID (NUMBER), DAY(DATE), REGISTERED_TO(NUMBER)

There are more columns in the table but it is irrelevant to my question as only the above columns are defined together as the primary key

In our application we do a large amount of inserts into this table so we do not use MERGE but use the following statement :

INSERT INTO CUSTOMERS  (CUSTOMER_ID , DAY, REGISTERED_TO)                      
                   SELECT ?, ?, ? 
                   FROM DUAL WHERE NOT EXISTS 
                            (SELECT NULL 
                             FROM CUSTOMERS
                             WHERE CUSTOMER_ID = ? 
                               AND DAY = ? 
                               AND REGISTERED_TO = ?
                              )";

We use a PreparedStatement object using the batch feature to insert a large number of records collected through the flow of the application per customer.

Problem is that sometimes I get the following error :

ORA-00001: unique constraint (CUSTOMERS_PK) violated

Strange thing is that when I do NOT use batch inserts and insert each record one by one (by simply executing pstmt.execute()) there are no errors.

Is it something wrong with the insert statement ? the jdbc driver ? Am I not using the batch mechanism correctly ?

Here is a semi-pseudo-code of my insertion loop :

  pstmt = conn.prepareStatement(statement);
  pstmt.setQueryTimeout(90);

  for each customer :
     - pstmt.setObject(1, customer id);
     - pstmt.setObject(2, current day);
     - pstmt.setObject(3, registered to);
     - pstmt.addBatch();
  end for

  pstmt.executeBatch();

It is all enclosed in a try/catch/finally block making sure the statement and connection are closed at the end of this process.

14
  • What transaction isolation are you using? Commented Nov 27, 2012 at 14:29
  • How are you getting the input data? Is there a possibility of duplicate data in the input source? Commented Nov 27, 2012 at 14:31
  • No I checked that. I logged all statements going into the batch and there were no duplicates. (It does not happen every batch but seldomly) Commented Nov 27, 2012 at 14:31
  • @mbelow Do you mean if I use auto commit ? Commented Nov 27, 2012 at 14:32
  • sounds like some parameters are still alive, when you call a second instance of your insert, you might use some static stuff? Commented Nov 27, 2012 at 14:32

1 Answer 1

2

I guess you are using several threads or processes in parallel, each doing inserts. In this case, Oracle's transaction isolation feature defeats your attempt to do the merge, because sometimes the following is bound to happen:

  • session A runs your statement, inserts a row (x,y,z)
  • session B runs the same statement, tries to insert row (x,y,z), gets a lock and waits
  • session A commits
  • session B receives the "unique constraint violated" error

That's because until session A commits, session B doesn't see the new row, so it tries to insert the same.

Sign up to request clarification or add additional context in comments.

5 Comments

You are right about the threads. Unfortunately each thread deals with only one customer and there cannot be a state where two or more threads process the same customer. I will check it again as this is an old written code but If you are right what can I do to prevent it ?.
There is hardly anything you can do to prevent it, but on the other hand, if you are sure that this is the one and only reason for the error, you can safely catch and "ignore" it (well, not completely ignore, but log for further checking etc., you know the drill...)
Yep that was my last resort. I'll check again your theory about the synchronization of the sessions. There must be something duplicated somewhere. Thanks for the help
Hi again @ammoQ. I did a very simple test by creating a single prepared statement, added the parameters with fixed values and executed the batch every 20 statements (i.e. using addBatch). Strange thing is that only if the customer was not present in the table the batch fails. BUT if the customer is already inside the table than the batch succeeds. Any thoughts on that ?
@giorashc if the customer already exists, the statement does nothing, so how could it fail?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.