java - Nested update with select deadlock -


background

i using code seems deadlock itself. in java, produces deadlockloserdataaccessexception periodically, , offending statement causing deadlock itself. (this being run in transaction innodb)

update set     a_field = (select sum(b_field) b b.a_id = a.id)      = ? 

after doing reading, came across for update clause performing locking read. modified code below

update set     a_field = (select sum(b_field) b b.a_id = a.id update)      = ? 

question

is proper add for update lock inside nested update/select? none of examples on locking reads documentation use for update in way.

structure of tables

below simplified version fields applicable query

table a

id      int(11) primary key a_field int(11) 

table b

id      int(11) primary key a_id    int(11) foreign key references (a.id) b_field int(11) 

indexes

the indexes exist single column indexes on both primary keys, , foreign key table a.

a plain answer question is:

yes, mysql supports for update clause in subqueries

hovewer sure not solution problem.
update in subquery doesn't prevent deadlocks in case

since didn't show whole transaction, snippet, guess there must other command in transaction places lock on record referenced foreign key.

better understandeing of how locking in mysql works, take @ simple example:

create table `a` (     `id` int(11) primary key auto_increment,     `a_field` int(11)  ); create table `b` (     `id` int(11) primary key auto_increment,     `a_id` int(11),     `b_field` int(11),    constraint `b_fk_aid` foreign key (`a_id`) references `a` (`id`) ); create table `c` (     `id` int(11) primary key auto_increment,     `a_id` int(11),     `c_field` int(11),    constraint `c_fk_aid` foreign key (`a_id`) references `a` (`id`) );  insert a( a_field ) values ( 10 ), ( 20 ); insert b( a_id, b_field ) values ( 1, 20 ), ( 2, 30 );  delimiter $$ create procedure test( p_a_id int, p_count int ) begin    declare int;    set = 0;    repeat       start transaction;       insert c( a_id, c_field ) values ( p_a_id, round(rand() * 100) );       update          set  a_field = (                    select sum(b_field)                     b b.a_id = a.id                     update)                           id = p_a_id;        commit;         set = + 1;    until > p_count     end repeat; end $$ delimiter ; 

notice for update used in subquery.
if execute procedure in 2 session @ same time:

call test( 2, 400 ); 

we get, @ once, deadlock error:

------------------------ latest detected deadlock ------------------------ 2013-09-05 23:08:27 1b8c *** (1) transaction: transaction 1388056, active 0 sec starting index read, thread declared inside innodb 5000 mysql tables in use 2, locked 2 lock wait 5 lock struct(s), heap size 1248, 2 row lock(s), undo log entries 1 mysql thread id 6, os thread handle 0x1db0, query id 3107246 localhost 127.0.0.1 test updating update          set  a_field = (                    select sum(b_field)                     b b.a_id = a.id                     update)                           id = p_a_id *** (1) waiting lock granted: record locks space id 222 page no 3 n bits 72 index `primary` of table `test`.`a` trx id 1388056 lock_mode x locks rec not gap waiting record lock, heap no 3 physical record: n_fields 4; compact format; info bits 0  0: len 4; hex 80000002; asc     ;;  1: len 6; hex 000000152e16; asc     . ;;  2: len 7; hex 2d0000013b285a; asc -   ;(z;;  3: len 4; hex 8000001e; asc     ;;  *** (2) transaction: transaction 1388057, active 0 sec starting index read, thread declared inside innodb 5000 mysql tables in use 2, locked 2 5 lock struct(s), heap size 1248, 2 row lock(s), undo log entries 1 mysql thread id 7, os thread handle 0x1b8c, query id 3107247 localhost 127.0.0.1 test updating update          set  a_field = (                    select sum(b_field)                     b b.a_id = a.id                     update)                           id = p_a_id *** (2) holds lock(s): record locks space id 222 page no 3 n bits 72 index `primary` of table `test`.`a` trx id 1388057 lock mode s locks rec not gap record lock, heap no 3 physical record: n_fields 4; compact format; info bits 0  0: len 4; hex 80000002; asc     ;;  1: len 6; hex 000000152e16; asc     . ;;  2: len 7; hex 2d0000013b285a; asc -   ;(z;;  3: len 4; hex 8000001e; asc     ;;  *** (2) waiting lock granted: record locks space id 222 page no 3 n bits 72 index `primary` of table `test`.`a` trx id 1388057 lock_mode x locks rec not gap waiting record lock, heap no 3 physical record: n_fields 4; compact format; info bits 0  0: len 4; hex 80000002; asc     ;;  1: len 6; hex 000000152e16; asc     . ;;  2: len 7; hex 2d0000013b285a; asc -   ;(z;;  3: len 4; hex 8000001e; asc     ;;  *** roll transaction (2) ------------ 

as see, mysql reports deadlock error caused same 2 updates.

however, half of truth.

true reason of deadlock error insert c statement, placed shared lock on referenced record in table (because of foreign key constraint in c table).

, - surprisingly - prevent deadlock, there must placed lock on row in a table @ beginning of transaction:

  declare dummy int;   ......    start transaction;       select id dummy        id = p_a_id update;       insert c( a_id, c_field ) values ( p_a_id, round(rand() * 100) );       update          set  a_field = (                    select sum(b_field)                     b b.a_id = a.id                )                           id = p_a_id;        commit;  

after change procedure runs without deadlocks.

thus, can try add select ... ... update @ beggining of transaction.

but if won't work, further solve problem, please:

  • show whole transaction (all commands invlolved in transaction)
  • show structures of tables used transaction
  • show triggers fired on insert/update/delete modify tables touched transaction

Comments

Popular posts from this blog

Detect support for Shoutcast ICY MP3 without navigator.userAgent in Firefox? -

web - SVG not rendering properly in Firefox -

java - JavaFX 2 slider labelFormatter not being used -