2017-07-16 72 views
1

我不習慣與計劃任務的工作,我需要一些建議(是我的思想好壞管理INSERT,UPDATE,計劃任務

我設計的是每20分鐘發車的功能。這個函數從json文件(我沒有控制權)中檢索數據並將數據插入到數據庫中。

當我這樣做時,我不認爲這會在數據庫視圖中創建唯一的ID問題,即每次都更新相同的數據。

我想這樣做兩個功能:

1:第一插入(INSERT)

2:根據ID(UPDATE)更新數據

@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

什麼是您的實際* *的問題? – joanolo

+0

我只是徘徊,如果這是一種好或壞的方式 –

+0

您使用的是哪個版本的PostgreSQL?如果使用更新的(9.5+)版本,您可能希望使用'INSERT ... ON CONFLICT DO UPDATE ...;'並且只需一步即可完成所有操作。請參閱['INSERT'](https://www.postgresql.org/docs/current/static/sql-insert.html) – joanolo

回答

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 

現在我們執行o NE 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"}  

您的代碼應循環處理您的傳入數據,並獲取它,並使用多行VALUES一次一行或分批執行所有INSERT/UPDATE(有時稱爲MERGEUPSERT)。

你可以在所有的代碼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

+1

非常好的解釋,我做了一個簡單的伎倆插​​入只有一次和更新後。稍後我可能會整合您的解決方案 –