簡體   English   中英

Postgresql SERIAL的工作方式不同嗎?

[英]Does Postgresql SERIAL work differently?

我有一個帶有SERIAL ID的postgres表。

id (serial) name age

插入通常發生在Web應用程序中。

我手動插入兩條新記錄,將id設置為max(id)+1 ****

在這兩個插入后,當Web應用程序插入2個記錄時,它會出現重復鍵錯誤。

僅2記錄。 之后一切正常。

問題是 - 為什么我的手動插入沒有增加序列?

自動增量和串行是否不同?

我在這里錯過了什么? MySQL或任何其他SQL有同樣的問題嗎?

當你創建一個serialbigserial列時,PostgreSQL實際上做了三件事:

  1. 創建intbigint列。
  2. 創建一個序列(由列擁有)以生成列的值。
  3. 將列的默認值設置為序列的nextval()

當您在不指定serial列的情況下INSERT一個值時(或者如果您明確指定DEFAULT作為其值),將在序列上調用nextval

  1. 返回列的下一個可用值。
  2. 增加序列的值。

如果手動為serial列提供非默認值,則序列將不會更新, nextval可以返回serial列已使用的值。 因此,如果您執行此類操作,則必須通過調用nextvalsetval來手動修復序列。

另外請記住,可以刪除記錄,因此可以預期serial列中存在間隙,因此即使沒有並發問題,使用max(id) + 1也不是一個好主意。

如果您使用serialbigserial ,最好的辦法就是讓PostgreSQL的需要為你分配價值的關懷,假裝他們是不透明的數字,只是發生在一定的順序出來:不要自行將它們分配和除了唯一性之外,不要假設任何關於它們的事情。 此經驗法則適用於所有數據庫IMO。


我不確定MySQL的auto_increment如何與所有不同的數據庫類型一起工作,但也許精細的手冊會有所幫助。

如果要將記錄插入帶有serial列的表中 - 只需從查詢中省略它 - 它將自動生成。

或者您可以使用以下內容插入其默認值:

insert into your_table(id, val)
values (default, '123');

第三種選擇是直接從串行序列中獲取值:

insert into your_table(id, val)
values (nextval(pg_get_serial_sequence('your_table','id')), '123');

我手動插入兩條新記錄,將id設置為max(id)+ 1 * *

這種方法完全錯誤,不適用於任何數據庫。 到目前為止,它只對你有用,純粹是運氣。

如果兩個連接同時運行,它們將獲得相同的ID。 只有在針對並發讀取鎖定表時,它才能可靠地工作,以便一次只能有一個連接獲取ID。

它也非常低效。

這就是存在序列的原因,因此您可以在存在並發插入器的情況下可靠地獲取ID。

只需使用:

INSERT INTO my_table(data1, data2) VALUES ('a','b') RETURNING id;

要么:

INSERT INTO my_table(id, data1, data2) VALUES (DEFAULT, 'a','b') RETURNING id;

DEFAULT是一個特殊的占位符,它告訴數據庫從表定義中獲取該列的默認值。 默認值為nextval('my_table_id_seq') ,因此將插入下一個序列值。

既然您在詢問有關序列的基本問題,我建議您也考慮序列不是無間隙的 序列具有“洞”是正常的,其中表值為1,3,4,5,9,10,....

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM