返回介绍

用户自定义类型

发布于 2025-04-21 21:42:13 字数 1887 浏览 0 评论 0 收藏

由附录 A 可见,Hibernate 支持很多 Java 类型(既有简单的值类型,也有对象类型)。通过建立映射规范,甚至可以将非常复杂的、嵌套的对象结构持久化保存到任何数据表和字段内。既然 Hibernate 提供的功能强大而又灵活,你可能会问为什么 Hibernate 内建的类型支持还会不够用?

促使你使用 Hibernate 自定义类型的一种情况是,你想使用不同于 Hibernate 通常情况下会选择的 SQL 字段类型来保存某种特定的 Java 类型。Hibernate 参考文档引用了一个例子,它将 Java BigInteger 类型的值持久化保存到 VARCHAR 字段。在某些为了兼容于传统数据库(legacy database)模式的情况下,就可能需要这么做。

另一种常见的自定义类型使用场合涉及枚举类型值的持久化。在 Java 5 以前,没有为枚举类型提供内建的语言支持。所以,尽管 Joshua Bloch 在他的《Effective Java Programming Language Guide》(Addison-Wesley)一书中提出的优秀的设计模式是事实上的标准,但 Hibernate 还是不知应该如何支持这一概念。在 Hibernate 3 之前,Hibernate 就提供了 PersistentEnum 接口,但这一接口与 Java 5 中引入的原生(native)枚举类型(enum)的支持并不适合,所以 PersistentEnum 对于 Java 5 的 enum 类型也没有什么用途。而且不幸的是,Hibernate 现在还没有提供相应的替换解决办法,所以我们在这里将介绍如何利用 Hibernate 对自定义类型的支持来实现枚举类型的持久化。

另一种需要调整类型系统的场合是,你必须将一个属性值拆分成多个组成分部,并保存到多个数据库字段。也许,公司内部强制要求使用的可重用库中的 Address 对象是把 ZIP+4 码保存成了一个单独的字符串,但是你要整合的数据库却需要一个 5 位数字的字段和一个 4 位数字、其值可为 null 的字段,来保存这两部分的数据。或者,也有可能是相反的情况,需要将一个数据库字段拆分成多个属性。

所幸,像这种情况,Hibernate 可以让你控制持久化映射的细节,使你在不得已时也能找到一种权宜之计。

注意:让简单的事情更容易,复杂的事情有可能。这样的精神要持续下去。

即使在某些不是严格必需的情况下,你也可能会想建立自定义值类型。如果你有一个复合类型(composite type),它在整个应用程序中的许多地方都用得到(向量、复数、地址等),你当然可以把会用到它的地方都映射成组件。但是,将映射细节封装在一个可共享的、可重用的 Java 类内,比让映射细节在每个映射文档内到处传播可能更有价值。如此一来,如果映射细节因任何原因需要修改时,只需要修改一个类,而不用去寻找和调整众多特定组件的映射配置。

就上述所有使用场合而言,所需要做的任务就是告诉 Hibernate 一种新方法,让它知道如何对内存中特定类型的值及其数据库持久化保存形式做相互转化。

应该怎么做

Hibernate 能让你在需要的情况下自行提供映射值的逻辑,办法就是实现以下两个接口之一:org.hibernate.usertype.UserType 或 org.hibernate.usertype.CompositeUserType。

Hibernate 会为特定类型的值创建一个转化器(translator),而并非为它另外创建一种知道如何自行持久化的新类型的值,了解这一点很重要。换言之,以 ZIP 码为例,不是由 ZIP 码属性本身去实现 UserType 接口,而是我们要另外新建一个实现了 UserType 接口的类,然后在映射文档中将这个类指定为用于映射 ZIP 码属性的 Java 类型。因此,我认为“自定义类型”这个术语有些令人混淆。

我们来看一个具体的示例。如前所述,自定义类型的一个常见目标就是持久化枚举类型。虽然 Hibernate 本身没有提供对枚举类型的支持,但是利用 UserType 机制可以容易地达到这一目的。之后,我们还会介绍一个更复杂的映射例子,它涉及多个属性和字段之间的映射。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。