달력

102018  이전 다음

  •  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  •  
  •  
  •  


테이블이 2개가 있다. A 테이블의 PK를 B 테이블이 FK로 참조하고 있을 때, A 테이블에 1개의 row를 추가하면서 B 테이블에도 1개의 row를 함께 추가하는 경우가 있다. 어떻게 해야 할까?? Oracle와 같은 DBMS라면 시퀀스를 사용해서 시퀀스를 먼저 뽑아내 두 테이블에 동일한 값을 설정하여 추가하면 되겠지만.. MySQL의 AUTO_INCREMENT로 설정된 column은 그 값을 먼저 가져올 수도 없다.

이럴 때는 MySQL의 LAST_INSERT_ID()라는 함수를 사용하면 된다. 이 함수는 가장 최근에 성공적으로 수행된 INSERT 구문의 첫번째 AUTO_INCREMENT column의 값을 반환한다. (LAST_INSERT_ID() (no arguments) returns the first  automatically generated value successfully inserted for an AUTO_INCREMENT column as a result of the most recently executed INSERT  statement.) MySQL 메뉴얼에 자세한 예제가 있다.


mysql> USE test;
Database changed
mysql> CREATE TABLE t (
    ->   id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
    ->   name VARCHAR(10) NOT NULL
    -> );
Query OK, 0 rows affected (0.09 sec)

mysql> INSERT INTO t VALUES (NULL, 'Bob');
Query OK, 1 row affected (0.01 sec)

mysql> SELECT * FROM t;
+----+------+
| id | name |
+----+------+
|  1 | Bob  |
+----+------+
1 row in set (0.01 sec)

mysql> SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                1 |
+------------------+
1 row in set (0.00 sec)

mysql> INSERT INTO t VALUES
    -> (NULL, 'Mary'), (NULL, 'Jane'), (NULL, 'Lisa');
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM t;
+----+------+
| id | name |
+----+------+
|  1 | Bob  |
|  2 | Mary |
|  3 | Jane |
|  4 | Lisa |
+----+------+
4 rows in set (0.01 sec)

mysql> SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                2 |
+------------------+
1 row in set (0.00 sec)

 

처음 INSERT 구문으로 "Bob"을 추가하고 LAST_INSERT_ID()의 반환값은 1이 나왔다. AUTO_INCREMENT column의 id값이다. 그리고 2번째 INSERT 구문으로 "Mary"와 "Jane", "Lisa"를 추가하였다. 이 때는 3개의 row를 추가하기 때문에 이 추가된 record 중 가장 처음에 추가된 record의 id인 2가 반환된다.

그리고 이 LAST_INSERT_ID()의 값은 각 connection 마다 따로 관리된다. 때문에 A와 B가 다른 connection을 가지고 동시에 INSERT 후 LAST_INSERT_ID()값을 SELECT하더라도 자신이 INSERT한 ID값을 반환받게 된다. 예를 들면, A가 INSERT를 하고 LAST_INSERT_ID()를 SELECT하려고 하는 순간 B가 먼저 INSERT를 하였다. 이 경우 A가 SELECT하여 얻어지는 ID값은 B가 INSERT한 ID값이 아닌 A가 INSERT한 ID값이 된다. 물론, 전제 조건은 A와 B가 다른 connection을 사용한다는 것이지만, 동시에 INSERT하고 접근하는 문제가 있어도 유용하게 사용할 수 있다.

 

또한 iBATIS에서 INSERT 이후 ID를 바로 반환하여 사용할 수 있다. 다음과 같이 selectKey를 이용하여 sqlMap을 설정한다.

<insert id="user.insertUserAndGetId" parameterClass="user">
    <![CDATA[
        INSERT INTO t
        (
            name
        )
        VALUES
        (
            #name#
        )
    ]]>
    <selectKey keyProperty="id" resultClass="Integer">
        SELECT LAST_INSERT_ID()
    </selectKey>
</insert>

 

UserVO user = new UserVO();
user.setName("Bob");

System.out.println("Index of user " + user.getName() + " is " + user.getId() + " (before insert)");
int id = ((Integer) sqlMap.insert("user.insertUserAndGetId")).intValue();
System.out.println("Index of user " + user.getName() + " is " + user.getId() + " (after insert)");


해당 INSERT 구문을 수행하고 selectKey에 정의한 구문을 수행하여 그 값을 반환한다. selectKey의 속성을 살펴보면, keyProperty와 resultClass가 있다.

keyProperty 속성을 설정해 주면 selectKey로 SELECT된 값을 전달인자의 변수값으로 설정해 준다. 소스코드의 user는 이름만 "Bob"으로 설정해 주었다. 하지만 INSERT를 수행한 다음 user.getId()의 값이 추가된 ID로 설정된 것을 볼 수 있다. 이 속성은 설정하는 경우만 해당 변수의 값(이 예제에서는 user의 id 변수)이 설정되므로 설정하지 않아도 문제는 없다.


Index of user Bob is 0 (before insert)
Index of user Bob is 7 (after insert)

 

resultClass는 selectKey로 반환되는 값의 타입을 나타낸다. 이 타입과 동일한 타입으로 소스코드에서 casting해서 받으면 된다. LAST_INSERT_ID()로 반환되는 값은 숫자이니 int로 받으면 될 것이다. 이 부분은 꼭 LAST_INSERT_ID()를 사용하지 않아도 된다. (물론 LAST_INSERT_ID()는 MySQL의 함수니까..) INSERT를 수행한 다음에 SELECT 구문으로 조회할 내용이 있으면 적어주면 된다.

'IBATIS' 카테고리의 다른 글

Mapped Statements  (0) 2010.02.23
IBATIS 최근 입력 UID 값 가져오기  (0) 2010.02.16
DATA 타입 처리  (0) 2010.01.21
ibatis  (0) 2009.12.28
Posted by o0꼰지0o
TAG

티스토리 툴바