(spring data jpa)식별자(@id, primary key) 자동 생성, @generatedvalue의 strategy...
Embed Size (px)
TRANSCRIPT

JPA 식별자 자동 생성(@GeneratedValue)
JPA 식별자 자동 생성(@GeneratedValue)
식별자 자동생성은 @GeneratedValue 어노테이션으로 지정한다.
복합키 보다는 대행키(인공키, Artifitial Key) 사용을 권장한다.
@GeneratedValue의 strategy 속성에 값을 지정해 여러 가지 식별자 자동 생
성 전략을 선택할 수 있는데 AUTO, TABLE, SEQUENCE, IDENTITY 값으로 지정
한다. 이 값들은 열거형인 GenerationType에 정의되어 있다.
GenerationType.AUTO : 데이터베이스에 관계없이 식별자를 자동 생성 하라
는 의미, DB가 변경되더라도 수정할 필요 없다.

자동 선택
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="USER_ID")
protected Long userId;
JPA 공급자에 따라 기본설정이 다름
Oracle을 사용할 경우 SEQUENCE가 기본
MS SQL Server의 경우 IDENTITY가 기본
위 예문의 경우 오라클이라면 하이버네이트 글로벌 시퀀스(hibernate_sequence)를
사용하므로 엔티티에서 두 군데 이상 AUTO로 사용한다면 시퀀스를 별도로 만들
고 명시적으로 SequenceGenerator를 기술하여 사용하는 것이 좋다.
GenerationType.TABLE : 가장 유연하고 이식성이 좋은 방법으로 키를 위한
테이블이 생성되어 있어야 하며, ID 생성 테이블은 두 개의 칼럼을 반드시 가
져야 한다. 처음 컬럼은 특정 시퀀스를 식별하는데 사용되는 문자열 타입이고
모든 Generator를 위한 위한 주키다. 두 번째 칼럼은 생성되고 있는 실제 ID
값인 시퀀스를 저장하는 숫자 타입으로 이 칼럼에 저장되는 값은 시퀀스에 할
당되었던 마지막 값이 된다. 하나의 테이블에 여러 식별자 값을 저장할 수 있
으며 오라클의 경우 아래처럼 사용하면 된다.
1. 식별자용 테이블 생성(JPA에서 자동생성)
CREATE TABLE SEQ_TABLE
(SEQ_NAME VARCHAR2(100) NOT NULL PRIMARY KEY,
SEQ_VALUE NUMBER NOT NULL);
2. 식별자 테이블 초기화(JPA에서 자동생성)
INSERT INTO SEQ_TABLE VALUES ('USER_SEQ', 1);
3. TableGenerator 생성, @GeneratedValue 사용
@TableGenerator (name="MY_GENERATOR", table="SEQ_TABLE",

pkColumnName="SEQ_NAME",
valueColumnName="SEQ_VALUE", pkColumnValue="USER_SEQ")
@Entity
public class User {
@GeneratedValue(strategy=GenerationType.TABLE, generator="MY_GENERATOR")
@Column(name="USER_ID")
@Id
protected Long userId;
GenerationType.SEQUENCE : DB에서 생성해 놓은 시퀀스를 이용하는 방법으
로 오라클, DB2, PostgreSQL, H2 데이터베이스 등에서 사용한다.
1. 오라클 DB에 시퀀스 생성
CREATE SEQUENCE USER_SEQ;
2. 엔티티에 SequenceGenerator, @GeneratedValue 지정
@SequenceGenerator(name="USER_SEQ_GENERATOR",
sequenceName="USER_SEQ")§
@Id
@Entity
public class User {
@GeneratedValue(strategy=GenerationType.SEQUENCE,
generator="USER_SEQ_GENERATOR")
@Column(name="USER_ID")
protected Long userId;
GeneratedType.IDENTITY : MySQL, MS-SQL 처럼 DB 자체적으로 식별자 칼럼
에 자동증분 속성이 있는 경우에 사용한다. 엔티티의 주키 컬럼을 위한 정의
는 DB 스키마 정의의 일부분으로 정의되어야 한다.
[GenerationType.TABLE, 오라클 예제]
STS에서 File -> New -> Spring Stater Project 프로젝트 이름 : GeneratedValueTest

다음화면에서 SQL : JPA, Web : Web 선택
1. pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>GeneratedValueTest</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>

<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- JSP, JSTL 사용위해 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<!-- DriverSpy -->
<dependency>
<groupId>org.bgee.log4jdbc-log4j2</groupId>
<artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
<version>1.16</version>
</dependency>
<!-- for oracle -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>

<version>11.1.0.7.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>oracle</id>
<name>ORACLE JDBC Repository</name>
<url>https://maven.oracle.com</url>
</repository>
</repositories>
</project>
2. application.properties
spring.datasource.platform=oracle
spring.datasource.sql-script-encoding=UTF-8
spring.datasource.url=jdbc:log4jdbc:oracle:thin:@localhost:1521:onj
spring.datasource.username=test
spring.datasource.password=test
#spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.driver-class-name = net.sf.log4jdbc.sql.jdbcapi.DriverSpy
spring.jpa.show-sql=true

spring.jpa.hibernate.ddl-auto=create
#hibernate config
spring.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect
logging.level.jpa=DEBUG
#view
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
3. log4jdbc.log4j2.properties
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
log4jdbc.dump.sql.maxlinelength=0
4. logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyyMMdd HH:mm:ss.SSS} [%thread] %-3level %logger{5} -
%msg %n</pattern>
</encoder>
</appender>
<logger name="jdbc" level="OFF"/>
<logger name="jdbc.sqlonly" level="DEBUG" additivity="false">>
<appender-ref ref="STDOUT" />
</logger>

<logger name="jdbc.sqltiming" level="INFO" additivity="false">>
<appender-ref ref="STDOUT" />
</logger>
<logger name="jdbc.resultsettable" level="DEBUG" additivity="false">>
<appender-ref ref="STDOUT" />
</logger>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
5. User.java
package com.example.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.TableGenerator;
@TableGenerator(name = "MY_GENERATOR", table = "SEQ_TABLE",
pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_VALUE",
pkColumnValue = "USER_SEQ")
@Entity(name="MyUser")
public class User {
@GeneratedValue(strategy = GenerationType.TABLE, generator =
"MY_GENERATOR")
@Id

private Long userId;
@Column
private String userName;
public User(String userName) {
this.userName = userName;
}
public User() {}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
6. UserRepository.java

package com.example.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.model.User;
public interface UserRepository
extends JpaRepository<User, Long> {
}
7. UserService.java
package com.example.service;
import java.util.List;
import com.example.model.User;
public interface UserService {
User get(Long userId);
User save(User user);
List<User> getAll();
}
8. UserServiceImpl.java
package com.example.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.model.User;
import com.example.repository.UserRepository;
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserRepository userRepository;
@Override
public User get(Long userId) {
return userRepository.findOne(userId);
}
@Override
public User save(User user) {
return userRepository.save(user);
}
@Override
public List<User> getAll() {
return userRepository.findAll();
}
}
9. UserController.java
package com.example.controller;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.example.model.User;
import com.example.service.UserService;
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping(value="/get/{userId}", method=RequestMethod.GET)
public User get(@PathVariable Long userId) {
return userService.get(userId);
}
@RequestMapping(value="/save/{userName}",
method=RequestMethod.GET)
public User save(@PathVariable String userName) {
return userService.save(new User(userName));
}
@RequestMapping(value="/getall", method=RequestMethod.GET)
public List<User> getAll() {
return userService.getAll();
}
}
10. 오라클에 식별자를 위한 테이블 및 데이터 생성

SQL> create table seq_table (
2 seq_name varchar2(100) primary key,
3 seq_value number not null);
테이블이 생성되었습니다.
SQL> INSERT INTO SEQ_TABLE VALUES ('USER_SEQ', 1);
1 개의 행이 만들어졌습니다.
SQL> commit;
커밋이 완료되었습니다.
11. 실행결과
