[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并顺利进行回滚操作。

广告
将在 10 秒后关闭
bannerAds