통상적인 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(
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(
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 Connector는Connector-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;
}
}