使用外键

时间:2017-12-04 04:52:49

标签: mysql foreign-keys innodb deadlock

DDL(删除了一些不相关的列信息)

Table: config_version
Create Table: CREATE TABLE `config_version` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `config_id` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_config_version_config_1` (`config_id`),
  CONSTRAINT `fk_config_version_config_1` FOREIGN KEY (`config_id`) REFERENCES `config` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=85532 DEFAULT CHARSET=utf8 COLLATE=utf8_bin ROW_FORMAT=COMPACT

Table: config
Create Table: CREATE TABLE `config` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_config_name_namespace_id` (`name`,`namespace_id`),
  KEY `fk_config_namespace_1` (`namespace_id`),
  CONSTRAINT `fk_config_namespace_1` FOREIGN KEY (`namespace_id`) REFERENCES `namespace` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1901 DEFAULT CHARSET=utf8 COLLATE=utf8_bin ROW_FORMAT=COMPACT

显示引擎innodb状态;

*** (1) TRANSACTION:

TRANSACTION 125411, ACTIVE 0 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 5 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 7, OS thread handle 123145570861056, query id 4898 localhost 127.0.0.1 root updating
update config set name = 'bts_driver_list_filter_gray_onceagain_list_filter_tw_control_group', description = '?????????????', namespace_id = 4, current_version = 89950, create_time = '2017-11-14 15:54:45', created_by = 'chenchongyu' where id = 982
2017-12-01T04:12:43.711301Z 6 [Note] InnoDB: *** (1) WAITING FOR THIS LOCK TO BE GRANTED:

RECORD LOCKS space id 672 page no 11 n bits 216 index PRIMARY of table `apollo_config_dev`.`config` trx id 125411 lock_mode X locks rec but not gap waiting
Record lock, heap no 97 PHYSICAL RECORD: n_fields 10; compact format; info bits 0
 0: len 8; hex 80000000000003d6; asc         ;;
 1: len 6; hex 00000001e9da; asc       ;;
 2: len 7; hex 24000001830584; asc $      ;;
 3: len 30; hex 6274735f6472697665725f6c6973745f66696c7465725f677261795f6f6e; asc bts_driver_list_filter_gray_on; (total 66 bytes);
 4: len 13; hex 3f3f3f3f3f3f3f3f3f3f3f3f3f; asc ?????????????;;
 5: len 11; hex 6368656e63686f6e677975; asc chenchongyu;;
 6: len 8; hex 8000000000000004; asc         ;;
 7: len 8; hex 8000000000015f56; asc       _V;;
 8: len 5; hex 999e1cfdad; asc      ;;
 9: len 1; hex 01; asc  ;;

2017-12-01T04:12:43.712251Z 6 [Note] InnoDB: *** (2) TRANSACTION:

TRANSACTION 125408, ACTIVE 0 sec starting index read
mysql tables in use 1, locked 1
5 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 6, OS thread handle 123145570582528, query id 4904 localhost 127.0.0.1 root updating
update config set name = 'bts_driver_list_filter_gray_onceagain_list_filter_tw_control_group', description = '?????????????', namespace_id = 4, current_version = 89947, create_time = '2017-11-14 15:54:45', created_by = 'chenchongyu' where id = 982
2017-12-01T04:12:43.712308Z 6 [Note] InnoDB: *** (2) HOLDS THE LOCK(S):

RECORD LOCKS space id 672 page no 11 n bits 216 index PRIMARY of table `apollo_config_dev`.`config` trx id 125408 lock mode S locks rec but not gap
Record lock, heap no 97 PHYSICAL RECORD: n_fields 10; compact format; info bits 0
 0: len 8; hex 80000000000003d6; asc         ;;
 1: len 6; hex 00000001e9da; asc       ;;
 2: len 7; hex 24000001830584; asc $      ;;
 3: len 30; hex 6274735f6472697665725f6c6973745f66696c7465725f677261795f6f6e; asc bts_driver_list_filter_gray_on; (total 66 bytes);
 4: len 13; hex 3f3f3f3f3f3f3f3f3f3f3f3f3f; asc ?????????????;;
 5: len 11; hex 6368656e63686f6e677975; asc chenchongyu;;
 6: len 8; hex 8000000000000004; asc         ;;
 7: len 8; hex 8000000000015f56; asc       _V;;
 8: len 5; hex 999e1cfdad; asc      ;;
 9: len 1; hex 01; asc  ;;

2017-12-01T04:12:43.713122Z 6 [Note] InnoDB: *** (2) WAITING FOR THIS LOCK TO BE GRANTED:

RECORD LOCKS space id 672 page no 11 n bits 216 index PRIMARY of table `apollo_config_dev`.`config` trx id 125408 lock_mode X locks rec but not gap waiting
Record lock, heap no 97 PHYSICAL RECORD: n_fields 10; compact format; info bits 0
 0: len 8; hex 80000000000003d6; asc         ;;
 1: len 6; hex 00000001e9da; asc       ;;
 2: len 7; hex 24000001830584; asc $      ;;
 3: len 30; hex 6274735f6472697665725f6c6973745f66696c7465725f677261795f6f6e; asc bts_driver_list_filter_gray_on; (total 66 bytes);
 4: len 13; hex 3f3f3f3f3f3f3f3f3f3f3f3f3f; asc ?????????????;;
 5: len 11; hex 6368656e63686f6e677975; asc chenchongyu;;
 6: len 8; hex 8000000000000004; asc         ;;
 7: len 8; hex 8000000000015f56; asc       _V;;
 8: len 5; hex 999e1cfdad; asc      ;;
 9: len 1; hex 01; asc  ;;

2017-12-01T04:12:43.714133Z 6 [Note] InnoDB: *** WE ROLL BACK TRANSACTION (2)

简化业务流程代码(代码)

@Transaction
public void service(){
    Config config = configMapper.selectByPrimaryKey(configId)
    ConfigVersion configVersion = toConfigVersion(config, configDTO)
    configVersionMapper.insert(configVersion)
    config.setCurrentVersion(configVersion.id)
    config.setDescription(configDTO.description)
    configMapper.updateByPrimaryKey(config)

    wait for service C http response
}

代码的SQL

insert into config_version (config_id, name, create_time, namespace_id, type, status,base_version_id, value, created_by, enable_from, description)
        values 
        ( #{configId,jdbcType=BIGINT}, 
        #{name,jdbcType=VARCHAR}, now(), 
        #{namespaceId,jdbcType=BIGINT}, #{type,jdbcType=TINYINT}, 
        #{status,jdbcType=TINYINT},
        #{baseVersionId,jdbcType=BIGINT}, #{value,jdbcType=LONGVARCHAR}, #{createdBy,jdbcType=VARCHAR}, 
        #{enableFrom,jdbcType=TIMESTAMP},#{description,jdbcType=VARCHAR})

    update config set 
    name = #{name,jdbcType=VARCHAR}, 
    description = #{description,jdbcType=VARCHAR},
    namespace_id = #{namespaceId,jdbcType=BIGINT},
    current_version = #{currentVersion,jdbcType=BIGINT},
    create_time = #{createTime,jdbcType=TIMESTAMP},
    created_by = #{createdBy,jdbcType=VARCHAR}
    where id = #{id,jdbcType=BIGINT}

业务场景(服务调用订单)

服务A调用服务B更新配置版,服务B将更新内容持久化到mysql以后会调用服务C,等待服务C返回以后,服务B再返回给服务A 如果服务A一定时间内没有接受到服务B返回,那么服务A会重试,重新向服务A发起一个请求
(服务A - > A,服务B - > B,服务C - > C;   一个调用B,更新config_version,B持久化为mysql,然后调用C,C返回后,B返回A.   如果B没有返回,A将重试; )

解决办法(溶液)

去掉config_version 对config的外键依赖(remove the foreign key)

CONSTRAINT `fk_config_version_config_1` FOREIGN KEY (`config_id`) REFERENCES `config` (`id`)

问题

但是没明白mysql insert和update时需要获取什么锁,所以没明白这里产生死锁的原因。 (发生死锁的原因是,哪种锁进入tx)

软件版本信息(mysql info)

sql mysql 版本信息 mysql: stable 5.7.20

0 个答案:

没有答案