需求背景
在《调用ZABBIX的API获取节点主机信息小记》(传送门:)这篇博客中,简单阐述了如何利用zabbix-api库来获取ZABBIX监控各节点主机的信息。需要将获取的信息录入数据库,由于节点数目不断增加,因此插入数据库时,要判断节点主机是否存在,存在则更新各主机信息,不存在则插入。
实现方案
首先需要建立一张表node_status:
+--------------+--------------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+--------------+--------------+------+-----+---------+-------+| node_name | varchar(100) | NO | PRI | NULL | || ip | varchar(100) | NO | | NULL | || site | varchar(100) | NO | | NULL | || frp_num | int(11) | NO | | NULL | || home_free | bigint(20) | NO | | NULL | || mem_use | varchar(100) | NO | | NULL | || last_time | datetime | NO | | NULL | || modify_time | datetime | NO | | NULL | |+--------------+--------------+------+-----+---------+-------+
该表中,将node_name即节点主机名称设为PRIMARY KEY。
一开始只是想到了用 if-else语句,判断node_name是否存在,存在则更新,不存在则插入。
if not exists (select node_name from node_status where node_name = target_name) insert into node_status(node_name,ip,...) values('target_name','ip',...)else update node_status set ip = 'ip',site = 'site',... where node_name = target_name
但是这么写出来,出现了两个问题:
1、效率太差,每次都需要执行两条SQL语句,一条语句用来判断node_name是否在表中已经存在,另一条语句用来插入或更新表中数据。2、高并发的情况下数据会出问题,不能保证原子性。那么有没有更优雅高效的方法呢,通过查阅资料,发现MySQL一条语句很好的解决了这个问题:ON DUPLICATE KEY UPDATE
该语句的语法如下:INSERT INTO tablename(field1,field2, field3, ...) VALUES(value1, value2, value3, ...) ON DUPLICATE KEY UPDATE field1=value1,field2=value2, field3=value3, ...;
这个语法的目的是为了解决重复性,当数据库中存在某个记录时,执行这条语句会更新它,而不存在这条记录时,会插入它。
该语句规则如下:如果你插入的记录导致一个UNIQUE索引或者primary key(主键)出现重复,那么就会认为该条记录存在,则执行update语句而不是insert语句,反之,则执行insert语句而不是更新语句。得到了这个插入语句的”八倍镜“,我们可以将原来那个很LOW的方式替换掉了:sql = """ INSERT INTO node_status(node_name,ip,site,frp_num, \+ home_free,mem_use,last_time,modify_time) \+ VALUES('%s','%s','%s','%d','%d','%s','%s','%s') \+ ON DUPLICATE KEY UPDATE \+ ip='%s', site='%s',frp_num='%d',home_free='%d', \+ mem_use='%s',last_time='%s',modify_time='%s' """ % \+ (id_value['host'], ip, site, frp_num, home_size, mem_use, last_time, modify_time),+ (ip, site, frp_num, home_size, mem_use, last_time, modify_time)
参考资料
1、
2、