Java中如何获取SQ_ASONE_TASK_DETAIL_ID.NEXTVAL生成的插入ID?
问题描述
执行INSERT语句时,TASK_SID字段由Oracle序列SQ_ASONE_TASK_DETAIL_ID.NEXTVAL自动生成,调用executeUpdate()完成插入后,需要获取这个生成的ID用于后续查询,但尝试用executeQuery()获取的方式失败。
插入数据的Java代码
l_objPreparedStatement.setString(1, p_sEmailId); String entrydate = p_mapAsOneEntryDTO.get(i).getEntryForDate(); String projectName = p_mapAsOneEntryDTO.get(i).getProjectName(); String taskNo = p_mapAsOneEntryDTO.get(i).getTaskNo(); String storyNo = p_mapAsOneEntryDTO.get(i).getStoryNo(); String storyTitle = p_mapAsOneEntryDTO.get(i).getStoryTitle(); String comment = p_mapAsOneEntryDTO.get(i).getComments(); String iterationNo = p_mapAsOneEntryDTO.get(i).getIterationNo(); float hrs = Float.parseFloat(p_mapAsOneEntryDTO.get(i).getWorkHours()); String subpro = p_mapAsOneEntryDTO.get(i).getSubProjectcat(); l_objPreparedStatement.setString(2, entrydate); l_objPreparedStatement.setString(3, projectName); l_objPreparedStatement.setString(4, taskNo); l_objPreparedStatement.setString(5, storyNo); l_objPreparedStatement.setString(6, storyTitle); l_objPreparedStatement.setString(7, comment); l_objPreparedStatement.setString(8, iterationNo); l_objPreparedStatement.setFloat(9, hrs); l_objPreparedStatement.setString(10, p_sLoggedUser); l_objPreparedStatement.setString(11, p_sLoggedUser); l_objPreparedStatement.setString(12, subpro); l_objPreparedStatement.executeUpdate();
对应的INSERT SQL语句
"INSERT INTO ASONE_TASK_DETAIL (TASK_SID,EMAIL_ID,ENTRY_FOR_DATE,PROJECT_NAME,TASK_NO,STORY_NO,STORY_TITLE,COMMENTS, " + "ITERATION_NO,WORK_HOURS,TIMESTAMP,TRIGGER_TYPE,CREATED_BY, " + "CREATED_DATE,MODIFIED_BY,MODIFIED_DATE,CATEGORY)VALUES(SQ_ASONE_TASK_DETAIL_ID.NEXTVAL,?,?,?,?,?,?,?,?,?,SYSDATE,'M',?,SYSDATE,?,SYSDATE,?) ";
失败的ID获取代码
ResultSet resultSet = l_objPreparedStatement.executeQuery(); String taskId = String.valueOf(resultSet.getInt("TASK_SID")); p_mapAsOneEntryDTO.get(i).setID(taskId);
解决方案
针对Oracle数据库,推荐以下几种可靠的方式获取插入时生成的序列值:
方法一:使用INSERT ... RETURNING子句
修改INSERT语句,添加RETURNING TASK_SID INTO ?,通过PreparedStatement注册输出参数获取生成的ID。
修改后的SQL语句
"INSERT INTO ASONE_TASK_DETAIL (TASK_SID,EMAIL_ID,ENTRY_FOR_DATE,PROJECT_NAME,TASK_NO,STORY_NO,STORY_TITLE,COMMENTS, " + "ITERATION_NO,WORK_HOURS,TIMESTAMP,TRIGGER_TYPE,CREATED_BY, " + "CREATED_DATE,MODIFIED_BY,MODIFIED_DATE,CATEGORY)VALUES(SQ_ASONE_TASK_DETAIL_ID.NEXTVAL,?,?,?,?,?,?,?,?,?,SYSDATE,'M',?,SYSDATE,?,SYSDATE,?) " + "RETURNING TASK_SID INTO ?";
调整后的Java代码
// 注册输出参数,类型需匹配TASK_SID的实际字段类型,这里假设为INTEGER l_objPreparedStatement.registerOutParameter(13, java.sql.Types.INTEGER); // 执行插入操作 l_objPreparedStatement.executeUpdate(); // 获取生成的TASK_SID int taskId = l_objPreparedStatement.getInt(13); p_mapAsOneEntryDTO.get(i).setID(String.valueOf(taskId));
方法二:预获取序列值再插入
先查询序列的下一个值并保存,再将该值作为TASK_SID插入表中,后续直接使用预存的值即可。
步骤1:获取序列值
PreparedStatement seqStmt = connection.prepareStatement("SELECT SQ_ASONE_TASK_DETAIL_ID.NEXTVAL FROM DUAL"); ResultSet rs = seqStmt.executeQuery(); int taskId = 0; if(rs.next()){ taskId = rs.getInt(1); } seqStmt.close(); rs.close();
步骤2:修改INSERT语句
"INSERT INTO ASONE_TASK_DETAIL (TASK_SID,EMAIL_ID,ENTRY_FOR_DATE,PROJECT_NAME,TASK_NO,STORY_NO,STORY_TITLE,COMMENTS, " + "ITERATION_NO,WORK_HOURS,TIMESTAMP,TRIGGER_TYPE,CREATED_BY, " + "CREATED_DATE,MODIFIED_BY,MODIFIED_DATE,CATEGORY)VALUES(?,?,?,?,?,?,?,?,?,?,SYSDATE,'M',?,SYSDATE,?,SYSDATE,?) ";
步骤3:设置参数并执行插入
// 将预获取的taskId作为第一个参数传入 l_objPreparedStatement.setInt(1, taskId); // 其余参数索引依次后移一位 l_objPreparedStatement.setString(2, p_sEmailId); // ... 其他参数设置保持原有逻辑 l_objPreparedStatement.executeUpdate(); // 直接使用预获取的taskId p_mapAsOneEntryDTO.get(i).setID(String.valueOf(taskId));
方法三:使用getGeneratedKeys(需驱动支持)
若使用的Oracle JDBC驱动版本支持,可在创建PreparedStatement时指定返回生成的键,再通过getGeneratedKeys()获取ID。
调整后的代码
// 创建PreparedStatement时指定返回TASK_SID字段 PreparedStatement l_objPreparedStatement = connection.prepareStatement(sql, new String[]{"TASK_SID"}); // ... 设置所有参数,执行插入 l_objPreparedStatement.executeUpdate(); // 获取生成的ID ResultSet rs = l_objPreparedStatement.getGeneratedKeys(); if(rs.next()){ int taskId = rs.getInt(1); p_mapAsOneEntryDTO.get(i).setID(String.valueOf(taskId)); } rs.close();
注意:该方法依赖JDBC驱动的兼容性,部分旧版本Oracle驱动可能支持不佳,优先推荐前两种方法。
内容的提问来源于stack exchange,提问作者dhS
相关产品推荐
相关产品推荐

