7

我在将字节数组映射到 Hibernate 中的 MySQL 数据库时遇到了一些麻烦,我想知道我是否遗漏了一些明显的东西。我的班级大致是这样的:

public class Foo {
    private byte[] bar;

    // Getter and setter for 'bar'
}

该表在 MySQL 5.5 中是这样定义的:

CREATE TABLE foo (
bar BINARY(64) NOT NULL)

Hibernate 3.6.2 的映射看起来与此类似:

<hibernate-mapping>
    <class name="example.Foo" table="foo">
        <property name="bar" column="bar" type="binary" />
    </class>
</hibernate-mapping>

我只使用 hbm2ddl 进行验证,当我部署应用程序时它给了我这个错误:

Wrong column type in foo for column bar. Found: binary, expected: tinyblob

如果在映射中使用 type="binary" 不会导致 Hibernate 期望列的类型是二进制(而不是 tinyblob),我不知道会发生什么。我花了一些时间谷歌搜索,但找不到确切的错误。类似错误的解决方案是...

  1. 在 <property> 上指定“长度”。这改变了 Hibernate 期望的类型,但它总是某种类型的 blob,而不是它找到的“二进制”类型。
  2. 不要在 property 元素上声明“类型”,而是嵌套一个 column 元素并给它一个 sql-type 属性。那是可行的,但这也会使绑定特定于 MySQL,所以如果可能的话,我想避免它。

这个设置有什么突出的地方会导致这种不匹配吗?如果我指定 type="binary" 而不是 "blob",为什么 Hibernate 需要一个 blob 而不是二进制文件?

4

3 回答 3

4

我相信问题是type="binary"

该类型是休眠的通用类型。它不直接映射到特定于数据库引擎的类型。根据您使用的驱动程序,它们被转换为不同的 SQL 类型。显然,MySQL 驱动程序将休眠类型“二进制”映射到一个 tinyblob。

此处提供了完整的休眠类型列表。

您有 2 个选项。您可以更改 CREATE TABLE 脚本以使用 tinyblob 数据类型存储该列。然后你的休眠验证不会失败,你的应用程序就会工作。这将是建议的解决方案。

仅当您必须在 DB 中使用 BINARY 数据类型时才应使用第二个选项。您可以做的是在休眠映射中指定一个 sql 类型,以便强制休眠使用您想要的类型。映射如下所示:

<property name="bar">
  <column name="bar" sql-type="binary" />
</property>

这样做的主要缺点是您失去了 DB 引擎的独立性,这就是大多数人首先使用休眠的原因。此代码仅适用于具有 BINARY 数据类型的数据库引擎。

于 2011-05-13T20:40:12.440 回答
2

我们最终解决类似问题的方法是编写我们自己的自定义 UserType。

UserTypes 相对容易实现。只需创建一个实现 org.hibernate.usertype.UserType 的类并实现 @override 方法。

在您的休眠定义中,使用用户类型非常简单:

<property name="data" type="com.yourpackage.hibernate.CustomBinaryStreamUserType" column="binary_data" />

简单地说,这将执行这个类来读取和写入数据库中的数据。特别是使用了 nullSafeGet 和 nullSafeSet 方法。

在我们的例子中,我们使用它在将二进制数据写入数据库之前对其进行 gzip 压缩,并在读取时将其解压缩。这隐藏了使用此数据从应用程序压缩数据的事实。

于 2011-05-13T20:37:42.533 回答
0

我认为在休眠中映射二进制列有一个简单的解决方案。

“BINARY”列可以很容易地映射到休眠实体类中的“java.util.UUID”。

例如,列定义看起来像

`tokenValue` BINARY(16) NOT NULL

Hibernate Entity 将具有以下代码以支持 BINARY 列

private UUID tokenValue;

@Column(columnDefinition = "BINARY(16)", length = 16)
public UUID getTokenValue() {
    return this.tokenValue;
}

public void setTokenValue(UUID sessionTokenValue) {
    this.tokenValue = tokenValue;
}
于 2014-08-24T08:37:59.153 回答