2012-07-11 3 views
4

ojdbc6을 사용하여 준비된 명령문에 UDT 객체를 바인딩하기 위해 java.sql.SQLData을 구현했습니다. 자, 내 UDT 중 일부는 배열을 포함합니다. 지금해야 할 일은 다음과 같습니다.Oracle 용 SQLData.writeSQL() 내 java.sql.SQLOutput에 쓰는 방법

class MyType implements SQLData { 
    public void writeSQL(SQLOutput stream) throws SQLException { 
    Array array = //... 
    stream.writeArray(array); 
    } 
} 

Oracle 배열을 생성하려면 JDBC 연결이 필요합니다. 일반적으로이이 같은 수행됩니다

OracleConnection conn = // ... 
Array array = conn.createARRAY("MY_ARRAY_TYPE", new Integer[] { 1, 2, 3 }); 

그러나, writeSQL(SQLOutput) 방법, 내가 연결되어 있지 않습니다. 또한 간결한 질문으로 설명하기 어려운 이유 때문에 MyType에 연결 참조를 유지할 수 없습니다. 어떻게 든 그 연결을 SQLOutput에서 추출 할 수 있습니까? 다음과 같이 불안정한 구성을 사용하지 마십시오.

// In ojdbc6, I have observed a private "conn" member in OracleSQLOutput: 
Field field = stream.getClass().getDeclaredField("conn"); 
field.setAccessible(true); 
OracleConnection conn = (OracleConnection) field.get(stream); 

아이디어가 있으십니까? 대안?

+0

해결 했습니까? 나는 똑같은 문제에 직면하고있다. –

+0

@PabloSantaCruz : 아직까지. 나는 UDT를 바인딩하기 전에 정적'ThreadLocal'에 로컬로 연결을 저장하는 방법에 대해 생각 해왔다. 그게 효과가 있지만, 정말 잘못 느낀다 ... –

+0

좋아, 내가 별도의 대답으로 한 것을 쓸 것이다. 또한 잘못된 생각이 들지만이 문제를 즉시 해결해야했습니다. –

답변

5

다음은이 문제를 해결 한 방법입니다. 그것은 예쁘지 않지만 작동합니다.

나는 java.sql.Connection을 받고 java.sql.ARRAY 개체를 설정하는 SQLData을 구현하는 클래스에 메서드를 추가했습니다. 이 같은

뭔가 :

public class MyObject01 implements SQLData { 
    private String value; 
    private MyObject02[] details; // do note that details is a java array 
    // ... also added getters and setters for these two properties 

    private Array detailsArray; 

    public void setupArrays(oracle.jdbc.OracleConnection oconn) 
     throws SQLException 
    { 
     detailsArrays = oconn.createARRAY(MyObject02.ORACLE_OBJECT_ARRAY_NAME, getDetails()); 
     // MyObject02.ORACLE_OBJECT_ARRAY_NAME must be the name of the oracle "table of" type name 
     // Also note that in Oracle you can't use JDBC's default createArray 
     // since it's not supported. That's why you need to get a OracleConnection 
     // instance here. 
    }  

    @Override 
    public void writeSQL(Stream stream) throws SQLException { 
     stream.writeString(getValue()); 
     stream.writeArray(detailsArray); // that's it 
    } 

    @Override 
    public void readSQL(Stream stream) throws SQLException { 
     setValue(stream.readString()); 
     Array array = stream.readArray(); 
     if (array != null) { 
      setDetails((MyObject02[])array.getArray()); 
     } 
    } 

첫 번째 부분입니다.

그런 다음 프로 시저 호출에서 해당 개체를 사용하기 전에 해당 개체에서 setupArrays 메서드를 호출하십시오. 예 : 물론

public class DB { 
    public static String executeProc(Connection conn, MyObject01 obj) 
     throws SQLException 
    { 
     CalllableStatement cs = conn.prepareCall(" { ? = call sch.proc(?) }"); 
     cs.registerOutParameter(1, Types.VARCHAR); 
     obj.setupArrays((oracle.jdbc.Connection)conn); 
     cs.setObject(2, obj, Types.STRUCT); 
     cs.executeUpdate(); 
     String ret = cs.getString(1); 
     cs.close(); 
     return ret; 
    } 
} 

, 연결시, 당신은 제대로 유형을 등록해야합니다

Connection conn = DriverManager.getConnection("jdbc:oracle://localhost:1521/XE", "scott", "tiger"); 
conn.getTypeMap().put(MyObject01.ORACLE_OBJECT_NAME, MyObject01.class); 
conn.getTypeMap().put(MyObject02.ORACLE_OBJECT_NAME, MyObject02.class); 
conn.getTypeMap().put(MyObject02.ORACLE_OBJECT_ARRAY_NAME, MyObject02[].class); 

는 도움이되기를 바랍니다.

+0

그렇습니다. 로컬의 스레드가'SQLData' 객체의 외부에 있다는 점을 제외하고는 제 ThreadLocal과 거의 같은 것입니다. 나는 그것이 얻는만큼 좋은 것으로 생각한다 : - / –