[Grails]关于PostgreSQL的序列说明
请参考以下链接:
http://stackoverflow.com/questions/2822623/how-to-set-up-an-insert-to-a-grails-created-file-with-next-sequence-number
如果在Grails中使用PostgreSQL,根据默认情况下不会使用PostgreSQL的sequence。通过按照下面的方式,在每个域中定义自己的sequence可以实现使用。
package hoge
class Test{
String word
static constraints = {
}
static mapping = {
id generator:'sequence', params: [sequence:'test_id_seq']
}
}
然而,这种方式实际上存在陷阱,当Grails处于CreateDrop模式时,它会自动创建包括上述序列在内的所有表,但是表的id属性没有指定为该序列的nextval。
因此,如果在原始的SQL中省略id,那么id不能为null!这是理所当然的错误。
在Grails中根据以下条件自动生成的表定义是:
-- こっちがテーブル
mydb=# \d test
Tabelle public.test
Spalte | Typ | Attribute
---------+------------------------+-----------
id | bigint | not null
version | bigint | not null
word | character varying(255) | not null
Indexe:
"test_pkey" PRIMARY KEY, btree (id)
-- こっちがsequence
mydb=# \d test_id_seq
Sequenz public.test_id_seq
Spalte | Typ | Wert
---------------+---------+---------------------------
sequence_name | name | test_id_seq
last_value | bigint | 4
start_value | bigint | 1
increment_by | bigint | 1
max_value | bigint | 9223372036854775807
min_value | bigint | 1
cache_value | bigint | 1
log_cnt | bigint | 32
is_cycled | boolean | f
is_called | boolean | t
由于未对id的Attribute指定nextval,因此以下的SQL将报错。
INSERT INTO test (version,word) VALUES(1, 'aaa')
Grails自身知道在域中指定的sequence信息,因此可以使用生成的sequence。然而,PostgreSQL本身无法自动使用sequence,因为如上面的表定义所示,test表的id对应的sequence信息没有任何地方写明,所以在INSERT时如果省略id,无法自动使用sequence。
需要原本的表定义如下。如果省略 id ,PostgreSQL 将自动使用 nextval 指定的序列。
Tabelle public.test2
Spalte | Typ | Attribute
--------+---------+--------------------------------------------------------
id | integer | not null Vorgabewert nextval('test2_id_seq'::regclass)
name | text |
使用Grails提供的功能来使用数据库,无论是使用sequence还是其他方法,并没有什么特别问题。
问题出现在当自己编写并执行SQL的INSERT语句时。
作为对策,有以下2点:
1. 手动生成所有的表和序列,或者后续添加nextval。
2. 在直接执行SQL时,要确保正确指定id。
第二种情况会变成以下的样子。
def query = "INSERT INTO test (id,version,word) VALUES(nextval('test_id_seq'),?,?)"
sql.executeInsert(query, [1,"test-data-a"])
顺便说一下,在这项服务中,可以直接执行SQL并顺利进行回滚操作。