導(dǎo)航

          <2011年12月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          最新評論

          ibatis存儲過程入?yún)⒓?-轉(zhuǎn)

          Posted on 2011-07-28 13:55 blues 閱讀(1187) 評論(1)  編輯  收藏 所屬分類: Data Base
          原文地址:
          http://mail-archives.apache.org/mod_mbox/ibatis-user-java/200802.mbox/%3C8B243E70CE6BFB438E3CDE03E1E4F698925024@zil01exm62.ds.mot.com%3E



          After spending a great deal of time in R&D I came up with the following
          solution for sending IN and OUT Oracle UDT collections (e.g. nested
          tables or arrays). I'm currently using Oracle 10g. My driver version is
          10.2.0.2.0 and I had to place the oracle i18n jar (version 10.1.0.2.0.0)
          in the class path to solve the '???' datum conversion to string problem.
          I am using AppFuse2 (Spring and iBatis 2.3.0). I had to modify 2.3.0 to
          allow access to the
          com.ibatis.sqlmap.engine.type.JdbcTypeRegistry.setType method. (Only
          required if you want OUT nested table).

          There is not much use for using a nested table as out parameter in my
          code... I would much rather use a REF CURSOR for this purpose. However,
          for the sake of example and mapping demonstration, I have one i_array IN
          nested table and one o_array OUT nested table as parameters to my
          procedure.

          I will try to demonstrate how this is done. First we will declare two
          schema scope (not package) types:

          DROP TYPE EMP_SALARY_TAB;
          DROP TYPE EMP_SALARY_REC;

          CREATE OR REPLACE TYPE EMP_SALARY_REC AS OBJECT (
          EMP_ID NUMBER(5),
          EMP_NAME VARCHAR2(255),
          START_DATE DATE,
          SALARY NUMBER
          );
          /

          CREATE OR REPLACE Type EMP_SALARY_TAB AS TABLE OF EMP_SALARY_REC;
          /

          next we will create a small package with one single test procedure

          CREATE OR REPLACE PACKAGE EMP_SALARY_PKG IS
          PROCEDURE GET_EMP_SALARIES(i_array IN EMP_SALARY_TAB,o_array OUT
          EMP_SALARY_TAB);
          End EMP_SALARY_PKG;
          /

          CREATE OR REPLACE PACKAGE BODY EMP_SALARY_PKG AS

          PROCEDURE GET_EMP_SALARIES(i_array IN EMP_SALARY_TAB,o_array OUT
          EMP_SALARY_TAB)
          IS
          emp_salary_rec OM.EMP_SALARY_REC;
          num_of_months NUMBER;
          base_salary_usd NUMBER := 70000;
          annual_bonus_pct NUMBER := 3.5;
          updated_salary NUMBER;
          BEGIN
          o_array := i_array;
          FOR idx IN i_array.first()..i_array.last() LOOP
          emp_salary_rec := i_array(idx);
          num_of_months := 24;
          updated_salary := (((num_of_months / 12) * annual_bonus_pct) /
          100) + base_salary_usd;
          emp_salary_rec.SALARY := updated_salary;
          o_array(idx) := emp_salary_rec;
          END LOOP;
          EXCEPTION
          WHEN OTHERS THEN
          -- handle errors here...
          dbms_output.put_line('Error: '||substr(1,255,sqlerrm));

          END GET_EMP_SALARIES;

          END EMP_SALARY_PKG;
          /


          Now we are ready to begin writing java. First - out POJO (the model used
          to transfer data to and from the DB) This is a nasty looking model
          because it implements ora.sql.ORAData and ORADataFactory. I basically
          copied most of the implementation from the Oracle JPublish help manual
          leave aside the standard bean methods used by my framework (AppFuse):

          package com.mot.nsa.model.oracle;

          import java.sql.Connection;
          import java.sql.SQLException;
          import java.util.Date;
          import oracle.jdbc.OracleTypes;
          import oracle.jpub.runtime.MutableStruct;
          import oracle.sql.Datum;
          import oracle.sql.ORAData;
          import oracle.sql.ORADataFactory;
          import oracle.sql.STRUCT;
          import org.apache.commons.logging.Log;
          import org.apache.commons.logging.LogFactory;
          import com.mot.nsa.model.BaseObject;

          public class EmpSalary extends BaseObject implements ORAData,
          ORADataFactory {

          // Class fields
          private Integer empId;
          private String empName;
          private Date startDate;
          private Double salary;
          // JPublish code
          public static final String _SQL_NAME = "OM.EMP_SALARY_REC";
          public static final int _SQL_TYPECODE = OracleTypes.STRUCT;
          protected MutableStruct _struct;
          static int[] _sqlType = { OracleTypes.NUMBER, OracleTypes.CHAR,
          OracleTypes.DATE, OracleTypes.NUMBER };
          static ORADataFactory[] _factory = new ORADataFactory[4];
          static final EmpSalary _EmpSalaryFactory = new EmpSalary();
          // logger (if you wish)
          private final Log log = LogFactory.getLog(EmpSalary.class);
          /**
          *
          */
          private static final long serialVersionUID = -7710368639791237838L;

          /* constructor */
          protected EmpSalary(boolean init) {
          if (init) {
          _struct = new MutableStruct(new Object[4], _sqlType,
          _factory);
          }
          }

          public EmpSalary() {
          this(true);
          }

          /* ORAData interface */
          public Datum toDatum(Connection conn) throws SQLException {
          log.info("Calling method toDatum...");
          Datum d = _struct.toDatum(conn, _SQL_NAME);
          return d;
          }

          /* ORADataFactory interface */
          public ORAData create(Datum d, int sqlType) throws SQLException {
          return create(null, d, sqlType);
          }

          protected ORAData create(EmpSalary o, Datum d, int sqlType) throws
          SQLException {
          log.info("Calling method create...");
          if (d == null) {
          return null;
          }
          if (o == null) {
          o = new EmpSalary(false);
          }
          o._struct = new MutableStruct((STRUCT) d, _sqlType, _factory);
          return o;
          }

          public static ORADataFactory getORADataFactory() {
          return _EmpSalaryFactory;
          }

          // Getters
          public Integer getEmpId() throws SQLException {
          return (Integer) _struct.getAttribute(0);
          }

          public String getEmpName() throws SQLException {
          return (String) _struct.getAttribute(1);
          }

          public Date getStartDate() throws SQLException {
          return (Date) _struct.getAttribute(2);
          }

          public Double getSalary() throws SQLException {
          return (Double) _struct.getAttribute(3);
          }

          // Setters
          public void setEmpId(Integer empId) throws SQLException {
          this.empId = empId;
          _struct.setAttribute(0, this.empId);
          }

          public void setEmpName(String empName) throws SQLException {
          this.empName = empName;
          _struct.setAttribute(1, this.empName);
          }

          public void setStartDate(Date startDate) throws SQLException {
          this.startDate = startDate;
          _struct.setAttribute(2, this.startDate);
          }

          public void setSalary(Double salary) throws SQLException {
          this.salary = salary;
          _struct.setAttribute(3, this.salary);
          }

          // Just standard hashCode, equals and toString for POJO's
          @Override
          public int hashCode() {
          return hashCode(this);
          }

          @Override
          public boolean equals(Object obj) {
          return equals(this, obj);
          }

          @Override
          public String toString() {
          return toString(this);
          }
          }

          Next we will write the 'EmpSalaryTypeHandlerCallback' which handles this
          type:

          import java.sql.Connection;
          import java.sql.ResultSet;
          import java.sql.SQLException;
          import java.util.ArrayList;
          import java.util.Date;
          import java.util.List;
          import oracle.jdbc.OracleTypes;
          import oracle.jdbc.driver.OracleConnection;
          import oracle.sql.ARRAY;
          import oracle.sql.ArrayDescriptor;
          import oracle.sql.STRUCT;
          import org.apache.commons.dbcp.DelegatingConnection;
          import org.apache.commons.logging.Log;
          import org.apache.commons.logging.LogFactory;
          import com.ibatis.sqlmap.client.extensions.ParameterSetter;
          import com.ibatis.sqlmap.client.extensions.ResultGetter;
          import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback;
          import com.ibatis.sqlmap.engine.type.JdbcTypeRegistry;
          import com.my.model.oracle.EmpSalary;

          public class EmpSalaryTypeHandlerCallback implements TypeHandlerCallback
          {

          private final Log log =
          LogFactory.getLog(EmpSalaryTypeHandlerCallback.class);
          private static final String SCHEMA = "OM";
          private static final String EMP_SALARY_TAB = SCHEMA + "." +
          "EMP_SALARY_TAB";
          private static final String EMP_SALARY_REC = SCHEMA + "." +
          "EMP_SALARY_REC";
          /**
          * If we need an OUT parameter of type OM.EMP_SALARY_TAB (e.g. our
          * implementation of getResult will be called) we will need to
          modify iBatis
          * framework (v2.3.0) to allow access to JdbcTypeRegistry.setType
          (currently
          * private -> should be public).
          *
          * If we only need to sen in a OM.EMP_SALARY_TAB - we do not need to
          modify
          * anything and the next static block is not required.
          */
          static {
          JdbcTypeRegistry.setType(EMP_SALARY_REC, OracleTypes.STRUCT);
          JdbcTypeRegistry.setType(EMP_SALARY_TAB, OracleTypes.ARRAY);
          };

          @SuppressWarnings("unchecked")
          public void setParameter(ParameterSetter setter, Object parameter)
          throws SQLException {
          log.info("calling setParameter...");
          try {
          List<EmpSalary> empSalaries = (List<EmpSalary>) parameter;
          // log.info("Converting list to array...");
          EmpSalary[] recArray = new EmpSalary[empSalaries.size()];
          for (int i = 0; i < recArray.length; i++) {
          recArray[i] = empSalaries.get(i);
          }
          log.info("Converted list to array.");
          setter.getPreparedStatement().getConnection();
          Connection conn =
          setter.getPreparedStatement().getConnection();
          if (conn instanceof DelegatingConnection) {
          DelegatingConnection dcon = (DelegatingConnection) conn;
          conn = dcon.getInnermostDelegate();
          }
          conn = (OracleConnection) conn;
          ArrayDescriptor arrayDescriptor =
          ArrayDescriptor.createDescriptor(EMP_SALARY_TAB, conn);
          ARRAY array = new ARRAY(arrayDescriptor, conn, recArray);
          setter.setArray(array);
          } catch (SQLException sqle) {
          log.info("SQLException: " + sqle, sqle);
          throw sqle;
          }
          }

          public Object getResult(ResultGetter getter) throws SQLException {
          ARRAY array = (oracle.sql.ARRAY) getter.getArray();
          ResultSet rs = array.getResultSet();
          List<EmpSalary> empSalaries = new ArrayList<EmpSalary>();
          while (rs != null && rs.next()) {
          STRUCT struct = (STRUCT) rs.getObject(2);
          Object[] attribs = struct.getAttributes();
          EmpSalary empSalary = new EmpSalary();
          empSalary.setEmpId(((java.math.BigDecimal)
          attribs[0]).intValue());
          empSalary.setEmpName((String) attribs[1]);
          empSalary.setStartDate((Date) attribs[2]);
          empSalary.setSalary(((java.math.BigDecimal)
          attribs[3]).doubleValue());
          empSalaries.add(empSalary);
          }
          return empSalaries;
          }

          /**
          * Nothing here can help us anyway...
          */
          public Object valueOf(String arg0) {
          if (arg0 == null) {
          return new ArrayList<EmpSalary>();
          }
          return arg0;
          }
          }

          Notice: if you want to pass a collection as an OUT parameter - you will
          have to modify iBatis 2.3.0 so you can do this:
          JdbcTypeRegistry.setType("MYTYPE",OracleTypes.SomeType). Now we can
          start iBatis mapping:

          <?xml version="1.0" encoding="UTF-8"?>
          <!DOCTYPE sqlMap
          PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
          "http://ibatis.apache.org/dtd/sql-map-2.dtd">
          <sqlMap namespace="DBTestSQL">

          <typeAlias alias="empSalaryTypeHandler"
          type="com.my.company.dao.ibatis.utils.EmpSalaryTypeHandlerCallback" />
          <typeAlias alias="empSalary" type="com.my.model.oracle.EmpSalary" />

          <resultMap id="empSalaryResult" class="empSalary">
          <result property="empId" jdbcType="NUMERIC"
          javaType="java.lang.Integer" column="EMP_ID"/>
          <result property="empName" jdbcType="VARCHAR"
          javaType="java.lang.String" column="EMP_NAME"/>
          <result property="startDate" jdbcType="TIMESTAMP"
          javaType="java.util.Date" column="START_DATE"/>
          <result property="salary" jdbcType="NUMERIC"
          javaType="java.lang.Double" column="SALARY"/>
          </resultMap>

          <parameterMap id="empSalaryParams" class="java.util.Map">
          <parameter property="iArray" typeHandler="empSalaryTypeHandler"
          mode="IN" />
          <parameter property="oArray" jdbcType="OM.EMP_SALARY_TAB"
          typeName="OM.EMP_SALARY_TAB" typeHandler="empSalaryTypeHandler"
          mode="OUT" resultMap="empSalaryResult" />
          </parameterMap>

          <procedure id="getEmpSalaries" parameterMap="empSalaryParams"
          resultMap="empSalaryResult">
          {call OM.EMP_SALARY_PKG.GET_EMP_SALARIES(?,?)}
          </procedure>

          </sqlMap>

          And finally - you dao implementation should look something like this:

          import java.util.HashMap;
          import java.util.List;
          import java.util.Map;
          import com.mot.nsa.dao.EmpSalaryDao;
          import com.mot.nsa.model.oracle.EmpSalary;

          public class EmpSalaryDaoiBatis extends GenericDaoiBatis<EmpSalary,
          Integer> implements EmpSalaryDao {

          public EmpSalaryDaoiBatis() {
          super(EmpSalary.class);
          }

          @SuppressWarnings("unchecked")
          public List<EmpSalary> getEmpSalaries(List<EmpSalary> empList) {
          Map<String, Object> params = new HashMap<String, Object>();
          params.put("oArray", empList);
          params.put("iArray", empList);
          getSqlMapClientTemplate().queryForObject("getEmpSalaries",
          params);
          log.info("Params: " + params);
          return (List<EmpSalary>) params.get("oArray");
          }
          }

          Feedback

          # re: ibatis存儲過程入?yún)⒓?-轉(zhuǎn)[未登錄]  回復(fù)  更多評論   

          2011-12-31 17:33 by KAKA
          請問你有沒有做過這個(gè)列子??i_array傳遞過去是空值emp_salary_rec := i_array(idx);這個(gè)地方報(bào)“未找到值”.能指教一下么?99134194@qq.com

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 卓资县| 阳西县| 二连浩特市| 巴林右旗| 左贡县| 灌云县| 张北县| 江北区| 吴忠市| 大石桥市| 微山县| 葵青区| 北碚区| 普格县| 富顺县| 博湖县| 大化| 长春市| 漳平市| 汪清县| 关岭| 宜州市| 盐源县| 南丰县| 邯郸县| 灵川县| 山东| 贵港市| 忻州市| 绥阳县| 太谷县| 岳池县| 宽甸| 扶沟县| 塘沽区| 南汇区| 平邑县| 新蔡县| 湘潭县| 彭山县| 镇原县|