需求
每小时统计一遍所有用户的某几项数据,一天当中此用户只有一条记录。对于有数据的用户保存数据库,否则放弃。
数据库 mysql
事务隔离级别 rr
表结构大体如下:
CREATE TABLE `user` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`time_key` int(11) NOT NULL,
`doctor_id` varchar(50) COLLATE utf8mb4_bin NOT NULL,
`ask_count` int(11) NOT NULL DEFAULT '0',
`cancel_count` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `uix_user_time_key_doctor_id` (`time_key`,`doctor_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
唯一索引 time_key+doctor_id
实现方式
1.对于所有的用户分页查询
2.通过CompletableFuture异步查询用户各项数据
CompletableFuture<DataTransferObject<Map<String,Integer>>> askFuture = CompletableFuture.supplyAsync(() -> askService.getAskCount(askStatisDto));
CompletableFuture<DataTransferObject<Map<String,Integer>>> cancelFuture = CompletableFuture.supplyAsync(() -> askService.getCancelCount(askStatisDto));
3.之后整合数据,异步保存
CompletableFuture.allOf(askFuture ,cancelFuture).whenCompleteAsync((aVoid, throwable) -> {
//存库
}
4.数据库保存语句用的是 replace into 表名
问题
死锁
问题复现
1.执行第一条语句
BEGIN;
REPLACE INTO user (time_key,doctor_id,ask_count,cancel_count) values(20190523,'333',1,1);
2.执行第二条语句
BEGIN;
REPLACE INTO user (time_key,doctor_id,ask_count,cancel_count) values(20190523,'999',6,6)
3.出现死锁,命令查看
这里死锁是因为从(-∞,插入数据]直接加了间隙锁
详见:https://www.dazhuanlan.com/2019/10/21/5dadd2ac43e9c/ 下一个键锁(Next-Key Locks)
所以现在的问题找到了。最终的解决办法是改成了同步。
网友评论