Serial
PG에서 자동 증가하는 정수형 컬럼을 만들 때 사용한다. 기본은 Integer 값을 가진다.
SEQUNCE
ORACLE 12 이전 버전에서 Serial을 구현하기 위해 Sequence를 사용하였다.
GENRATED ALWAYS AS IDENTITY
ORACLE 12 이후 버전에서 Serial을 구현하기 위해 사용
useGeneratedKeys와 keyProperty 사용 시 주의 사항
<aside> 💡
useGeneratedKeys
와 keyProperty
를 사용하여 자동 증가 값을 반환받을 때 Oracle(Tibero)에서 GENERATED ALWAYS AS IDENTITY
컬럼을 사용하면, 예상과 달리 rowid
가 반환되는 경우가 있습니다. 이 경우 반환 값이 String
으로 처리되는 문제가 발생할 수 있습니다.
Oracle에서 GENERATED ALWAYS AS IDENTITY
로 생성된 자동 증가 컬럼의 값을 반환하려 할 때, 기본적으로 ROWID
값이 반환될 수 있습니다. 이는 Oracle이 ROWID
를 내부적으로 행을 고유하게 식별하는 값으로 사용하기 때문입니다. 그 결과, MyBatis가 useGeneratedKeys
를 사용하면 ROWID
를 문자열로 받아오는 경우가 발생할 수 있습니다.
ROWID
는 Oracle에서 각 행을 고유하게 식별하는 값이기 때문에 문자열 형식으로 반환됩니다. 이로 인해 int
또는 long
타입의 자동 증가값을 기대했으나 String
타입인 ROWID
를 받게 되어 타입 불일치 문제가 발생
useGeneratedKeys
대신 RETURNING INTO
사용Oracle에서 RETURNING INTO
구문을 사용하면, 자동 증가값이 정확히 반환되기 때문에 useGeneratedKeys
를 사용하는 대신 이를 활용할 수 있습니다.
Mapper XML 예시:
<insert id="insertEmployee" useGeneratedKeys="false">
INSERT INTO employees (employee_name)
VALUES (#{employee_name})
RETURNING employee_id INTO #{employee_id};
</insert>
이 방식은 RETURNING INTO
구문을 사용하여 자동 증가된 employee_id
를 employee_id
필드에 매핑합니다.
Tibero에서는 RETURNING INTO 구문사용 불가 따라서 selectKey 구문을 이용한다. 실무에서는 max 함수를 이용하는 편이다.
<insert id="insertUser" parameterType="com.domain.User" useGeneratedKeys="true" keyProperty="userID">
INSERT INTO USER(name, email) VALUES ("대환", "[email protected]")
<selectKey keyProperty="userID" resultType="Integer" order="AFTER">
SELECT MAX(userID) FROM USER;
</selectKey>
</insert>
</aside>
Serail → SEQUENCE로 변환하기(Mybatis)
serail → int
CREATE TABLE example (
id INT PRIMARY KEY,
name VARCHAR(100)
);
sequence 생성
CREATE SEQUENCE example_seq
START WITH 1
INCREMENT BY 1;
Mapper의 insert문 변경
MyBatis에서 INSERT 문을 사용할 때, Tibero의 NEXTVAL을 사용하여 시퀀스 값을 자동으로 증가시키는 방법은 매우 간단하다.
MyBatis에서는 일반적으로 SQL 매퍼 파일(XML)에서 SQL 쿼리를 정의하고, insert 태그를 사용하여 SQL을 실행합니다. 또한, 자동 생성된 ID를 반환받으려면 useGeneratedKeys와 keyProperty 속성을 사용한다.
MAPPER
<insert id="insertExample" useGeneratedKeys="true" keyProperty="id">
INSERT INTO example (id, name)
VALUES (example_seq.NEXTVAL, #{name})
</insert>
MyBatis Mapper(Repository) 인터페이스 설정
public interface ExampleMapper {
void insertExample(Example example);
}
객체 클래스(Java 설정)
public class Example {
private Integer id;
private String name;
// getter, setter
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
서비스 클래스 실행
@Service
public class ExampleService {
@Autowired
private ExampleMapper exampleMapper;
public void insertExample() {
Example example = new Example();
example.setName("John Doe");
// Insert 호출
exampleMapper.insertExample(example);
**// 삽입 후 자동 생성된 ID 출력**
System.out.println("Generated ID: " + example.getId());
}
}
설명
이렇게 하면 MyBatis를 사용해서 시퀀스를 활용하여 자동 증가 값을 처리할 수 있다.
PG | Oracle |
---|---|
TEXT | CLOB |
BTYEA | BLOB |
INT8 | NUBER(19) |
NOW() | SYSTDATE |
PostgreSQL의 경우 ::int와 같은 형식으로 형변환이 가능하나, ORACLE에서는 CAST연산자를 통해 형변환한다.
-- PG
Id::Int
-- ORACLE
CAST(Id as Integer)
concat 사용 시 PG는 3개 이상의 인자를 넣을 수 있으나, ORACLE(Tibero)는 불가능하다.