2

I'm trying to retrieve the contents of a BLOB column from an Oracle Database using mybatis. There is a table 'Demo' that contains a column 'binfile' of type BLOB. I would like to select the BLOB column and display it as a byte array/raw binary data. I'm using a Oracle thin JDBC driver.

The query in the mybatis mapper looks like this:

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

If I do this, the result I get looks like this:

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

If I do this:

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

I obviously get an error saying that the raw variable saying 'PL/SQL: numeric or value error: raw variable length too long' as the image is well over 100 kB, since a VARCHAR2 variable in SQL can support only 2000 bytes.

Is there a solution to this?

I thought of writing a stored proc that reads the BLOB column block by block and writes the output to a file. But that file will be saved on the database server and I can't retrieve that.

3 Answers 3

3

You can use the BLOB directly, do import oracle.sql.BLOB;

Examples:

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();
Sign up to request clarification or add additional context in comments.

Comments

0

Have you tried mapping the field to jdbcType=LONGVARBINARY?

1 Comment

not working if mapping field to jdbcType=LONGVARBINARY
0

In my case I had to implement a custom BaseTypeHandler to support Oracle BLOB conversion to byte[] for Mybatis.

  1. Add the Oracle JDBC driver to your project, you will need mybatis dependencies too. If you are using 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. Add the custom BaseTypeHandler for reading byte[] from Oracle BLOB class:

    @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. Add the type handlers package to mybatis configuration. As you can see, I am using 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. And then, you can read byte[] from Oracle BLOBs from Mybatis:

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

I hope this will help. This is an adaptation of this excellent answer: https://stackoverflow.com/a/27522590/2692914.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.