使用mybatis給Oracle存儲過程傳List,數組類型.

0.不廢話.直接上過程

1.因爲Oracle本身是有數組概念的.我們直接使用Oracle中的數組,但需要先創建類型,varray也就是Oracle的數組,100指定長度,of後面指定類型,

CREATE OR REPLACE TYPE tables_array AS VARRAY(100) OF VARCHAR2(32);

2.第二步,創建一個表,進行測試數據,

drop table test;
create table test
(
  name varchar2(32)
);

3.第三步,創建一個測試過程.,傳入自定義的數組類型,使用數組內部方法.遍歷添加

create or replace procedure t_list_to_p(arr_t in tables_array) is
begin
  for i in arr_t.first .. arr_t.last loop
    insert  into test values(arr_t(i));
  end loop;
  commit;
end t_list_to_p;

在這裏擴展下Oracle數組的操作方法以及屬性

COUNT             返回集合中元素的個數   
DELETE            刪除集合中所有元素    
DELETE(x)         刪除元素下標爲x的元素      對VARRAY非法     
DELETE(x,y)       刪除元素下標從X到Y的元素   對VARRAY非法     

EXIST(x)          如果集合元素x已經初始化,則返回TRUE, 否則返回FALSE    
EXTEND            在集合末尾添加一個元素      對Index_by非法    
EXTEND(x)         在集合末尾添加x個元素       對Index_by非法    
EXTEND(x,n)       在集合末尾添加元素n的x個副本 對Index_by非法    
FIRST             返回集合中的第一個元素的下標號,對於VARRAY集合始終返回1。    

LAST              返回集合中最後一個元素的下標號, 對於VARRAY返回值始終等於COUNT.    
LIMIT             返回VARRY集合的最大的元素個數   Index_by集合和嵌套表無用    
NEXT(x)           返回在第x個元素之後及緊挨着它的元素值,如果x是最後一個元素,返回null.    
PRIOR(x)          返回在第x個元素之前緊挨着它的元素的值,如果x是第一個元素,則返回null。    
TRIM              從集合末端開始刪除一個元素  對於index_by不合法    

TRIM(x)           從集合末端開始刪除x個元素

4.plsql中調用賦值,這個我找了好久.在這展示下.用於測試過程(指存儲過程)是否好用.只要是怎麼給數組賦值,如果是對象的話,table_list(able_obj('12')),關於對象類型,我會在寫一篇

declare
  -- Non-scalar parameters require additional processing 
  arr_t tables_array:=tables_array('13','14','15');
begin
  -- Call the procedure
  t_list_to_p(arr_t => arr_t);
end;

5.到這裏函數這裏就準備好了.至於如何用jdbc測試.就不說了.網上很多,接下來講如何用mybatis進行調用.先把mybaitis環境搭建好.這裏就不貼代碼了.

6.編寫map.xml文件調用,以及對應的接口

void appCurrentRoad(@Param("roads")List<String> roads);

 下面的.參數最好都寫上.而typeHandler則是必須的.也是我自定義的一個,

<select id="appCurrentRoad" statementType="CALLABLE" >
        call t_list_to_p(
         #{roads,jdbcType=ARRAY,javaType=List,typeHandler=com.hollycrm.emscheck.common.util.ArrayTypeHandler,mode=IN}
        )
</select>

7.編寫自定義的typeHandler.因爲我們在Oracle聲明的自定義數組.是自定義類型的.所以mybatis無法自動處理,

部分詳細內容.可以看下https://www.jianshu.com/p/23d6a0d07a87

https://blog.csdn.net/wlwlwlwl015/article/details/52526630有講解typeHandler的部分源碼,

繼承BaseTypeHandler重寫對應方法

package com.common.util;


import oracle.sql.ARRAY;
import oracle.sql.ArrayDescriptor;
import oracle.sql.STRUCT;
import oracle.sql.StructDescriptor;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;


//這個註解聲明瞭他是處理jdbc類型的  @MappedTypes()也可以用這個註解指定javaType.進行約束,一般不用
@MappedJdbcTypes(JdbcType.ARRAY)
public class ArrayTypeHandler extends BaseTypeHandler{

    @Override
    public Object getNullableResult(ResultSet arg0, String arg1)
            throws SQLException {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return null;
    }

    @Override
    public Object getNullableResult(CallableStatement arg0, int arg1)
            throws SQLException {
        // TODO Auto-generated method stub
        return null;
    }
    //這個方法是將java中的集合類型轉換成數據庫中對應類型.在這裏也就是數組類型
    @SuppressWarnings("unchecked")
    @Override
    public void setNonNullParameter(java.sql.PreparedStatement parameterSetter, int i,
                                    Object o, JdbcType jdbcType) throws SQLException {
        Connection conn = null;
        try {
            if(null != o){
                List<String> list = (ArrayList<String>) o;
                conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost", "test", "test");
                //這裏必須得用大寫,而且必須要引入一個包,如果不引入這個包的話字符串無法正常轉換,包是:orai18n.jar(這個並沒試過)
                //這個應該是封裝的一個轉換方法吧.不是很清楚
                ArrayDescriptor arrayDes = ArrayDescriptor.createDescriptor("TABLES_ARRAY",conn);
                //這裏是聲明一個數據庫的數組類型
                ARRAY array = new ARRAY(arrayDes,conn,list.toArray());
                parameterSetter.setArray(i, array);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
            if(null != conn){
                conn.close();
            }
        }

    }
}

8.差不多就是這些了. 參照帖子https://blog.csdn.net/hzw2312/article/details/8444462

 
如果沒有在Handler中註釋jdbcType也可在這裏設置 
Xml代碼  

<typeHandlers>  
        <typeHandler javaType="list" <!--jdbcType="ARRAY"--> handler="com.package.MyHandler"/>  
</typeHandlers> 

9.最後在總結下遇到的錯誤

這個錯誤是我在沒有指定@MappedJdbcTypes(JdbcType.ARRAY)這個註解的時候拋出的.在有就是各參數是否對應,如最後的mode是否是in 或者out 或者inout類型

ORA-03115: unsupported network datatype or representation 不支持的網絡數據類型或表示

最開始的錯誤.在沒有自定義TypeHandler時

TypeException: Could not set parameters for mapping: ParameterMapping{property='roads', mode=IN, javaType=class java.lang.Object, jdbcType=null, numericScale=null, resultMapId='null', jdbcTypeName='null',expression='null'..SQLException: 無效的列類型

10.ok大概就這些了.有什麼不對的,歡迎不吝賜教

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章