JDBC 3.0才支持这样的写法,否则就使用select last_insert_id()吧……
String psql = "INSERT INTO Employee (name, age, address, isMale, level, Department_ID) VALUES (?, ?, ?, ?, ?, ?)"; PreparedStatement ps = conn.prepareStatement(psql,Statement.RETURN_GENERATED_KEYS);
ps.setString(1, emp.getName()); ps.setInt(2, emp.getAge()); ps.setString(3, emp.getAddress()); ps.setInt(4, emp.getIsMale()); ps.setInt(5, emp.getLevel()); ps.setInt(6, emp.getDepartment_ID());
ps.executeUpdate();
ResultSet keys = ps.getGeneratedKeys(); // equivalent to "SELECT last_insert_id();"
if(keys.next()) { System.out.println(keys.getInt(1)); }
如果有多个字段的值是自动生成的,而且又不明确有多少个,或者插入的不仅仅是一条数据的话,或许可以考虑使用以下方式,即通过获得结果集的元据来操作:
Connection conn = //获得连接...; Statement st = conn.createStatement(); st.execute(sql, Statement.RETURN_GENERATED_KEYS); ResultSet rs = st.getGeneratedKeys(); ResultSetMetaData rsmd = rs.getMetaData(); int cols = rsmd.getColumnCount(); while (rs.next()) { for (int i = 1; i < = cols; i++) { //处理数据... } }
在JDBC 3.0之前的版本中,PreparedStatement不能绑定主键,如果采用表自增键(如MySql的auto increment或SqlServer的identity)将给获取正确的主键值带来挑战——因为你必须在插入数据后,马上执行另一条获取新增主键的查询语句。表 1给出了不同数据库获取最新自增主键值的查询语句:
表 1 不同数据库获取新增加的主键值
数据库 获取新增主键的查询语句 DB2 IDENTITY_VAL_LOCAL() Informix SELECT dbinfo('sqlca.sqlerrd1') FROM <TABLE> Sybase SELECT @@IDENTITY SqlServer SELECT SCOPE_IDENTITY()或SELECT @@IDENTITY MySql SELECT LAST_INSERT_ID() HsqlDB CALL IDENTITY() Cloudscape IDENTITY_VAL_LOCAL() Derby IDENTITY_VAL_LOCAL() PostgreSQL SELECT nextval('<TABLE>_SEQ')
如果数据库的并发率很高,比如在插入记录后执行查询主键之前,数据库又执行了若干条插入记录的SQL语句,这时,通过表 1 返回的主键值就是最后一条插入语句的主键值,而非我们希望的主键值了。
所以使用查询语句获取表自增键值是不安全的,这也是为什么有些数据库(如 Oracle、Firebird)故意不提供自增键,而只提供序列的原因,序列强制要求你在新增记录前,先获取主键值。
Oracle通过SELECT <SEQUENCE_NAME>.nextval FROM DUAL获取序列的下一个值,而FireBird通过SELECT GEN_ID(<SEQUENCE_NAME> 1) FROM RDB$DATABASE获取序列的下一个值。
|