在涉及到DataBase的開發的過程,經常遇到如下的場景:
業務邏輯需要向資料庫插入一條新資料,但是需要做如下的判斷:
1. 判斷資料庫裡是否已經存在這樣一條記錄(有特定的判斷依據);
2.1 如果資料庫裡沒有這條記錄,那麼全新建立這條記錄;
2.2 如果資料庫裡已有這條記錄,那麼更新這條記錄;
一般情況下,會想到的處理方式如下:
程式設計程式碼級控制資料的插入和更新:
synchronized void insertNewRecord(Object data){
Object data = “select * from table where clientId = ‘abc’”;
if(data == null) {
// insert into table;
} else {
// update table;
}
這時候考慮到執行緒安全的問題,給整個方法加上了synchronized關鍵字,從而保證整個方法的多個步驟形成一個原子操作。 這時候所帶的問題也顯而易見:
1. 需要透過細心的程式設計來保證這個操作在多執行緒下的正確性;
2. 透過synchronize關鍵字對整個方法進行同步,對系統性能無疑會產生影響;
3. 能資料的操作是透過兩次操作的完成的。
那麼有沒什麼方法可以解決上面的問題,將對資料庫的兩次操作變成一次呢?
在MySql裡可以透過以下兩種SQL語句來完成:
1. INSERT ON DUPLICATE KEY UPDATE
如果您指定了ON DUPLICATE KEY UPDATE,並且插入行後會導致在一個UNIQUE索引或PRIMARY KEY中出現重複值,則執行舊行UPDATE。例如,如果列a被定義為UNIQUE,並且包含值1,則以下兩個語句具有相同的效果:
mysql>INSERT INTO table (a,b,c) VALUES (1,2,3)
->ON DUPLICATE KEY UPDATE c=c+1;
mysql>UPDATE table SET c=c+1 WHERE a=1;
如果行作為新記錄被插入,則受影響行的值為1;如果原有的記錄被更新,則受影響行的值為2。
註釋:如果列b也是唯一列,則INSERT與此UPDATE語句相當:
mysql>UPDATE table SET c=c+1 WHERE a=1 OR b=2 LIMIT 1;
如果a=1 OR b=2與多個行向匹配,則只有一個行被更新。通常,您應該儘量避免對帶有多個唯一關鍵字的表使用ON DUPLICATE KEY子句。
2. REPLACE INTO VALUES
使用REPLACE的最大好處就是可以將DELETE和INSERT合二為一,形成一個原子操作。這樣就可以不必考慮在同時使用DELETE和INSERT時新增事務等複雜操作了。
在使用REPLACE時,表中必須有唯一索引,而且這個索引所在的欄位不能允許空值,否則REPLACE就和INSERT完全一樣的。
在執行REPLACE後,系統返回了所影響的行數,如果返回1,說明在表中並沒有重複的記錄,如果返回2,說明有一條重複記錄,系統自動先呼叫了DELETE刪除這條記錄,然後再記錄用INSERT來插入這條記錄。如果返回的值大於2,那說明有多個唯一索引,有多條記錄被刪除和插入。
REPLACE的語法和INSERT非常的相似,如下面的REPLACE語句是插入或更新一條記錄。
REPLACE INTO users (id,name,age) VALUES(123, "趙本山", 50);
注: REPLACE和INSERT ON DUPLICATE的區別,在於REPLACE會影響多條結果。比如在表中有超過一個的唯一索引。在這種情況下,REPLACE將考慮每一個唯一索引,並對每一個索引對應的重複記錄都刪除,然後插入這條新記錄。假設有一個table1表,有3個欄位a, b, c。它們都有一個唯一索引。
CREATE TABLE table1(a INT NOT NULL UNIQUE,b INT NOT NULL UNIQUE,c INT NOT NULL UNIQUE);
假設table1中已經有了3條記錄
a b c
1 1 1
2 2 2
3 3 3
下面我們使用REPLACE語句向table1中插入一條記錄。
REPLACE INTO table1(a, b, c) VALUES(1,2,3);
返回的結果如下
Query OK, 4 rows affected (0.00 sec)
在table1中的記錄如下
1 2 3
最後: 上述兩種方法都作用在唯一性索引上,如果你判斷重複的列不是唯一性索引,那麼這兩種方法必然是不適用的,那麼這時候還想作為一次操作就必須作用SQL的組合語句了:
INSERT INTO table VALUES (*, * , *, …) WHERE * NOT IN (SELECT * FROM WHERE *=*);
在涉及到DataBase的開發的過程,經常遇到如下的場景:
業務邏輯需要向資料庫插入一條新資料,但是需要做如下的判斷:
1. 判斷資料庫裡是否已經存在這樣一條記錄(有特定的判斷依據);
2.1 如果資料庫裡沒有這條記錄,那麼全新建立這條記錄;
2.2 如果資料庫裡已有這條記錄,那麼更新這條記錄;
一般情況下,會想到的處理方式如下:
程式設計程式碼級控制資料的插入和更新:
synchronized void insertNewRecord(Object data){
Object data = “select * from table where clientId = ‘abc’”;
if(data == null) {
// insert into table;
} else {
// update table;
}
}
這時候考慮到執行緒安全的問題,給整個方法加上了synchronized關鍵字,從而保證整個方法的多個步驟形成一個原子操作。 這時候所帶的問題也顯而易見:
1. 需要透過細心的程式設計來保證這個操作在多執行緒下的正確性;
2. 透過synchronize關鍵字對整個方法進行同步,對系統性能無疑會產生影響;
3. 能資料的操作是透過兩次操作的完成的。
那麼有沒什麼方法可以解決上面的問題,將對資料庫的兩次操作變成一次呢?
在MySql裡可以透過以下兩種SQL語句來完成:
1. INSERT ON DUPLICATE KEY UPDATE
如果您指定了ON DUPLICATE KEY UPDATE,並且插入行後會導致在一個UNIQUE索引或PRIMARY KEY中出現重複值,則執行舊行UPDATE。例如,如果列a被定義為UNIQUE,並且包含值1,則以下兩個語句具有相同的效果:
mysql>INSERT INTO table (a,b,c) VALUES (1,2,3)
->ON DUPLICATE KEY UPDATE c=c+1;
mysql>UPDATE table SET c=c+1 WHERE a=1;
如果行作為新記錄被插入,則受影響行的值為1;如果原有的記錄被更新,則受影響行的值為2。
註釋:如果列b也是唯一列,則INSERT與此UPDATE語句相當:
mysql>UPDATE table SET c=c+1 WHERE a=1 OR b=2 LIMIT 1;
如果a=1 OR b=2與多個行向匹配,則只有一個行被更新。通常,您應該儘量避免對帶有多個唯一關鍵字的表使用ON DUPLICATE KEY子句。
2. REPLACE INTO VALUES
使用REPLACE的最大好處就是可以將DELETE和INSERT合二為一,形成一個原子操作。這樣就可以不必考慮在同時使用DELETE和INSERT時新增事務等複雜操作了。
在使用REPLACE時,表中必須有唯一索引,而且這個索引所在的欄位不能允許空值,否則REPLACE就和INSERT完全一樣的。
在執行REPLACE後,系統返回了所影響的行數,如果返回1,說明在表中並沒有重複的記錄,如果返回2,說明有一條重複記錄,系統自動先呼叫了DELETE刪除這條記錄,然後再記錄用INSERT來插入這條記錄。如果返回的值大於2,那說明有多個唯一索引,有多條記錄被刪除和插入。
REPLACE的語法和INSERT非常的相似,如下面的REPLACE語句是插入或更新一條記錄。
REPLACE INTO users (id,name,age) VALUES(123, "趙本山", 50);
注: REPLACE和INSERT ON DUPLICATE的區別,在於REPLACE會影響多條結果。比如在表中有超過一個的唯一索引。在這種情況下,REPLACE將考慮每一個唯一索引,並對每一個索引對應的重複記錄都刪除,然後插入這條新記錄。假設有一個table1表,有3個欄位a, b, c。它們都有一個唯一索引。
CREATE TABLE table1(a INT NOT NULL UNIQUE,b INT NOT NULL UNIQUE,c INT NOT NULL UNIQUE);
假設table1中已經有了3條記錄
a b c
1 1 1
2 2 2
3 3 3
下面我們使用REPLACE語句向table1中插入一條記錄。
REPLACE INTO table1(a, b, c) VALUES(1,2,3);
返回的結果如下
Query OK, 4 rows affected (0.00 sec)
在table1中的記錄如下
a b c
1 2 3
最後: 上述兩種方法都作用在唯一性索引上,如果你判斷重複的列不是唯一性索引,那麼這兩種方法必然是不適用的,那麼這時候還想作為一次操作就必須作用SQL的組合語句了:
INSERT INTO table VALUES (*, * , *, …) WHERE * NOT IN (SELECT * FROM WHERE *=*);