[英]Why does this :id in Rails not work with Postgresql but it does work with MySQL?
[英]Does Postgresql SERIAL work differently?
我有一個帶有SERIAL ID的postgres表。
id (serial) name age
插入通常發生在Web應用程序中。
我手動插入兩條新記錄,將id設置為max(id)+1 ****
在這兩個插入后,當Web應用程序插入2個記錄時,它會出現重復鍵錯誤。
僅2記錄。 之后一切正常。
問題是 - 為什么我的手動插入沒有增加序列?
自動增量和串行是否不同?
我在這里錯過了什么? MySQL或任何其他SQL有同樣的問題嗎?
當你創建一個serial
或bigserial
列時,PostgreSQL實際上做了三件事:
int
或bigint
列。 nextval()
。 當您在不指定serial
列的情況下INSERT一個值時(或者如果您明確指定DEFAULT
作為其值),將在序列上調用nextval
:
如果手動為serial
列提供非默認值,則序列將不會更新, nextval
可以返回serial
列已使用的值。 因此,如果您執行此類操作,則必須通過調用nextval
或setval
來手動修復序列。
另外請記住,可以刪除記錄,因此可以預期serial
列中存在間隙,因此即使沒有並發問題,使用max(id) + 1
也不是一個好主意。
如果您使用serial
或bigserial
,最好的辦法就是讓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.