别问为什么我的格式这么丑,因为这是直男性冷淡风!(好吧,其实是因为我不会弄..小声bb...)
之前一直没怎么管过集群服务,今天刚好碰到自己的服务在多台机器上跑定时任务时产生了重复插入数据的bug,因此查了下并发重复插入数据的资料,自己整理了一下,留个记录
像同一台机,多个线程同时跑这种并发问题这次就不做描述了,使用synchronized、volatile、lock等能满足基本同步需求
本次要记录的是集群部署下,多台机器,同时对数据库做插入操作,如果主键ID是自增长,且可以有固定字段确定数据唯一性的情况下,如何避免产生重复数据。
本来考虑加版本号用乐观锁来控制的,但是会进行表结构更改,为了不影响现有的表结构,我此次使用了一个笨方法,直接从sql语句上控制。说到sql语句控制,可能就会想到使用IF THEN语句,但是考虑到语句复杂度,我使用了最基本的去重查询,废话说了一堆,直接上sql
示例1:
根据worker_id和create_datetime来确定当天的一条记录,通过NOT EXISTS过滤已存在的数据,结果是:如果存在重复数据,过滤后select出来的为空值,不会进行插入。不存在则直接插入,而使用limit 1是因为只需要插入一条记录
INSERT INTO `t_collection_report` (
`worker_id`,
`worker_name`,
`all_count`,
`processed_count`,
`finish_count`
)
SELECT
'591',
'德玛西亚',
'1',
'1',
'3'
FROM
t_collection_report
WHERE
NOT EXISTS (
SELECT
`worker_id`,
`worker_name`,
`all_count`,
`processed_count`,
`finish_count`
FROM
t_collection_report
WHERE
worker_id = '591'
AND SUBSTR(create_time, 1, 10) = substr(now(), 1, 10)
)
LIMIT 1
示例2:
根据group_id和cust_id可以确定记录唯一性,插入传入值
INSERT INTO t_group_cust_ref (
group_id,
cust_id,
overdue_days,
operator,
state
)
SELECT
FROM
t_group_cust_ref
WHERE
NOT EXISTS (
SELECT
group_id,
cust_id,
overdue_days,
operator,
state
FROM
t_group_cust_ref
WHERE
group_id = # and cust_id=#
)
LIMIT 1
示例3:
存在主键ID,但主键ID是自己生成,不想重复插入时报错。使用IGNORE,可以使程序正常运行,但数据库更新数据为0
INSERT IGNORE INTO t_group_cust_ref (id) VALUES (39)
除此之外还有其他更好的方法,这次就先记录这么多,后续碰到了其他问题再继续研究
领取专属 10元无门槛券
私享最新 技术干货