在Oracle ADF的Java代码中动态添加键值对并调用存储过程的最优方案
最优实现方案
整体思路
- 数据库端定义嵌套表类型接收多组键值对数据,编写对应批量处理的存储过程
- Java端将选中行数据转换为对应数据结构,批量封装后传入存储过程
- 通过ADF获取数据库连接,调用存储过程完成批量操作,同时处理事务与异常
步骤1:数据库端定义类型与存储过程
假设使用Oracle数据库,先定义单行数据类型和嵌套表类型,再编写批量处理的存储过程:
-- 定义单行审批数据类型 CREATE OR REPLACE TYPE REC_APPROVAL_DATA AS OBJECT ( ID NUMBER, START_DATE TIMESTAMP, SRC_TYPE VARCHAR2(10), TYPE VARCHAR2(10), UPDATED_BY VARCHAR2(50), LAST_UPDATE_DATE DATE ); -- 定义批量数据的嵌套表类型 CREATE OR REPLACE TYPE TBL_APPROVAL_DATA AS TABLE OF REC_APPROVAL_DATA; -- 批量审批存储过程 CREATE OR REPLACE PROCEDURE PROC_BATCH_APPROVE(p_data TBL_APPROVAL_DATA) IS BEGIN -- 用FORALL实现高效批量更新(比循环单条更新性能提升数倍) FORALL i IN p_data.FIRST..p_data.LAST UPDATE YOUR_TARGET_TABLE SET TYPE = p_data(i).TYPE, UPDATED_BY = p_data(i).UPDATED_BY, LAST_UPDATE_DATE = p_data(i).LAST_UPDATE_DATE WHERE ID = p_data(i).ID AND SRC_TYPE = p_data(i).SRC_TYPE; COMMIT; END; /
步骤2:Java端改造代码
1. 定义DTO映射数据库单行类型
创建简单Java类对应数据库的REC_APPROVAL_DATA类型,方便数据封装:
public class ApprovalData { private Long id; private Timestamp startDate; private String srcType; private String type; private String updatedBy; private Date lastUpdateDate; // 构造方法 public ApprovalData(Long id, Timestamp startDate, String srcType, String type, String updatedBy, Date lastUpdateDate) { this.id = id; this.startDate = startDate; this.srcType = srcType; this.type = type; this.updatedBy = updatedBy; this.lastUpdateDate = lastUpdateDate; } // 省略getter/setter方法 }
2. 改造原业务代码,收集数据并调用存储过程
ViewObject VO = getViewObjectFromAMImpl("EOView2", "AppModuleDataControl"); Row[] selectedRows = VO.getFilteredRows("tSelect", true); List<ApprovalData> approvalList = new ArrayList<>(); ADFContext adfCtx = ADFContext.getCurrent(); SecurityContext secCntx = adfCtx.getSecurityContext(); String currentUser = secCntx.getUserName(); Date currentDate = new Date(); // 筛选符合条件的行,封装到列表 for (Row r : selectedRows) { if ("E".equals(r.getAttribute("SrcType"))) { Long id = (Long) r.getAttribute("Id"); // 替换为实际主键字段 Timestamp startDate = (java.sql.Timestamp) r.getAttribute("StartDate"); String srcType = (String) r.getAttribute("SrcType"); ApprovalData data = new ApprovalData(id, startDate, srcType, "S", currentUser, currentDate); approvalList.add(data); } } int counter = approvalList.size(); System.out.println("printing count" + counter); if (counter == 0) { JSFUtils.addFacesErrorMessage("No records Approved."); } else { // 调用批量存储过程 callBatchApprovalProcedure(approvalList); JSFUtils.addFacesInformationMessage(counter + " records Approved successfully."); AdfFacesContext.getCurrentInstance().addPartialTarget(hearderTableBind); } approvePopup.cancel();
3. 实现存储过程调用方法
private void callBatchApprovalProcedure(List<ApprovalData> approvalList) { Connection conn = null; CallableStatement stmt = null; try { // 获取ADF事务的数据库连接 conn = getDBTransaction().getConnection(); // 注册数据库定义的嵌套表和单行类型 ArrayDescriptor arrayDesc = ArrayDescriptor.createDescriptor("TBL_APPROVAL_DATA", conn); StructDescriptor structDesc = StructDescriptor.createDescriptor("REC_APPROVAL_DATA", conn); // 将List转换为数据库可识别的Struct数组 Struct[] structArray = new Struct[approvalList.size()]; for (int i = 0; i < approvalList.size(); i++) { ApprovalData data = approvalList.get(i); Object[] structAttrs = new Object[]{ data.getId(), data.getStartDate(), data.getSrcType(), data.getType(), data.getUpdatedBy(), data.getLastUpdateDate() }; structArray[i] = new Struct(structDesc, conn, structAttrs); } // 封装为ARRAY对象传入存储过程 ARRAY dataArray = new ARRAY(arrayDesc, conn, structArray); // 执行存储过程 String sql = "{call PROC_BATCH_APPROVE(?)}"; stmt = conn.prepareCall(sql); stmt.setArray(1, dataArray); stmt.execute(); // 提交事务(若存储过程未内部提交) getDBTransaction().commit(); } catch (SQLException e) { // 异常回滚,提示错误 getDBTransaction().rollback(); JSFUtils.addFacesErrorMessage("Approval failed: " + e.getMessage()); e.printStackTrace(); } finally { // 关闭资源 try { if (stmt != null) stmt.close(); if (conn != null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } } }
关键注意事项
- 数据库类型名称需与代码中完全一致(Oracle默认区分大小写,建议统一用大写)
- 若使用JDeveloper开发,可通过向导自动生成数据库类型对应的Java类,无需手动处理
Struct和ARRAY - 存储过程中使用
FORALL而非循环单条操作,是批量处理的性能核心 - 异常处理需确保事务一致性,避免部分数据更新成功的情况
内容的提问来源于stack exchange,提问作者kishore
相关产品推荐
相关产品推荐

