MySQL中ON_DUPLICATE_KEY_UPDATE的用法实践

前言

最近在平台推送业务的特性开发中,使用到了MySQL的"ON DUPLICATE KEY UPDATE"语法,这里结合业务场景对该语法的使用做个介绍。

业务场景

使用平台的推送服务之前,需要注册设备。对于终端的注册信息,主要有玩家的user_id、对应于某渠道的客户端包名bundle_id、以及其它相关信息,例如当前设备的推送类型(FCM、APNS、Baidu等)、设备的device_token、依托于AWS推送服务的Amazon 资源名称 (ARN)、 该终端设备对应玩家的默认语言、所在国家或地区等信息。

不同游戏终端设备的注册逻辑大同小异,基本都是在玩家每次上线时由游戏服务器向平台的推送服务发起注册请求。如果当前终端设备之前注册过,则只是更新该终端设备的其它注册信息(例如推送渠道更改、设备device_token变更、默认语言、国家地区信息的变更等);假若当前终端设备未注册过时,就写入一条新的记录。

对于iOS、应用宝以外的渠道下载的客户端(以bundle_id作区分),原则上玩家账号(user_id)是可以互通的。也就是说,某个游戏中同一个user_id可以对应多个bundle_id,一条终端设备的注册记录以自增id作为PRIMARY KEY,同时以(user_id, bundle_id)作为UNIQUE KEY,一组(user_id, bundle_id)可以唯一标识一条注册记录。

描述到这里就清楚了,当前业务可以抽象描述为:

1.对于每条终端设备的注册信息,通过user_id和bundle_id确定其唯一性;

2.对于已注册的终端设备,每次重新注册时可能会更新其它字段(update);

3.对于未注册的终端设备,则在注册时新写入一条注册信息(insert)。

用法实践

不太好的处理方法

对于上文所述的业务场景,如果想要插入或更新一条注册信息,使用功能单一的SQL语句,需要怎么做呢?

1.执行SELECT语句,条件为user_id & bundle_id,确认待插入的记录是否已存在;

2.若记录已存在,则执行UPDATE语句更新相应记录其它字段值,条件依然为user_id & bundle_id;

3.若记录不存在,则执行INSERT语句,插入一条新记录。

可见前后需要执行三条SQL语句才能完成一个功能,而且为确保业务逻辑的前后一致,可能还需要将此三条SQL组合成一个事务,确保中间操作出现异常可以回滚到最初状态,不会造成脏数据等问题。比较繁琐。

使用ON DUPLICATE KEY UPDATE

鉴于此,我们采用以下sql语句进行设备注册时新设备注册信息的写入,或已有设备的信息更新:

INSERT INTO `table_name`(`section1`,`section2`,`section3`)VALUES(`value1`,`value2`,`value3`) ON DUPLICATE KEY UPDATE `section3`=`value3`

具体含义就是:

1.当字段section1、section2、section3对应的值value1、value2、value3不存在时,便插入一条新记录,其中字段section1、section2、section3对应的值分别为value1、value2、value3,如果表中有其它未显式指定的字段,则使用默认值;

2.当字段section1、section2、section3中包含PRIMARY KEY或UNIQUE KEY时,跳转至UPDATE部分,执行部分字段的更新操作。

相比之前的SELECT + UPDATE/INSERT方案,简单明了。

补充说明

1.该用法对mysql表的影响行数计算:

如果是作为一条新记录写入表中,则影响的行数为1;

如果是对原有记录的更新操作,则受影响的行数为2(update操作完成后,主键id也会自增1);

2.与PRIMARY KEY或UNIQUE KEY的关系:

如果该条INSERT语句插入表中会导致当前PRIMRAY KEY或某个已存在的UNIQUE KEY出现重复值,那么就执行后半段的UPDATE语句,更新被命中记录的部分字段值;

3.写法的简化:

若当前被插入的记录共有5个字段,其中section1和section2组成了表的联合索引,则SQL语句时传统写法是:

INSERT INTO `table_name`(`section1`,`section2`,`section3`,`section4`,`section5`)VALUES('?','?','?','?','?') ON DUPLICATE KEY UPDATE `section3`='?',`section4`='?',`section5`='?';

本文所遇的真实业务场景,需要插入的字段不止5个,而是20+,可想而知以现在的方式写出来的sql语句,光变量需要填40个,有重复不说,还可能把变量顺序填返,造成数据错误,又不好修复。

相对精简的写法,省去了后面update部分重复手写的变量,使得传入的参数数量少了一半,代码可读性提高,变量填错位的可能性也会大大降低:

INSERT INTO `table_name`(`section1`,`section2`,`section3`,`section4`,`section5`)VALUES('?','?','?','?','?') ON DUPLICATE KEY UPDATE `section3`=VALUES(`section3`),`section4`=VALUES(`section4`),`section5`=VALUES(`section5`);

更进一步,对于一次性需要插入或更新多条记录的场景,该UPDATE部分的精简写法可以动态传入要修改的值给对应某行,这样就可以满足需要给不同的记录插入不同的值的情况,例如:

INSERT INTO `table_name`(`section1`,`section2`,`section3`,`section4`,`section5`)VALUES('?','?','?','?','?'),('?','?','?','?','?') ON DUPLICATE KEY UPDATE `section3`=VALUES(`section3`),`section4`=VALUES(`section4`),`section5`=VALUES(`section5`);
4.特殊之处

该语法是MySQL特有的语法,不是SQL的标准语法🙂

小结

使用前需要根据实际业务场景评估是否使用该语法,并且确认目标表的字段、主键、联合索引等符合(或改造后符合)该语法的使用场景。

总体感觉该语法挺好用的,其它没了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,340评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,762评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,329评论 0 329
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,678评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,583评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,995评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,493评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,145评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,293评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,250评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,267评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,973评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,556评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,648评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,873评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,257评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,809评论 2 339

推荐阅读更多精彩内容

  • ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常。 O...
    我想起个好名字阅读 5,067评论 0 9
  • 一、MySQL优化 MySQL优化从哪些方面入手: (1)存储层(数据) 构建良好的数据结构。可以大大的提升我们S...
    宠辱不惊丶岁月静好阅读 2,402评论 1 8
  • ORACLE自学教程 --create tabletestone ( id number, --序号usernam...
    落叶寂聊阅读 1,058评论 0 0
  • width: 65%;border: 1px solid #ddd;outline: 1300px solid #...
    邵胜奥阅读 4,752评论 0 1
  • 雪又开始下了,早上下地铁的时候有雪粒子飘在空中。开完会回头看窗外意外看到久违的阳光。今天因为要协调一个紧急的问题把...
    壹诺思维阅读 383评论 6 4