Java
jpa
spring-boot
spring-data-jpa

@GeneratedValueを使って主キーを生成する方法

More than 1 year has passed since last update.

JPAにおいて、@GeneratedValueを使って主キーにユニークな値を自動で生成し、@Idを持つフィルドに適用できます。この主キーの値を生成するために、以下4種類の方法があります。

GenerationType.IDENTITY

GenerationType.SEQUENCE

GenerationType.TABLE

GenerationType.AUTO

DBMS毎にそれらの違いを検証して見ました。


検証環境


  • Spring Boot 1.4.3.RELEASE

  • PostgreSQL 9.3.15

  • MySQL Community Server 5.7.17

  • Oracle Database Express Edition 11g Release 2


GenerationType.IDENTITY

テーブルのidentity列を利用して,主キー値を生成します。

@Entity

@Table(name="users")
public class User implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="userid")
private long userId;

@Column(name="username")
private String userName;

@Column(name="password")
private String password;

@Column(name="email")
private String email;

...
}

PostgreSQLの場合は、関連するテーブルのカラムタイプを SERIAL にする必要があります。

CREATE TABLE users

(
userid serial NOT NULL,
username character varying,
password character varying,
email character varying,
CONSTRAINT "PK" PRIMARY KEY (userid)
)

MySQLの場合は、カラムの属性にAUTO_INCREMENTを指定する必要があります。

Create TABLE users (

userid bigint not null AUTO_INCREMENT PRIMARY KEY,
username varchar(20),
password varchar(20),
email varchar(20)
);

Oracleは、GenerationType.IDENTITYをサポートしていません。


GenerationType.SEQUENCE

データベースのシーケンスオブジェクトを使用して,主キー値を生成します。

@Entity

@Table(name="users")
public class User implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "userid_seq")
@SequenceGenerator(name = "userid_seq", sequenceName = "userid_seq", allocationSize = 1)
@Column(name="userid")
private long userId;

@Column(name="username")
private String userName;

@Column(name="password")
private String password;

@Column(name="email")
private String email;

...
}

PostgreSQLの場合は、sequenceNameに指定されているシーケンスオブジェクトが必要です。

CREATE SEQUENCE userid_seq

INCREMENT 1
MINVALUE 1
MAXVALUE 10000
START 1
CACHE 1
CYCLE;

MySQLはシーケンスをサポートしないため、GenerationType.SEQUENCEを利用できません。

Oracleは、PostgreSQLと同様に指定されているシーケンスオブジェクトが必要です。

create sequence "USERID_SEQ"

start with 1
increment by 1
maxvalue 10000
minvalue 1
nocache
cycle
noorder


GenerationType.TABLE

主キー値を保持しておくためのテーブルを使用して,主キー値を生成します。

@Entity

@Table(name="users")
public class User implements Serializable {

@Id
@TableGenerator( name = "seqTable", table = "seq_table", pkColumnName = "seq_name", pkColumnValue = "user_seq", valueColumnName = "seq_value", initialValue = 1, allocationSize = 1 )
@GeneratedValue(strategy = GenerationType.TABLE, generator="seqTable")
@Column(name="userid")
private long userId;

@Column(name="username")
private String userName;

@Column(name="password")
private String password;

@Column(name="email")
private String email;

...
}

PostgreSQL、MySQLとOracleは何れも対応しているし、指定されているテーブルオブジェクトを作成する必要があります。

--postgresql

CREATE TABLE seq_table
(
seq_name character varying NOT NULL,
seq_value bigint,
CONSTRAINT seq_pk PRIMARY KEY (seq_name)
)


GenerationType.AUTO

データベースごとに異なる方法を選択し,主キー値を生成します。

@Entity

@Table(name="users")
public class User implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="userid")
private long userId;

@Column(name="username")
private String userName;

@Column(name="password")
private String password;

@Column(name="email")
private String email;

...
}

PostgreSQLの場合は、シーケンスオブジェクトhibernate_sequenceを使います。このシーケンスが存在しない場合、org.postgresql.util.PSQLException: ERROR: リレーション"hibernate_sequence"は存在しませんのエラーメッセージが表示されます。

MySQLの場合は、GenerationType.IDENTITYと同じの動きをします。カラムの属性にAUTO_INCREMENTが指定されていない場合にjava.sql.SQLException: Field 'userid' doesn't have a default valueのエラーメッセージが表示されます。

Oracleの場合は、PostgreSQLと同じく、シーケンスオブジェクトhibernate_sequenceが使用されます。