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が使用されます。