1. 程式人生 > >一種實現mysql裡自增序列的方法

一種實現mysql裡自增序列的方法

最近工作中遇到一個需求,需要設計一個自增欄位,當每插入一條記錄的時候,該欄位加1,但是由於種種原因,該欄位無法作為primary key存在,這樣就需要該欄位實現為一個自增序列。

mysql中的auto_increment可以實現自增長,其起始值是可以指定的,步長固定就是1,但是一張表裡只有一個欄位可以設定為auto_increment,我們的表中已經存在主鍵欄位,其它欄位就不能再指定為auto_increment。

還有一種方式是在mysql中使用儲存過程或者function模擬自增序列,但是加入儲存過程無故增添了資料庫維護的成本,也不利於將來專案交接,所以合適的方式還是在業務程式碼中實現上述需求。

首先我們想到下面的思路,建立另外一張表,該表只有一個主鍵自增欄位:

create table mysequence (
    `id` bigint not null auto_increment,
    PRIMARY KEY (`id`)
)

然後在業務程式碼中,每需要一個自增的序列值時,就向上述表中插入一條記錄,並將插入記錄的id值返回,用SQL實現就是下面兩句:
insert mysequence values( NULL );
select LAST_INSERT_ID();

其中的LAST_INSERT_ID是mysql自帶的function,用於向表中insert一條記錄後,來返回最近insert的那行記錄的自增欄位值。

關於LAST_INSERT_ID總結了一下需要注意的地方:

1、當使用單條insert語句插入多條記錄時, LAST_INSERT_ID只返回插入的第一條記錄產生的值。

2、LAST_INSERT_ID是基於連線的,也就是說它返回的值是這條連線在最近一次insert操作執行後的自增值,該值是不會被其它連線的sql語句所影響,也就是說它不需要通過加鎖或者事務機制來保證其在多連線場景下的正確性。

但是這裡有一個潛在的坑,就是LAST_INSERT_ID()返回的是最後一個寫入資料庫的id,但是在單連線多個數據表都有寫入的情況下,這個語句返回的很有可能是另外一張表寫入的id,這時返回的id就有可能是錯誤的。

所以更優雅一些的解決方法還是不建議使用LAST_INSERT_ID,返回來思考需求,我們就是想獲得本次insert後主鍵自增長之後的值,mybatis中有一個usegeneratedkeys屬性,將

該屬性設定為true之後,mybatis執行完插入語句後,會自動將自增長的值賦給輸入引數,我們還以上面的表為例講解如何實現。

<insert id="insert" parameterType="mysequence"   
        useGeneratedKeys="true" keyProperty="id">  
        insert into my sequence(id)values (#{id})
</insert>
插入前實體id的屬性值為0,插入後實體id為儲存後自增的id,可以通過輸入物件的getter方法獲取id自增後的值。
@RequestMapping(value="/insert")
@ResponseBody
public JsonReture insert(Mysequence mysequence){
  mySequenceService.insert(mysequence);
  System.out.println("主鍵id為:" + mysequence.getId());
}