【问题标题】:Is there any alternative to 'rawtohex' to insert data to a blob column in H2?是否有任何替代 'rawtohex' 将数据插入 H2 中的 blob 列?
【发布时间】:2018-11-20 23:04:06
【问题描述】:

我有一个连接到 Oracle 数据库的 Java 应用程序。其中一个表包含一个 blob 列,我们使用 utl_raw.cast_to_raw 填充它,如下所示:

public class MyDAO extends JdbcDaoSupport {
    public void persist(String name, String data) {
        String sql = "insert into table (id, name, data) values " +
                     "(sequence.nextval, ?, utl_raw.cast_to_raw(?))";
        getJdbcTemplate().update(sql, [name, data]);
    }
}

由于某些我不知道的原因,我们在这个应用程序中没有使用 Hibernate、JPA 或类似的东西。只需简单的 SQL 语句和 Spring JDBC 即可执行它们。 (...) 无论如何,上述方法工作正常。至少对于 Oracle。

我已经建立了一个包含最少数据的内存 H2 数据库,用于我们的 JUnit 测试。但是 H2 中没有 utl_raw 包。 Apparently, the way to go is 改为使用 rawtohex function。它有点工作...但是它使数据长度加倍。例如,如果我将字符串 "TEST" 持久保存在 blob 列中,然后我检索它的值,它将变为 " T E S T"。作为一个字节数组,它将是[0, 84, 0, 69, 0, 83, 0, 84]。 H2 文档指出这是应该发生的:

将字符串转换为十六进制表示。每个字符串字符使用 4 个十六进制字符。

Weird。我想这是支持 UTF-16 字符串(?)的方式,但我使用的是 UTF-8。它实际上损坏了我的数据。

还有其他方法可以将 blob 存储在 H2 中吗?我见过 this answer where they suggest using a PreparedStatement,但是我必须自己处理连接:

super.getConnection().prepareStatement(/* ... */).executeUpdate();
// release the statement and the connection, handle exceptions

当然,它并没有太多比我们现在拥有的丑,但是,我仍然非常不愿意更改工作生产代码以使其与我们的 JUnit 测试设置兼容。

另一种选择是将 blob 当作 UTF-16 字符串来检索,因此它实际上每个字符使用 4 个十六进制。但同样,我会只为 H2 解决问题,而为 Oracle 解决问题。

我还有其他选择吗?有什么办法可以告诉 H2 数据库在rawtohex 中每个字符只使用 1 个字节?或者我可以用another function 代替rawtohex

【问题讨论】:

    标签: java blob h2


    【解决方案1】:

    我一直在尝试在构建时使用 Liquibase 来填充内存中的 H2 数据库。

    我遇到了同样的空格填充问题,但通过从使用 RAWTOHEX 切换到使用 StringToUTF8 解决了它。

    【讨论】:

      【解决方案2】:

      我不会在数据库(Oracle 或 H2)中进行转换。

      H2's docs 说要使用PreparedStatement.setBinaryStream。这可能也适用于甲骨文?根据您要转换的字符串的大小,其他方法可能会更高效。顺便说一句,将字符串转换为二进制对象的任何特殊原因?

      如果您知道它总是相对较小的字符串(例如

      String sql = "insert into table (id, name, data) values " +
                   "(sequence.nextval, ?, ?)";
      PreparedStatement ps = super.getConnection().prepareStatement(sql);
      InputStream stream = new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8));
      ps.setString(1, name);
      ps.setBinaryStream(2, stream);
      ps.executeUpdate();
      

      【讨论】:

      • 谢谢,我会在两个数据库上都试一试,尽管我仍然不相信只是为了测试目的而更改工作代码。
      • 至于将它们转换为二进制对象的原因......好吧,我们需要一个列来存储“大字符串”,并且有人认为 blob 是这样做的方法。我想 clob 会是更好的选择,但该应用程序已经投入生产,所以我需要一个非常令人信服的理由来让更改获得批准。
      • 我同意不要仅仅为了测试目的而更改代码。如果您只打算使用 Oracle,那么为什么不将它也用于测试呢?另一方面,如果您可能在其他数据库上使用此代码,则需要进行此类更改。
      • 我可以考虑几个令人信服的理由来迁移到 CLOB,具体取决于具体情况。 1. 安全性:根据数据的来源(以及您是否清理),狡猾的用户可能会向您发送一个可执行文件以存储在那里并稍后检索。 2. 如果您想使用 Oracle Text 进行搜索,BLOB 需要“过滤”,这可能效率较低:docs.oracle.com/en/database/oracle/oracle-database/12.2/ccapp/…
      猜你喜欢
      • 2016-11-16
      • 2015-11-16
      • 2011-09-09
      • 2022-12-20
      • 2015-06-09
      • 1970-01-01
      • 2013-08-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多