我不习惯使用预定的任务,我需要一些建议(我认为好或坏)
我正在设计一个每20分钟运行一次的功能。此函数从json文件(我无法控制)中检索数据,并将数据插入数据库。
当我这样做时,我不认为这会在数据库视图中创建一个唯一的ID问题,即它是每次更新的相同数据。
我想过做两个功能:
1:第一次插入(INSERT)
2:根据ID(更新)
更新数据@Component
public class LoadSportsCompetition {
@PostConstruct
public void insert() {
// 1 : get json data
// 2 : insert in DB
}
@Scheduled(cron="0 0/20 * * * ?")
public void update() {
// 1 : get json data
// 2 : update rows by ID
}
}
答案 0 :(得分:1)
在PostgreSQL 9.5及更高版本中处理此问题的(最可能)最佳方法是使用INSERT ... ON CONFLICT ... DO UPDATE
。
让我们假设这是你的原始表(非常简单,为了这个例子):
CREATE TABLE tbl
(
tbl_id INTEGER,
payload JSONB,
CONSTRAINT tbl_pk
PRIMARY KEY (tbl_id)
) ;
我们用起始数据填充它:
INSERT INTO tbl
(tbl_id, payload)
VALUES
(1, '{"a":12}'),
(2, '{"a":13, "b": 25}'),
(3, '{"a":15, "b": [12,13,14]}'),
(4, '{"a":12, "c": "something"}'),
(5, '{"a":13, "x": 1234.567}'),
(6, '{"a":12, "x": 1234.789}') ;
现在我们执行一个非冲突的插入(即:ON CONFLICT ...... DO将不会被执行):
-- A normal insert, no conflict
INSERT INTO tbl
(tbl_id, payload)
VALUES
(7, '{"x": 1234.56, "y": 3456.78}')
ON CONFLICT ON CONSTRAINT tbl_pk DO
UPDATE
SET payload = excluded.payload ; -- Note: the excluded pseudo-table comprises the conflicting rows
现在我们执行一个INSERT
会产生PRIMARY KEY
冲突,该冲突将由ON CONFLICT
子句处理并执行更新
-- A conflicting insert
INSERT INTO tbl
(tbl_id, payload)
VALUES
(3, '{"a": 16, "b": "I don''t know"}')
ON CONFLICT ON CONSTRAINT tbl_pk DO
UPDATE
SET payload = excluded.payload ;
现在,两行插入将在一行上发生冲突,并插入另一行:
-- Now one of each
-- A conflicting insert
INSERT INTO tbl
(tbl_id, payload)
VALUES
(4, '{"a": 18, "b": "I will we updated"}'),
(9, '{"a": 17, "b": "I am nuber 9"}')
ON CONFLICT ON CONSTRAINT tbl_pk DO UPDATE
SET payload = excluded.payload ;
我们现在检查表:
SELECT * FROM tbl ORDER BY tbl_id ;
tbl_id | payload -----: | :---------------------------------- 1 | {"a": 12} 2 | {"a": 13, "b": 25} 3 | {"a": 16, "b": "I don't know"} 4 | {"a": 18, "b": "I will we updated"} 5 | {"a": 13, "x": 1234.567} 6 | {"a": 12, "x": 1234.789} 7 | {"x": 1234.56, "y": 3456.78} 9 | {"a": 17, "b": "I am nuber 9"}
您的代码应遍历您的传入数据,获取它,并一次执行所有INSERT/UPDATE
(有时称为MERGE
或UPSERT
)一行,或分批执行多行VALUES
。
您可以在 dbfiddle here
获取所有代码还有一种替代方案,如果您分批工作,则更适合。使用WITH
语句,该语句包含一个UPDATE
子句,后跟INSERT
个句子:
-- Avoiding (most) concurrency issues.
BEGIN TRANSACTION ;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE ;
WITH data_to_load (tbl_id, payload) AS
(
VALUES
(3, '{"a": 16, "b": "I don''t know"}' :: jsonb),
(4, '{"a": 18, "b": "I will we updated"}'),
(7, '{"x": 1234.56, "y": 3456.78}'),
(9, '{"a": 17, "b": "I am nuber 9"}')
),
update_existing AS
(
UPDATE
tbl
SET
payload = data_to_load.payload
FROM
data_to_load
WHERE
tbl.tbl_id = data_to_load.tbl_id
)
-- Insert the non-existing
INSERT INTO
tbl
(tbl_id, payload)
SELECT
tbl_id, payload
FROM
data_to_load
WHERE
data_to_load.tbl_id NOT IN (SELECT tbl_id FROM tbl) ;
COMMIT TRANSACTION ;
您将获得相同的结果,您可以在 dbfiddle here 中看到。
在这两种情况下,都准备好进行错误处理,并准备好重试事务,如果它们因并发操作也会因修改数据库而发生冲突。您的事务可以是显式的(如第二种情况)或隐式,如果您对每个INSERT
进行某种自动提交