0

I have the same question as described here and also I think the answer https://stackoverflow.com/a/22343265/297487 is a good solution but I have another question about this answer.

Is the following trigger (copied from answer) thread-safe? I mean if two concurrent record inserted to table, does "priority" column (as describe in question) have consistent value (The same value as id)?

delimiter //
 drop trigger if exists bi_table_name //

 create trigger bi_table_name before insert on table_name
for each row begin
   set @auto_id := ( SELECT AUTO_INCREMENT 
                FROM INFORMATION_SCHEMA.TABLES
                WHERE TABLE_NAME='table_name'
                  AND TABLE_SCHEMA=DATABASE() ); 
set new.priority= @auto_id;
end;
//

delimiter ;

How do we interpret "for each row" clause? Suppose that MySQL wants insert two concurrent rows. How does this trigger works?

One interpretation is as follows:

MySQL locks table and before insert one of the rows (one of concurrent record) MySQL trigger starts and gets current AUTO_INCREMENT value and sets it to "priority" column and then inserts a record. After that MySQL starts inserting another record and then the same situation applies for new record.

Another interpretation might be as follows:

When two concurrent records are inserted to MySQL, MySQL locks the table and then before inserting two concurrent records a trigger starts and "for each row" clause iterate between two record and set "priority" column value to the same value and then insert two concurrent record in database. In this situation the trigger does not work as expected.

Which one of the above interpretation is correct?

Update :

I have the following table :

    CREATE TABLE `t_file` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `name` varchar(255) COLLATE utf8_persian_ci NOT NULL,
      `p_name` bigint(20) DEFAULT NULL,
      PRIMARY KEY (`id`),
      UNIQUE KEY `p_name_2` (`p_name`)

    ) ENGINE=InnoDB AUTO_INCREMENT=206284 DEFAULT CHARSET=utf8 COLLATE=utf8_persian_ci;

I want to insert value of p_name the same as id when row inserted.

The trigger that sets value of p_name is as follows(copied from your code)

  delimiter $$
    drop trigger if exists file_p_name $$

    create trigger file_p_name before insert on t_file
    for each row begin
      set @id := ( SELECT AUTO_INCREMENT
                        FROM INFORMATION_SCHEMA.TABLES
                        WHERE TABLE_NAME='t_file'
                          AND TABLE_SCHEMA=DATABASE() );
      set new.p_name= @id;
    end;
    $$

    delimiter ;

In our application, i surround the code that inserts int_file table with try catch,in almost always everything is OK,but sometimes(in concurrent insert to t_file table), i see the following exception in our application's log:

   SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry \'387456\' for key \'p_name_2\''

It seems the trigger does not work as expected or maybe i am wrong!!!

Community
  • 1
  • 1
Khosro
  • 707
  • 1
  • 7
  • 16

1 Answers1

0

The answer referred in your question was posted by me some time back.

While in "For Each Row", The NEW is the corresponding new row, being inserted, in context. And the set new.xxx is only applicable for that row and but not 'for all rows' in batch. So there won't be any collision and the question of failure should not arise.

I have also answered a similar question How does “for each row” work in triggers in mysql?. Please go through the examples given in the answer.

Refer to Documentation:

Community
  • 1
  • 1
Ravinder Reddy
  • 23,692
  • 6
  • 52
  • 82
  • it seems your are OK,but I have uploaded this code in a system with the same situation that has many concurrent users.I will inform you about result. – Khosro Jan 29 '15 at 13:29
  • I order to test above trigger in a concurrent system , i have created a unique constraint for "priority" column.After a three days ,i have seen some exceptions indicate that duplicate "priority" column insertion in mentioned table.So that it seems above trigger is not thread-safe and has some problem in concurrent system. – Khosro Jan 31 '15 at 04:43
  • It is really bad MySQL has not "after trigger" for updating a row after inserting it. – Khosro Jan 31 '15 at 04:44
  • I don't agree with you. You mentioned that you created `priority` as `unique` column. If an update on the column is set through `trigger` definition and it fails, then trigger is not the culprit here but the idea of setting a constraint column value in the trigger body. Triggers might have not exist if they are not thread-safe. If you still believe on what you tested is correct, you better post the sequence of operations followed along with tables, trigger definitions and data. – Ravinder Reddy Jan 31 '15 at 17:30
  • Excuse me for delay answer.I was evaluating my code more to make sure exception is related to `trigger`.I updated my question. – Khosro Feb 04 '15 at 05:16
  • **@Khosro**: Can you also post the test setup you followed for execution? – Ravinder Reddy Jul 15 '15 at 03:19