首页 文章

使用mybatis从Oracle DB中选择BLOB列

提问于
浏览
2

我正在尝试使用mybatis从Oracle数据库中检索BLOB列的内容 . 有一个表'Demo',其中包含BLOB类型的列'binfile' . 我想选择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>

我显然得到一个错误,说原始变量说'PL / SQL:数字或值错误:原始变量长度太长',因为图像远远超过100 kB,因为SQL中的VARCHAR2变量只能支持2000个字节 .

这个问题有方法解决吗?

我想过编写一个存储过程,它逐块读取BLOB列并将输出写入文件 . 但该文件将保存在数据库服务器上,我无法检索它 .

3 回答

  • 0

    你可以直接使用BLOB,做 import oracle.sql.BLOB;

    例子:

    BLOB blob = (BLOB)map.get("binfile");
    
    //one way: as array
    byte[] bytes = blob.getBytes(1L, (int)blob.length());
    System.out.println(new String(bytes)); //use for text data
    System.out.println(Arrays.toString(bytes));
    
    //another way: as stream
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("data.bin"));
    InputStream is = blob.binaryStreamValue();
    int b = -1;
    while ((b = is.read()) != -1) {
        bos.write(b);
    }
    bos.close();
    
  • 2

    您是否尝试将字段映射到jdbcType = LONGVARBINARY?

  • 0

    在我的情况下,我必须实现custom BaseTypeHandler to support Oracle BLOB conversion to byte[] for Mybatis .

    • 将Oracle JDBC驱动程序添加到项目中,您也需要 mybatis 依赖项 . 如果您使用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>
    
    @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);
            }
        }
    }
    
    • 将类型处理程序包添加到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>
    
    • 然后,您可以从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 .

相关问题