레이블이 AutoIncrement인 게시물을 표시합니다. 모든 게시물 표시
레이블이 AutoIncrement인 게시물을 표시합니다. 모든 게시물 표시

2010년 12월 25일 토요일

SQL이 아닌 함수(getGeneratedKeys())를 이용한 AutoIncrement 키값 가져오기

통상적인 RDBMS는 Sequence 또는, AutoIncrement 형태의 시리얼한 id 채번 기능을 제공하고 있다.
또한, 이러한 Sequence 또는 AutoIncrement 로 부터 값이 추출되면, 그 세션에서 최종으로 사용된 id값을
가져올 수 있는 방법들을 제공하고 있다. (Oracle의 SEQUENCE.nextval 또는 MySQL의 LAST_INSERT_ID() 등)
많은 프로그램들에서 이러한 최종 채번된 id값을 가져오기 위해서 “SELECT LAST_INSERT_ID()” 쿼리 문장을
이용하여 조회하고 있는 것으로 보인다.
하지만, 이 방식은 또 한번의 서버 쿼리(Network round-trip)를 발생시키는 방식이며, JDBC 3.0 이상에서는
데이터베이스 서버까지 조회하지 않고 그냥 값을 가져오는 API를 제공하고 있다.

Network 비용이 그리 비싼 건 아니지만,
사용하는 JDBC Driver의 버전이 3.0 이상이라면 (물론 JDK 1.4 이상에서),
아래와 같이 Statement.getGeneratedKeys() 라는 함수를 이용하여 또 한번의 네트워크 통신 없이 바로 가져올 수 있다.
이 방식을 사용하기 위해서는 아래와 같이 Statement.executeUpdate() 나 PreparedStatement.prepareStatement()
함수 호출 시 별도의 설정 항목이 필요합니다.

l   Statement 객체 이용할 경우
int affectedRowCount = stmt.executeUpdate(
       "insert into tb_ai (fdpk, fddata) values (NULL, 'test')",Statement.RETURN_GENERATED_KEYS);
 ResultSet rs = stmt.getGeneratedKeys();
String autoInsertedKey = (rs.next()) ? rs.getString(1) : null;

l   PreparedStatement 객체 이용할 경우
PreparedStatement pstmt = conn.prepareStatement(
       "insert into tb_ai (fdpk, fddata) values (NULL, ?)", Statement.RETURN_GENERATED_KEYS);
 ResultSet rs = pstmt.getGeneratedKeys();
String autoInsertedKey = (rs.next()) ? rs.getString(1) : null;

이러한 방식은 DBMS 의존적인 부분이 아니라(물론 Vendor에서 지원하지 않으면 안되겠지만),
JDBC Driver Version 3.0 의 Spec이기 때문에 기본적인 DBMS(Oracle, MySQL, MSSQL, …)에서는
모두 지원되는 기능이므로 DB Framework에서 지원되지 않는다면, 기능 보완 요청을 통해서 해결이 가능할 듯 함

MySQL JDBC ConnectorConnector-J 3.0.17 부터 JDBC 3.0 지원하고 있습니다 

---------------------------------------------------------------------------------------
/**
 * create table tb_ai(
 *       fdpk bigint not null auto_increment,
 *       fddata varchar(100),
 *       primary key(fdpk)
 * );
 *
 * Get Auto generated insert key
 *     // Every version of JDBC driver
 *     1. rs = stmt.executeQuery("SELECT LAST_INSERT_ID()");
 *     // Over JDBC driver version 3.0
 *     2. rs = pstmt.getGeneratedKeys();
 */
public class GetAutoIncrementKeyTester {
         public static void main(String[] args) throws Exception{
                   GetAutoIncrementKeyTester tester = new GetAutoIncrementKeyTester();

                   String autoInsertedKey = tester.insertWithLiteralStatement();
                   System.out.println(">> Auto inserted key : " + autoInsertedKey);

                   autoInsertedKey = tester.insertWithLiteralStatement();
                   System.out.println(">> Auto inserted key : " + autoInsertedKey);
         }

         protected String insertWithLiteralStatement() throws Exception{
                   Connection conn = getMasterConnection();
                   Statement stmt = conn.createStatement();

                   stmt.executeUpdate(
                       "insert into tb_ai (fdpk, fddata) values (NULL, 'test')",Statement.RETURN_GENERATED_KEYS);
                   ResultSet rs = stmt.getGeneratedKeys();
                   String autoInsertedKey = (rs.next()) ? rs.getString(1) : null;
                   rs.close();stmt.close();conn.close();

                   return autoInsertedKey;
         }

         protected String insertWithPreparedStatement() throws Exception{
                   Connection conn = getMasterConnection();
                   PreparedStatement pstmt = conn.prepareStatement(
                       "insert into tb_ai (fdpk, fddata) values (NULL, ?)",Statement.RETURN_GENERATED_KEYS);

                   pstmt.setString(1, "data");
                   pstmt.executeUpdate();

                   ResultSet rs = pstmt.getGeneratedKeys();
                   String autoInsertedKey = (rs.next()) ? rs.getString(1) : null;
                   rs.close();pstmt.close();conn.close();

                   return autoInsertedKey;
         }

         protected Connection getMasterConnection() throws Exception{
                   String driver = "com.mysql.jdbc.Driver";
                   String url = "jdbc:mysql://test_db_host_ip:20306/test_db_name";
                   String uid = "userid";
                   String pwd = "password";

                   Class.forName(driver).newInstance();

                   Connection conn = DriverManager.getConnection(url , uid, pwd);
                   conn.setAutoCommit(false);

                   return conn;
         }
}