当前位置: 首页 > 面试题库 >

无法使用Hibernate / PostgreSQL将欧元符号存储到LOB String属性中

赵智勇
2023-03-14
问题内容

我在将Hibernate 3.6.10的PostgreSQL 8.4中的特殊字符(如欧元符号(€))写回LOB字符串属性时遇到麻烦。

我所知道的是,PostgreSQL提供了两种不同的方式将大字符对象存储在表的列中。它们可以直接存储在该表列中,也可以间接存储在单独的表中(实际上称为pg_largeobject)。在后一种情况下,该列保留对pg_largeobject中的行的引用(OID)。

Hibernate 3.6.10中的默认行为是间接OID方法。但是,可以向Lob属性添加额外的注释@
org.hibernate.annotations.Type(type =“ org.hibernate.type.TextType”)以获取直接存储行为。

两种方法都可以正常工作,除了我想使用特殊符号(例如欧元符号(€))的那一刻。在这种情况下,直接存储机制可以继续工作,但是间接存储机制会中断。

我想用一个例子来证明这一点。我创建了一个具有2个@Lob属性的测试实体。一种遵循直接存储原理,另一种遵循间接存储:

@Basic
@Lob
@Column(name = "CLOB_VALUE_INDIRECT_STORAGE", length = 2147483647)
public String getClobValueIndirectStorage()

@Basic
@Lob
@org.hibernate.annotations.Type(type="org.hibernate.type.TextType")
@Column(name = "CLOB_VALUE_DIRECT_STORAGE", length = 2147483647)
public String getClobValueDirectStorage()

如果创建一个实体,则用欧元符号填充这两个属性,然后将其持久化到数据库中,当我执行SELECT时会看到以下内容

 id | clob_value_direct_storage | clob_value_indirect_storage
----+---------------------------+----------------------------
  6 | €                         | 910579

如果再查询表pg_largeobject,我会看到:

  loid  | pageno | data
--------+--------+------
 910579 |      0 | \254

pg_largeobject的’data’列的类型为bytea,这意味着信息存储为原始字节。表达式“ \
254”表示一个单字节,而在UTF-8中表示字符“¬”。这正是从数据库加载实体时获得的值。

UTF-8中的欧元符号由3个字节组成,因此我希望’data’列具有3个字节而不是1个字节。

这不仅会出现在欧元符号上,还会发生在许多特殊字符上。这是Hibernate中的问题吗?还是JDBC驱动程序?有什么方法可以调整此行为?

在此先感谢您

Franck de Bruijn


问题答案:

在深入研究Hibernate的源代码和PostgreSQL
JDBC驱动程序之后,我设法找到了问题的根本原因。最后,调用BlobOutputStream的write()方法(由JDBC驱动程序提供)以将Clob的内容写入数据库。此方法如下所示:

public void write(int b) throws java.io.IOException
{
    checkClosed();
    try
    {
        if (bpos >= bsize)
        {
            lo.write(buf);
            bpos = 0;
        }
        buf[bpos++] = (byte)b;
    }
    catch (SQLException se)
    {
        throw new IOException(se.toString());
    }
}

此方法将“ int”(32位/ 4字节)作为参数,并将其转换为“ byte”(8位/
1字节),实际上会丢失3个字节的信息。Java中的字符串表示形式是UTF-16编码的,这意味着每个字符都由16位/
2字节表示。欧元符号的int值为8364。转换为字节后,保留值172(以八位位组表示254)。

我不确定现在最好的解决方案是什么。恕我直言,JDBC驱动程序应负责将Java
UTF-16字符编码/解码为数据库所需的任何编码。但是,我看不到JDBC驱动程序代码中有任何调整可能性来改变其行为(并且我不想编写和维护自己的JDBC驱动程序代码)。

因此,我使用自定义的ClobType扩展了Hibernate,并在将其写入数据库之前设法将UTF-16字符转换为UTF-8,反之亦然。

解决方案太大,无法简单地粘贴到此答案中。如果您有兴趣,请给我留言,然后发送给您。

干杯,弗兰克



 类似资料:
  • 问题内容: PostgreSQL 11现在支持存储过程,我正在尝试使用 Hibernate 5.3.7.Final 和 Postgresql 42.2.5 JDBC驱动程序 进行调用。在PostgreSQL 11之前,我们有可以用JPA调用的函数。但是,函数是通过执行的,而新的存储过程必须以 我正在尝试执行以下简单的存储过程: JPA批注如下所示: 我用以下方法调用存储过程: 我的日志如下所示:

  • 问题内容: PostgreSQL 11现在支持存储过程,我正在尝试使用 Hibernate 5.3.7.Final 和 Postgresql 42.2.5 JDBC驱动程序 进行调用。在PostgreSQL 11之前,我们有可以用JPA调用的函数。但是,函数是通过执行的,新存储过程必须以 我正在尝试执行以下简单的存储过程: JPA批注如下所示: 我用以下方法调用存储过程: 我的日志如下所示: 第一

  • 问题内容: 我的PostgreSQL数据库(9.2)中有一个表,其中的列类型为JSON。我很难将此列映射到“ JPA2实体”字段类型。 我尝试使用String,但是当我保存实体时,出现一个异常,即它无法将字符转换为JSON。 处理JSON列时使用的正确值类型是什么? 一个简单的解决方法是定义一个文本列。 问题答案: 请参阅PgJDBC错误#265。 PostgreSQL过于严格,对数据类型转换非常

  • 问题内容: 我想将某个结构存储到其中具有JSON字段的数据库中。 该表的架构为: 我在项目中使用sqlx和lib / pq驱动程序,并且不会执行以下操作。相反,它惊慌地说有一个零指针。DB是全局结构 当我从架构和固定装置中删除时,一切运行正常。但是由于某种原因,当包含此字段时,程序会出现紧急情况。关于如何在数据库模式和Go结构中定义字段的任何想法? 问题答案: SQLX有一个类型的,会做你需要什么

  • 我有一个使用Spring启动1.52版本的Java Web应用程序,并且在应用程序属性文件中,我有此配置连接到postgresql。 我有一个模型类,它用Hibernate表示一个表: 这个服务类将Coverage对象保存到数据库。 我使用此存储库服务将 Coverage 对象保存到数据库: 一切都很好,除非元数据具有非ascii字符µ。我在postgresql数据库中查看,它将像这样保存\265

  • 我正在使用HM-10副本CC4A-1模块。我把它和Arduino Uno R3连接在一起,经过很多努力,它连接上了。我使用Arduino串行监视器执行了一些AT命令,在执行AT RENEW命令后,它突然停止工作。我还试图执行AT BAUD