【问题标题】:Select a BLOB column from Oracle DB using mybatis使用 mybatis 从 Oracle DB 中选择一个 BLOB 列
【发布时间】:2013-06-07 23:29:14
【问题描述】:

我正在尝试使用 mybatis 从 Oracle 数据库中检索 BLOB 列的内容。有一个表 'Demo' 包含一个 BLOB 类型的列 'binfile'。我想选择 BLOB 列并将其显示为字节数组/原始二进制数据。我正在使用 Oracle 瘦 JDBC 驱动程序。

mybatis mapper中的查询是这样的:

<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 列并将输出写入文件。但该文件将保存在数据库服务器上,我无法检索。

【问题讨论】:

    标签: sql oracle blob mybatis


    【解决方案1】:

    就我而言,我必须实现custom BaseTypeHandler to support Oracle BLOB conversion to byte[] for Mybatis

    1. 将 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>
      
    2. 添加custom BaseTypeHandler for reading byte[] from Oracle BLOB 类:

      @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. 将类型处理程序包添加到 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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 如果将字段映射到 jdbcType=LONGVARBINARY 则不起作用
      【解决方案3】:

      你可以直接使用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();
      

      【讨论】:

        猜你喜欢
        • 2016-04-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-23
        • 2016-07-24
        • 2018-06-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多