backend/iBatis

[iBatis] 자동 생성 Key

버리야 2009. 1. 18. 21:28
반응형
이전에 포스팅했던 2008/08/29 - [나만의 작업/iBatis] - [iBATIS] 4. How to 내용에 있는
"Auto Generation Key" 부분에서 추가할 것이 있어서 좀 더 자세한 내용.

iBatis in Action 에서 발췌.

거의 모든 데이터베이스는 새롭게 삽입되는 레코드마다 자동으로 기본 키를 생성해 주는
기능을 가지고 있는데, 삽입을 완료한 후 생성된 기본키를 알 필요가 있다면....?

자동 생성되는 기본키를 사용하도록 iBatis에서 <insert> 요소의 특별한 자식 요소인 <selectKey> 요소를 사용하여 생성된 키를 모델 객체로 가져올 수 있다. 이 접근법을 따르는 두가지 패턴이 있다.

1. 레코드를 삽입하고 데이터베이스가 키를 생성한 후에 생성된 키를 가져오는 것. 

주의! ) 사용하는 드라이버가 마지막에 실행한 insert 구문에 의해 생성된 키를 반환하는 것을 확실히 보장하는지 확인해야 할 필요가 있는데 두개의 스레드가 거의 동시에 insert 구문을 실행한다면 실행순서는 [사용자 #1추가], [사용자 #2 추가], [사용자 #1을 위한 selectKey], [사용자 #2를 위한 selectKey]가 될 수 있다.

드라이버가 마지막으로 생성된 키를 (전역적으로) 반환한다면 [사용자 #1을 위한 selectKey]는 사용자 #2용으로 생성된 키 값이 되어 버리고 이로 인해 어플리케이션이 혼란에 빠지게 된다~

=> 결국 풀어보면 시점이 살짝!~ 꼬여 서로 다른 기본키 값이 들어갈 경우가 있다는 말~
이 방법을 쓸려면 대부분의 드라이버는 잘 작동하긴 하지만 확신이 없다면 꼭 테스트를 해 볼 것. 

트리거를 사용하면 이 접근법에서 문제를 일으킬 수도 있다. 
MS SQL 에서는 @@identity 값은 트리거에 의해 영향을 받아 키 값을 생성하여 레코드를 하나 추가하고, 뒤이어 트리거를 사용해서 키 값을 생성하여 테이블에 레코드를 추가하면, @@identity에 의해 반환되는 값은 첫번째 레코드용으로 생성된 키가 아닌 트리거에 의해 추가된 레코드용으로 생성된 키가 될 것!!
이런 경우엔 SCOPE_IDENTITY 함수를 대신 사용할 것.

2. 레코드를 추가하기 전에 키를 가져오는 것.

이 접근법을 하용하면 레코드를 삽입하기 전에 키 값을 할당하는 일을 해줘야해서 더 많은 작업이 필요하긴 하지만, 이 방법은 스레드를 사용할 때,  레코드 삽입 후에 키를 가져올 때 발생할 수 있는 잠재적인 문제점들을 피해갈 수 있다.

sqlmaps에서는,
<insert id="insert">
 <selectKey keyProperty="accountId" resultClass="int">
   SELECT nextVal('account_accountid_seq')
 </selectKey>
INSERT INTO Account(accountId, username, password) VALUES ( #accountId#, #username#, #password#)
</insert>
주의!! ) generated key를 확인하는 방법은 각 DB마다 다르니 맞는 sql문을 넣으면 된다~
내 경우엔(Oracle) key값이 sequence여서 
select seq.nextval from dual 이런 sql문을 넣었다.

Mysql에선, LAST_INSERT_ID() 
Mssql에선, SCOPE_IDENTITY()

함수를 이용하여 generated된 key를 확인 가능.

참고)
<selectKey>는 pre-generated key(oracle)와 post-generated key(ms-sql)를 모두 지원한다.

자바코드에서는,
Integer returnValue = (Integer) sqlMap.insert("Account.insert", account);

가장 중요!)
<selectKey> 요소에서 keyProperty 속성은 iBatis가 생성된 키 값을 가져다 입력할 객체의 값으로 설정.
이미 입력된 객체가 키 값을 가지고 있기 때문에 원한다면 반환된 값을 무시할 수도 있다.

=> keyProperty에 지정된 이름의 값이 <insert>문에서 같은 이름의 값으로 들어감.








반응형