2

mybatis を使用して Oracle データベースから BLOB 列の内容を取得しようとしています。タイプBLOBの列「binfile」を含むテーブル「Demo」があります。BLOB 列を選択して、バイト配列/生のバイナリ データとして表示したいと考えています。Oracle シン JDBC ドライバーを使用しています。

mybatis マッパーのクエリは次のようになります。

<mapper namespace="Oracle" >
...
<select id="SelectBinary" resultType="hashmap">
    SELECT binfile from mpdemo.Demo
    </select>
</mapper>

これを行うと、得られる結果は次のようになります。

BINFILE: "oracle.sql.BLOB@5d67eb18"

私がこれを行う場合:

<select id="SelectBinaryDup" resultType="hashmap">
  SELECT utl_raw.cast_to_varchar2(dbms_lob.substr(binfile)) from mpdemo.Demo
</select>

SQL の VARCHAR2 変数は 2000 バイトしかサポートできないため、画像が 100 kB をはるかに超えているため、「PL/SQL: 数値または値のエラー: 生の変数の長さが長すぎます」という生の変数というエラーが明らかに表示されます。

これに対する解決策はありますか?

BLOB 列をブロックごとに読み取り、出力をファイルに書き込むストアド プロシージャを作成することを考えました。しかし、そのファイルはデータベース サーバーに保存され、取得できません。

4

3 に答える 3

0

私の場合、 Mybatis の byte[] への Oracle BLOB 変換をサポートするためにカスタム BaseTypeHandler を実装する必要がありました。

  1. mybatisOracle JDBC ドライバーをプロジェクトに追加します。依存関係も必要になります。Maven を使用している場合:

    <dependency>
        <groupId>com.oracle</groupId>
        <artifactId>ojdbc14</artifactId>
        <version>10.2.0.3.0</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.2.3</version>
    </dependency>
    
  2. Oracle BLOBクラスから byte[] を読み取るためのカスタム BaseTypeHandler を追加します。

    @MappedTypes(byte[].class)
    public class OracleBlobTypeHandler extends BaseTypeHandler<byte[]> {
        @Override
        public void setNonNullParameter(PreparedStatement preparedStatement, int i, byte[] bytes, JdbcType jdbcType) throws SQLException {
            // see setBlobAsBytes method from https://jira.spring.io/secure/attachment/11851/OracleLobHandler.java
            try {
                if (bytes != null) {
                    //prepareLob
                    BLOB blob = BLOB.createTemporary(preparedStatement.getConnection(), true, BLOB.DURATION_SESSION);
    
                    //callback.populateLob
                    OutputStream os = blob.getBinaryOutputStream();
                    try {
                        os.write(bytes);
                    } catch (Exception e) {
                        throw new SQLException(e);
                    } finally {
                        try {
                            os.close();
                        } catch (Exception e) {
                            e.printStackTrace();//ignore
                        }
                    }
                    preparedStatement.setBlob(i, blob);
                } else {
                    preparedStatement.setBlob(i, (Blob) null);
                }
            } catch (Exception e) {
                throw new SQLException(e);
            }
        }
    
        /** see getBlobAsBytes method from https://jira.spring.io/secure/attachment/11851/OracleLobHandler.java */
        private byte[] getBlobAsBytes(BLOB blob) throws SQLException {
    
            //initializeResourcesBeforeRead
            if(!blob.isTemporary()) {
                blob.open(BLOB.MODE_READONLY);
            }
    
            //read
            byte[] bytes = blob.getBytes(1L, (int)blob.length());
    
            //releaseResourcesAfterRead
            if(blob.isTemporary()) {
                blob.freeTemporary();
            } else if(blob.isOpen()) {
                blob.close();
            }
    
            return bytes;
        }
    
        @Override
        public byte[] getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
            try {
                //use a custom oracle.sql.BLOB
                BLOB blob = (BLOB) resultSet.getBlob(columnName);
                return getBlobAsBytes(blob);
            } catch (Exception e) {
                throw new SQLException(e);
            }
        }
    
        @Override
        public byte[] getNullableResult(ResultSet resultSet, int i) throws SQLException {
            try {
                //use a custom oracle.sql.BLOB
                BLOB blob = (BLOB) resultSet.getBlob(i);
                return getBlobAsBytes(blob);
            } catch (Exception e) {
                throw new SQLException(e);
            }
        }
    
        @Override
        public byte[] getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
            try {
                //use a custom oracle.sql.BLOB
                BLOB blob = (BLOB) callableStatement.getBlob(i);
                return getBlobAsBytes(blob);
            } catch (Exception e) {
                throw new SQLException(e);
            }
        }
    }
    
  3. type handlers パッケージを mybatis 構成に追加します。ご覧のとおり、私は spring-mybatis を使用しています。

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="typeHandlersPackage" value="package.where.customhandler.is" />
    </bean>
    
  4. そして、Mybatis から Oracle BLOB から byte[] を読み取ることができます:

    public class Bean {
        private byte[] file;
    }
    
    interface class Dao {
        @Select("select file from some_table where id=#{id}")
        Bean getBean(@Param("id") String id);
    }
    

これが役立つことを願っています。これは、この優れた回答の適応です: https://stackoverflow.com/a/27522590/2692914

于 2016-01-29T17:43:11.873 に答える