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

JPAにおいて、`@GeneratedValue`を使って主キーにユニークな値を自動で生成し、`@Id`を持つフィルドに適用できます。この主キーの値を生成するために、以下４種類の方法があります。
・`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列を利用して，主キー値を生成します。

```java
@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 にする必要があります。

```sql
CREATE TABLE users
(
    userid serial NOT NULL,
    username character varying,
    password character varying,
    email character varying,
    CONSTRAINT "PK" PRIMARY KEY (userid)
)
```
MySQLの場合は、カラムの属性にAUTO_INCREMENTを指定する必要があります。

```sql
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`
データベースのシーケンスオブジェクトを使用して，主キー値を生成します。

```java
@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`に指定されているシーケンスオブジェクトが必要です。

```sql
CREATE SEQUENCE userid_seq
    INCREMENT 1
    MINVALUE 1
    MAXVALUE 10000
    START 1
    CACHE 1
    CYCLE;
```
MySQLはシーケンスをサポートしないため、`GenerationType.SEQUENCE`を利用できません。

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

```sql
create sequence "USERID_SEQ"
    start with 1
    increment by 1
    maxvalue 10000
    minvalue 1
    nocache
    cycle
    noorder
```

##`GenerationType.TABLE`
主キー値を保持しておくためのテーブルを使用して，主キー値を生成します。

```java
@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は何れも対応しているし、指定されているテーブルオブジェクトを作成する必要があります。

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

##`GenerationType.AUTO`
データベースごとに異なる方法を選択し，主キー値を生成します。

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