建立一张表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 语句,判断主键是否存在,存在则更新,不存在则插入。
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, ...) ONDUPLICATE 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)