2017-09-06 57 views
1

我有兩個涉及用戶定義類型的相關存儲過程。第一個接受一個對象ID並返回用戶定義類型的相應實例。第二個接受一個相同的用戶定義類型的實例,並對它進行一些操作。如何將用戶定義的類型作爲輸入傳遞給存儲過程?

我正在使用Java,JDBC和一點Spring JDBC。我已經成功完成了第一個存儲過程,即。我可以從數據庫中檢索用戶定義類型的實例,但是,我無法使第二個存儲過程正常工作。

這裏是我迄今爲止的基本輪廓:

架構(PL/SQL)

create or replace type example_obj as object 
    (ID  NUMBER, 
    NAME VARCHAR2(100)) 

create or replace type example_tab as table of example_obj 

create or replace package 
example as 

procedure getExample 
(p_id  in number, 
p_example out example_tab); 

procedure useExample 
(p_example in example_tab); 

end example; 

實體(JAVA) - 表示Java中

public class Example { 
    public BigDecimal ID; 
    public String Name; 
} 
用戶定義類型

映射器(Java) - 從SQL類型映射到Java類型並返回

public class ExampleMapper extends Example implements SQLData { 
    public static final String SQL_OBJECT_TYPE_NAME = "example_obj"; 
    public static final String SQL_TABLE_TYPE_NAME = "example_tab";  

    @Override 
    public String getSQLTypeName() throws SQLException { 
     return SQL_TABLE_TYPE_NAME; 
    } 

    @Override 
    public void readSQL(SQLInput stream, String typeName) throws SQLException { 
     ID = stream.readBigDecimal(); 
     Name = stream.readString(); 
    } 

    @Override 
    public void writeSQL(SQLOutput stream) throws SQLException { 
     stream.writeBigDecimal(ID); 
     stream.writeString(Name); 
    } 
} 

第一個存儲過程(爪哇) - 檢索

import java.sql.CallableStatement; 
import java.sql.Connection; 
import java.sql.SQLException; 
import org.springframework.jdbc.core.JdbcTemplate; 

public Example getExample(BigDecimal ID) throws SQLException { 
    String query = "begin example.getExample(?, ?); end;"; 
    Connection connection = jdbcTemplate.getDataSource().getConnection(); 
    CallableStatement callableStatement = connection.prepareCall(query); 

    callableStatement.setBigDecimal("p_id", ID); 

    Map<String, Class<?>> typeMap = connection.getTypeMap(); 
    typeMap.put(Example.SQL_OBJECT_TYPE_NAME, ExampleMapper.class); 
    callableStatement.registerOutParameter("p_example", Types.ARRAY, Example.SQL_TABLE_TYPE_NAME); 
    connection.setTypeMap(typeMap); 

    callableStatement.execute(); 

    Array array = (Array)callableStatement.getObject("p_example"); 
    Object[] data = (Object[])array.getArray(); 
    Example example = (Example)data[0]; // It's an ExampleMapper, but I only want Example 
    return example; 
} 

正如我先前指出的,第一存儲過程是否正常工作給予其ID爲例對象。從數據庫中檢索的對象被自動映射到相應的Java對象中。下一步是能夠調用接受此用戶定義類型的實例的存儲過程。

第二個存儲過程(JAVA) - 使用一個實例對象 - 不完全

public void useExample(Example example) throws SQLException { 
    String query = "begin example.useExample(?); end;"; 
    Connection connection = jdbcTemplate.getDataSource().getConnection(); 
    CallableStatement callableStatement = connection.prepareCall(query); 

    // Is this required (as per getExample())? 
    Map<String, Class<?>> typeMap = connection.getTypeMap(); 
    typeMap.put(Example.SQL_OBJECT_TYPE_NAME, ExampleMapper.class); 
    connection.setTypeMap(typeMap); 

    /*** 
    *** What goes here to pass the object in as a parameter? 
    ***/ 
    callableStatement.setObject("p_example", ???); 

    callableStatement.execute(); 
} 

回答

0

碴周圍公平一點之後,我能夠開發一個解決方案。幾點意見:

  • 沒有太多的文件說明如何在網上做到這一點。
  • 在我看來,使用用戶定義的類型作爲輸入得不到很好的支持。
  • 我發現我不得不使用Struct這是違反直覺(因爲只有數組用於輸出)。
  • SQLData接口未使用,即。 writeSQL()從未被調用,因爲我發現我必須手動構建結構。映射輸出時調用readSQL()
  • 我不得不使用DB特定的代碼來創建數組,在我的情況下這意味着Oracle類。

這可能會導致事情發生錯誤,所以我很樂意對我的解決方案提出意見。

public void useExample(Example example) throws SQLException { 
    String query = "begin example.useExample(?); end;"; 
    Connection connection = jdbcTemplate.getDataSource().getConnection(); 
    CallableStatement callableStatement = connection.prepareCall(query); 

    Map<String, Class<?>> typeMap = connection.getTypeMap(); 
    typeMap.put(Example.SQL_OBJECT_TYPE_NAME, ExampleMapper.class); 
    connection.setTypeMap(typeMap); 

    // Manually convert the example object into an SQL type. 
    Object[] exampleAttributes = new Object[]{example.ID, example.Name}; 
    Struct struct = connection.createStruct(type.getObjectType(), exampleAttributes); 

    // Build the array using Oracle specific code. 
    DelegatingConnection<OracleConnection> delegatingConnection = (DelegatingConnection<OracleConnection>) new DelegatingConnection(connection); 
    OracleConnection oracleConnection = (OracleConnection) delegatingConnection.getInnermostDelegate(); 
    Object[] data = new Object[]{struct}; 
    Array array oracleConnection.createOracleArray(Example.SQL_TABLE_TYPE_NAME, data); 

    // Set the input value (finally). 
    callableStatement.setObject("p_example", array); 

    callableStatement.execute(); 
} 
相關問題